; ; Formatted Debug Output (FDO) ; Copyright (c) 2005-2006, mike.dld ; Created: 2005-01-29, Changed: 2006-11-10 ; ; For questions and bug reports, mail to mike.dld@gmail.com ; ; Available format specifiers are: %s, %d, %u, %x (with partial width support) ; ; to be defined: ; __DEBUG__ equ 1 ; __DEBUG_LEVEL__ equ 5 macro debug_func name { if used name name@of@func equ name } macro debug_beginf { align 4 name@of@func: } debug_endf fix end if macro DEBUGS _sign,[_str] { common local tp tp equ 0 match _arg:_num,_str \{ DEBUGS_N _sign,_num,_arg tp equ 1 \} match =0 _arg,tp _str \{ DEBUGS_N _sign,,_arg \} } macro DEBUGS_N _sign,_num,[_str] { common pushf pushad local ..str,..label,is_str is_str = 0 forward if _str eqtype '' is_str = 1 end if common if is_str = 1 jmp ..label ..str db _str,0 ..label: add esp,4*8+4 mov edx,..str sub esp,4*8+4 else mov edx,_str end if if ~_num eq if _num eqtype eax if _num in <eax,ebx,ecx,edx,edi,ebp,esp> mov esi,_num else if ~_num eq esi movzx esi,_num end if else if _num eqtype 0 mov esi,_num else local tp tp equ 0 match [_arg],_num \{ mov esi,dword[_arg] tp equ 1 \} match =0 =dword[_arg],tp _num \{ mov esi,dword[_arg] tp equ 1 \} match =0 =word[_arg],tp _num \{ movzx esi,word[_arg] tp equ 1 \} match =0 =byte[_arg],tp _num \{ movzx esi,byte[_arg] tp equ 1 \} match =0,tp \{ 'Error: specified string width is incorrect' \} end if else mov esi,0x7FFFFFFF end if call fdo_debug_outstr popad popf } macro DEBUGD _sign,_dec { local tp tp equ 0 match _arg:_num,_dec \{ DEBUGD_N _sign,_num,_arg tp equ 1 \} match =0 _arg,tp _dec \{ DEBUGD_N _sign,,_arg \} } macro DEBUGD_N _sign,_num,_dec { pushf pushad if (~_num eq) if (_dec eqtype eax | _dec eqtype 0) 'Error: precision allowed only for in-memory variables' end if if (~_num in <1,2,4>) if _sign 'Error: 1, 2 and 4 are only allowed for precision in %d' else 'Error: 1, 2 and 4 are only allowed for precision in %u' end if end if end if if _dec eqtype eax if _dec in <ebx,ecx,edx,esi,edi,ebp,esp> mov eax,_dec else if ~_dec eq eax if _sign = 1 movsx eax,_dec else movzx eax,_dec end if end if else if _dec eqtype 0 mov eax,_dec else add esp,4*8+4 if _num eq mov eax,dword _dec else if _num = 1 if _sign = 1 movsx eax,byte _dec else movzx eax,byte _dec end if else if _num = 2 if _sign = 1 movsx eax,word _dec else movzx eax,word _dec end if else mov eax,dword _dec end if sub esp,4*8+4 end if mov cl,_sign call fdo_debug_outdec popad popf } macro DEBUGH _sign,_hex { local tp tp equ 0 match _arg:_num,_hex \{ DEBUGH_N _sign,_num,_arg tp equ 1 \} match =0 _arg,tp _hex \{ DEBUGH_N _sign,,_arg \} } macro DEBUGH_N _sign,_num,_hex { pushf pushad if (~_num eq) & (~_num in <1,2,3,4,5,6,7,8>) 'Error: 1..8 are only allowed for precision in %x' end if if _hex eqtype eax if _hex in <eax,ebx,ecx,edx,esi,edi,ebp,esp> if ~_hex eq eax mov eax,_hex end if else if _hex in <ax,bx,cx,dx,si,di,bp,sp> if ~_hex eq ax movzx eax,_hex end if shl eax,16 if (_num eq) mov edx,4 end if else if _hex in <al,ah,bl,bh,cl,ch,dl,dh> if ~_hex eq al movzx eax,_hex end if shl eax,24 if (_num eq) mov edx,2 end if end if else if _hex eqtype 0 mov eax,_hex else add esp,4*8+4 mov eax,dword _hex sub esp,4*8+4 end if if ~_num eq mov edx,_num else mov edx,8 end if call fdo_debug_outhex popad popf } ;----------------------------------------------------------------------------- debug_func fdo_debug_outchar debug_beginf pushad mov cl,al mov ebx,1 mov eax,63 mcall popad ret debug_endf debug_func fdo_debug_outstr debug_beginf mov eax,63 mov ebx,1 .l1: dec esi js .l2 mov cl,[edx] or cl,cl jz .l2 mcall inc edx jmp .l1 .l2: ret debug_endf debug_func fdo_debug_outdec debug_beginf or cl,cl jz @f or eax,eax jns @f neg eax push eax mov al,'-' call fdo_debug_outchar pop eax @@: push 10 pop ecx push -'0' .l1: xor edx,edx div ecx push edx test eax,eax jnz .l1 .l2: pop eax add al,'0' jz .l3 call fdo_debug_outchar jmp .l2 .l3: ret debug_endf debug_func fdo_debug_outhex __fdo_hexdigits db '0123456789ABCDEF' debug_beginf mov cl,dl neg cl add cl,8 shl cl,2 rol eax,cl .l1: rol eax,4 push eax and eax,0x0000000F mov al,[__fdo_hexdigits+eax] call fdo_debug_outchar pop eax dec edx jnz .l1 ret debug_endf ;----------------------------------------------------------------------------- macro DEBUGF _level,_format,[_arg] { common if __DEBUG__ = 1 & _level >= __DEBUG_LEVEL__ local ..f1,f2,a1,a2,c1,c2,c3,..lbl _debug_str_ equ __debug_str_ # a1 a1 = 0 c2 = 0 c3 = 0 f2 = 0 repeat ..lbl-..f1 virtual at 0 db _format,0,0 load c1 word from %-1 end virtual if c1 = '%s' virtual at 0 db _format,0,0 store word 0 at %-1 load c1 from f2-c2 end virtual if c1 <> 0 DEBUGS 0,_debug_str_+f2-c2 end if c2 = c2 + 1 f2 = %+1 DEBUGF_HELPER S,a1,0,_arg else if c1 = '%x' virtual at 0 db _format,0,0 store word 0 at %-1 load c1 from f2-c2 end virtual if c1 <> 0 DEBUGS 0,_debug_str_+f2-c2 end if c2 = c2 + 1 f2 = %+1 DEBUGF_HELPER H,a1,0,_arg else if c1 = '%d' | c1 = '%u' local c4 if c1 = '%d' c4 = 1 else c4 = 0 end if virtual at 0 db _format,0,0 store word 0 at %-1 load c1 from f2-c2 end virtual if c1 <> 0 DEBUGS 0,_debug_str_+f2-c2 end if c2 = c2 + 1 f2 = %+1 DEBUGF_HELPER D,a1,c4,_arg else if c1 = '\n' c3 = c3 + 1 end if end repeat virtual at 0 db _format,0,0 load c1 from f2-c2 end virtual if (c1<>0)&(f2<>..lbl-..f1-1) DEBUGS 0,_debug_str_+f2-c2 end if virtual at 0 ..f1 db _format,0 ..lbl: __debug_strings equ __debug_strings,_debug_str_,<_format>,..lbl-..f1-1-c2-c3 end virtual end if } macro __include_debug_strings dummy,[_id,_fmt,_len] { common local c1,a1,a2 forward if defined _len & ~_len eq _id: a1 = 0 a2 = 0 repeat _len virtual at 0 db _fmt,0,0 load c1 word from %+a2-1 end virtual if (c1='%s')|(c1='%x')|(c1='%d')|(c1='%u') db 0 a2 = a2 + 1 else if (c1='\n') dw $0A0D a1 = a1 + 1 a2 = a2 + 1 else db c1 and 0x0FF end if end repeat db 0 end if } macro DEBUGF_HELPER _letter,_num,_sign,[_arg] { common local num num = 0 forward if num = _num DEBUG#_letter _sign,_arg end if num = num+1 common _num = _num+1 } macro include_debug_strings { if __DEBUG__ = 1 match dbg_str,__debug_strings \{ __include_debug_strings dbg_str \} end if }