proc1 proc
.echo procedure name
proc1 endp
how I can detect the name of the procedure (inside a procedure).
I want to echo
I've often wanted such a function for tracing, but have never found a way, so I'm anxiously awaiting the answer also.
Easy at runtime, see below, but apparently impossible from within a macro, due to the sequential nature of macro expansion. However, since you are the master of the code, why not replace
proc1 proc
.echo procedure name
proc1 endp
with
proc1 proc
.echo procedure proc1
proc1 endp
??
include \masm32\include\masm32rt.inc
WhereAmI MACRO
tmp$ CATSTR <You are currently in Pro_>, %CurProcCt, <, named >, <cpn>
% echo tmp$
ENDM
.code
start:
call Pro_2
call Pro_1
call Pro_3
call Pro_3
call Pro_3
; .err ; remove comment to see the echo tmp$
exit
Pro_1 proc
CurProcCt = 1
cpn equ A
WhereAmI
MsgBox 0, chr$(CurProcCt+48), "You are in Pro", MB_OK
ret
Pro_1 endp
Pro_2 proc
CurProcCt = 2
cpn equ B
WhereAmI
MsgBox 0, chr$(CurProcCt+48), "You are in Pro", MB_OK
ret
Pro_2 endp
Pro_3 proc
CurProcCt = 3
cpn equ C
WhereAmI
MsgBox 0, chr$(CurProcCt+48), "You are in Pro", MB_OK
ret
Pro_3 endp
end start
You must use custom prologue/epilogue macro to get proc name.
Jimg check out this attachment.
EDIT: I can't attach
An Error Has Occurred!
The upload folder is full. Please try a smaller file and/or contact an administrator.
posting it in CODE
;; prologue, epilogue, seh
pushcontext LISTING
.NOLIST
.NOCREF
.NOLISTMACRO
PEXCEPTION_RECORD TYPEDEF PTR EXCEPTION_RECORD
PCONTEXT TYPEDEF PTR CONTEXT
PNT_TIB TYPEDEF PTR NT_TIB
;; RETURN : EXCEPTION_DISPOSITION in EAX
EXCEPTION_ROUTINE TYPEDEF PROTO C \
ExceptionRecord:PEXCEPTION_RECORD,\
EstablisherFrame:PVOID,\
ContextRecord:PCONTEXT,\
DispatcherContext:PVOID
PEXCEPTION_ROUTINE TYPEDEF PTR EXCEPTION_ROUTINE
PEXCEPTION_REGISTRATION_RECORD TYPEDEF PTR EXCEPTION_REGISTRATION_RECORD
EXCEPTION_REGISTRATION_RECORD struct
Next PEXCEPTION_REGISTRATION_RECORD ?
Handler PEXCEPTION_ROUTINE ?
EXCEPTION_REGISTRATION_RECORD ends
; userparams: <FORCEFRAME>,<FORCENOFRAME>,<SEH>
assume fs:nothing
.data?
__current_seh_calee dd ?; single thread only!
__seh_save_ebp dd ?
__seh_save_esi dd ?
__seh_save_edi dd ?
.code
IFDEF DEBUG
GetExceptStr proc dwExceptCode
mov eax,dwExceptCode
.if eax == STATUS_BREAKPOINT
mov eax,T('BREAKPOINT')
.elseif eax == STATUS_SINGLE_STEP
mov eax,T('SINGLE_STEP')
.elseif eax == STATUS_GUARD_PAGE_VIOLATION
mov eax,T('GUARD_PAGE_VIOLATION')
.elseif eax == STATUS_ACCESS_VIOLATION
mov eax,T('ACCESS_VIOLATION')
.elseif eax == STATUS_ILLEGAL_INSTRUCTION
mov eax,T('ILLEGAL_INSTRUCTION')
.elseif eax == STATUS_PRIVILEGED_INSTRUCTION
mov eax,T('PRIVILEGED_INSTRUCTION')
.elseif eax == STATUS_INTEGER_DIVIDE_BY_ZERO
mov eax,T('INTEGER_DIVIDE_BY_ZERO')
.elseif eax == EXCEPTION_FLT_DIVIDE_BY_ZERO
mov eax,T('FLT_DIVIDE_BY_ZERO')
.else
mov edx,T(' ')
push edx
invoke wsprintf,edx,T('%.8X'),eax
pop eax
.endif
ret
GetExceptStr endp
ENDIF
IFDEF DEBUG
.data
db "Project build date: "
db @CatStr(<!">,@SubStr(%@Date,4,2),<.>,@SubStr(%@Date,1,2),<.>,@SubStr(%@Date,7,2),<!">),13,10
db "Masm v",@CatStr(<!">,@SubStr(@CatStr(<%@Version>),1,1),<.>,@SubStr(@CatStr(<%@Version>),2,2),<!">),0
sehExceptionCap db 'indolent programmer!',0
sehExceptionCp2 db 'EXCEPTION NON CONTINUABLE',0
sehExceptionMsg db 'Exception Occured at Address : %.8X',13,10
db 'Exception Code : %s',13,10,13,10
db 'Last Function Recorded was : %s',13,10
szcontb db 13,10
db 'Continue?',0
.data?
sehExceptionMsgbuff db 100h dup(?)
.code
ENDIF
__seh__UnhandledException proc
pushad
mov esi,[esp][4*8][1*4] ;; pExceptPtrs
mov edi,[esi].EXCEPTION_POINTERS.pExceptionRecord
mov esi,[esi].EXCEPTION_POINTERS.ContextRecord
invoke GetExceptStr,[edi].EXCEPTION_RECORD.ExceptionCode
mov edx,eax
mov eax,__dbg_lastprocname
.if !eax
mov eax,offset __dbg_1
.endif
mov szcontb,0
invoke wsprintf,addr sehExceptionMsgbuff,addr sehExceptionMsg,\
[edi].EXCEPTION_RECORD.ExceptionAddress,edx,eax
mov eax,MB_OK or MB_ICONHAND or MB_TOPMOST
mov edx,offset sehExceptionCp2
invoke MessageBox,0,addr sehExceptionMsgbuff,edx,eax
popad
mov eax,EXCEPTION_CONTINUE_SEARCH
retn
__seh__UnhandledException endp
__seh_handler proc ;c pExcept,pFrame,pContext,pDispatch
IFNDEF DEBUG
push edx
mov edx,[esp][3*4][4]; ContextRecord Arg of EXCEPTION_ROUTINE
mov eax,offset __cleanup_seh
mov [edx].CONTEXT.regEip,eax
mov eax,[__seh_save_ebp]
mov [edx].CONTEXT.regEbp,eax
mov eax,[__seh_save_edi]
mov [edx].CONTEXT.regEdi,eax
mov eax,[__seh_save_esi]
mov [edx].CONTEXT.regEsi,eax
or [edx].CONTEXT.regEax,-1
xor eax,eax ; ExceptionContinueExecution
pop edx
retn; CDECL
ELSE
pushad
mov edi,[esp][4*8][3*4] ;; Context
mov esi,[esp][4*8][1*4] ;; pExcept
push offset __cleanup_seh
pop [edi].CONTEXT.regEip
push [__seh_save_ebp]
pop [edi].CONTEXT.regEbp
push [__seh_save_edi]
pop [edi].CONTEXT.regEdi
push [__seh_save_esi]
pop [edi].CONTEXT.regEsi
mov ebx,[esi].EXCEPTION_RECORD.ExceptionFlags
invoke GetExceptStr,[esi].EXCEPTION_RECORD.ExceptionCode
mov edx,eax
mov eax,__dbg_lastprocname
.if !eax
mov eax,offset __dbg_1
.endif
.if ebx == EXCEPTION_NONCONTINUABLE
mov szcontb,0
.else
mov szcontb,13
.endif
invoke wsprintf,addr sehExceptionMsgbuff,addr sehExceptionMsg,\
[esi].EXCEPTION_RECORD.ExceptionAddress,edx,eax
mov eax,MB_YESNO or MB_ICONERROR or MB_TOPMOST
mov edx,offset sehExceptionCap
.if ebx == EXCEPTION_NONCONTINUABLE
mov eax,MB_OK or MB_ICONHAND or MB_TOPMOST
mov edx,offset sehExceptionCp2
.endif
invoke MessageBox,0,addr sehExceptionMsgbuff,edx,eax
or [edi].CONTEXT.regEax,-1
.if eax == IDNO || ebx == EXCEPTION_NONCONTINUABLE
mov eax,offset __seh_terminate
mov [edi].CONTEXT.regEip,eax
.endif
popad
xor eax,eax
retn
ENDIF
__seh_handler endp
__seh_terminate proc
xor eax,eax
mov edx,[_imp__ExitProcess@4]
dec eax
push eax
call edx
int 3
__seh_terminate endp
__setup_seh proc
mov __current_seh_calee,eax
pop eax
mov __seh_save_ebp,ebp
mov __seh_save_edi,edi
mov __seh_save_esi,esi
push offset __seh_handler
push fs:[NT_TIB.ExceptionList]
mov fs:[NT_TIB.ExceptionList],esp
push eax
retn
__setup_seh endp
__cleanup_seh proc
mov esp,fs:[NT_TIB.ExceptionList]
pop fs:[NT_TIB.ExceptionList]
add esp,4
push dword ptr [__current_seh_calee]
retn
__cleanup_seh endp
?Prolog MACRO procname, flags, parambytes, localbytes, reglist, userparams
LOCAL r,fforce,fseh
;%echo procname, flags, parambytes, localbytes, reglist, userparams
ifdef DEBUG
ifndef __dbg_lastprocname
.data
align 4
__dbg_lastprocname dd offset __dbg_1
__dbg_1 db '???',0
.code
endif
.data
__dbg_sz&procname db '&procname',0
.code
mov dword ptr [__dbg_lastprocname],offset __dbg_sz&procname
endif
fforce = 0
fseh = 0
for r,<userparams>
ifidni <&r>,<FORCEFRAME>
fforce = 1
elseifidni <&r>,<FORCENOFRAME>
fforce = 2
elseifidni <&r>,<SEH>
fseh = 1
endif
endm
IF (parambytes+localbytes) NE 0
if fforce ne 2
push ebp
mov ebp,esp
endif
IF localbytes NE 0
add esp,-localbytes
ENDIF
elseif fforce eq 1
push ebp
mov ebp,esp
ENDIF
IFNB <reglist>
FOR r, reglist
push r
ENDM
ENDIF
IF fseh eq 1
mov eax,offset __&procname&__cleanup
call __setup_seh
endif
EXITM %localbytes
ENDM
?Epilog MACRO procname, flags, parambytes, localbytes, reglist, userparams
LOCAL r,fforce,fseh
;;%echo procname, flags, parambytes, localbytes, reglist, userparams
fforce = 0
fseh = 0
for r,<userparams>
ifidni <&r>,<FORCEFRAME>
fforce = 1
elseifidni <&r>,<FORCENOFRAME>
fforce = 2
elseifidni <&r>,<SEH>
fseh = 1
endif
endm
IF fseh eq 1
call __cleanup_seh
__&procname&__cleanup:
endif
if (fforce eq 2) and (localbytes ne 0)
add esp,localbytes
endif
IFNB <reglist>
FOR r, reglist
pop r
ENDM
ENDIF
if fforce ne 2
IF (parambytes+localbytes NE 0) OR (fforce eq 1)
leave
;mov esp,ebp
;pop ebp
ENDIF
endif
; flags and 10000b = true :: caller cleans stack
IF ( (flags and 10000b) ) OR ( parambytes EQ 0 )
ret
ELSE
ret parambytes
ENDIF
ENDM
popcontext LISTING
OPTION PROLOGUE:?Prolog
OPTION EPILOGUE:?Epilog
Mind boggling :eek
As it sits, I get:
Assembling: F:\WinAsm\Progs\alltemps\tst7\tst.asm
F:\WinAsm\Progs\alltemps\tst7\tst.asm(66) : error A2006: undefined symbol : T
F:\WinAsm\Progs\alltemps\tst7\tst.asm(66) : error A2114: INVOKE argument type mismatch : argument : 0
F:\WinAsm\Progs\alltemps\tst7\tst.asm(310) : error A2088: END directive required at end of file
F:\WinAsm\Progs\alltemps\tst7\tst.asm(48) : error A2006: undefined symbol : T
F:\WinAsm\Progs\alltemps\tst7\tst.asm(50) : error A2006: undefined symbol : T
F:\WinAsm\Progs\alltemps\tst7\tst.asm(52) : error A2006: undefined symbol : T
F:\WinAsm\Progs\alltemps\tst7\tst.asm(54) : error A2006: undefined symbol : T
F:\WinAsm\Progs\alltemps\tst7\tst.asm(56) : error A2006: undefined symbol : T
F:\WinAsm\Progs\alltemps\tst7\tst.asm(58) : error A2006: undefined symbol : T
F:\WinAsm\Progs\alltemps\tst7\tst.asm(60) : error A2006: undefined symbol : T
F:\WinAsm\Progs\alltemps\tst7\tst.asm(62) : error A2006: undefined symbol : T
F:\WinAsm\Progs\alltemps\tst7\tst.asm(64) : error A2006: undefined symbol : T
F:\WinAsm\Progs\alltemps\tst7\tst.asm(97) : error A2006: undefined symbol : __dbg_lastprocname
F:\WinAsm\Progs\alltemps\tst7\tst.asm(99) : error A2006: undefined symbol : __dbg_1
F:\WinAsm\Progs\alltemps\tst7\tst.asm(143) : error A2006: undefined symbol : __dbg_lastprocname
F:\WinAsm\Progs\alltemps\tst7\tst.asm(145) : error A2006: undefined symbol : __dbg_1
F:\WinAsm\Progs\alltemps\tst7\tst.asm(174) : error A2006: undefined symbol : _imp__ExitProcess@4
if I move the prolog macro up, no errors. Now to test ......
It's very simple to use.
DEBUG EQU <nothing but evil>
.NOLIST
.NOCREF
.NOLISTMACRO
.686p
.mmx
.xmm
.model flat,stdcall
option casemap:none
assume fs:nothing
include windows.inc
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
T MACRO __qstr:VARARG
LOCAL __sym
.DATA
ALIGN 4
__sym DB __qstr,0
ALIGN 4
.CODE
EXITM <OFFSET __sym>
ENDM
.LIST
include catchexception.inc
TestProc proc <SEH>
xor eax,eax
mov eax,[eax]
ret
TestProc endp
start:
call TestProc
invoke ExitProcess
end start
Okay, getting closer. Down to-
F:\WinAsm\Progs\alltemps\tst7\catchexception.inc(305) : error A2008: syntax error : Report
F:\WinAsm\Progs\alltemps\tst7\tst.asm(40) : error A2137: too few arguments to INVOKE
F:\WinAsm\Progs\alltemps\tst7\catchexception.inc(169) : error A2006: undefined symbol : _imp__ExitProcess@4
I'll find it.
Opps, mostly my fault. cut and paste, ugh.
only error left-
F:\WinAsm\Progs\alltemps\tst7\catchexception.inc(169) : error A2006: undefined symbol : _imp__ExitProcess@4
ah yes, sry, my inlcude files look like this
EXTERNDEF STDCALL _imp__EnumTimeFormatsW@12:PPROTO@12
EXTERNDEF STDCALL _imp__EnumUILanguagesA@12:PPROTO@12
EXTERNDEF STDCALL _imp__EnumUILanguagesW@12:PPROTO@12
EXTERNDEF STDCALL _imp__EraseTape@12:PPROTO@12
EXTERNDEF STDCALL _imp__EscapeCommFunction@8:PPROTO@8
EXTERNDEF STDCALL _imp__ExitProcess@4:PPROTO@4
EXTERNDEF STDCALL _imp__ExitThread@4:PPROTO@4
EXTERNDEF STDCALL _imp__ExpandEnvironmentStringsA@12:PPROTO@12
EXTERNDEF STDCALL _imp__ExpandEnvironmentStringsW@12:PPROTO@12
EXTERNDEF STDCALL _imp__FatalAppExitA@8:PPROTO@8
No jmp thunk is generated
PROTO@4 TYPEDEF PROTO STDCALL :DWORD
EXTERNDEF STDCALL _imp__ExitProcess@4:PTR PROTO@4
;ExitProcess EQU <_imp__ExitProcess@4>
http://www.masm32.com/board/index.php?topic=6369.0
so: mov eax,[_imp__ExitProcess@4]
is equal to eax=getprocaddress(exitprocess) but the address is from import table
It works. :U Now to figure out how.
You mentioned you wanted it for tracing so i included the seh stuff too, it's my old code and it definitely needs to be rewritten.
Yeah, the simple answer to the OP's question would be a prologue identical the the default PROLOGUEDEF, with the addition of setting an external variable to the procname parameter.
Any simple way to get a copy of PROLOGUEDEF? It seems it could be quite complicated to duplicate from scratch taking into account the various proc types and such.
Check out this page and code by Zooba
http://msdn.microsoft.com/en-us/library/4zc781yh(VS.80).aspx
Must be wrong link, that just sends me to msdn.
EDIT: oops, I see now that is indeed by Zooba. Must be the correct link.
There they say "Here is a sample prologue macro which provides basic frame functionality".
That implies it is not the actual PROLOGUEDEF, just an example. I'm only concerned with replacing the prologue and not covering all the possibilities like pascal, c, syscall, etc.
Playing around, I stripped down your prologue and got this to work:
.NOLIST
.NOCREF
.NOLISTMACRO
.686p
.mmx
.xmm
.model flat,stdcall
option casemap:none
assume fs:nothing
include windows.inc
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
xProlog MACRO procname, flags, parambytes, localbytes, reglist, userparams
LOCAL r,fforce,fseh
fforce = 0
for r,<userparams>
ifidni <&r>,<FORCEFRAME>
fforce = 1
elseifidni <&r>,<FORCENOFRAME>
fforce = 2
endif
endm
IF (parambytes+localbytes) NE 0
if fforce ne 2
push ebp
mov ebp,esp
endif
IF localbytes NE 0
add esp,-localbytes
ENDIF
elseif fforce eq 1
push ebp
mov ebp,esp
ENDIF
IFNB <reglist>
FOR r, reglist
push r
ENDM
ENDIF
xprocname textequ <&procname>
EXITM %localbytes
ENDM
OPTION PROLOGUE:xProlog
.LIST
.code
.listall
TestProc proc
nop
%echo testing xprocname
.data ; just to test with messagebox
%xxproc db "&xprocname&",0
.code
invoke MessageBox,0,addr xxproc,0,0
ret
TestProc endp
start:
call TestProc
invoke ExitProcess,0
end start
For some reason, xprocname is only available after the first instruction so I had to insert a nop. I can't see any reason for that.
That works at runtime, like my earlier post above, and fails at assembly time, i.e. the echos come in the wrong order, as shown below. Where do you see a practical application?
.NOLIST
.NOCREF
.NOLISTMACRO
.686p
.mmx
.xmm
.model flat,stdcall
option casemap:none
assume fs:nothing
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
xProlog MACRO procname, flags, parambytes, localbytes, reglist, userparams
LOCAL r,fforce,fseh
fforce = 0
for r,<userparams>
ifidni <&r>,<FORCEFRAME>
fforce = 1
elseifidni <&r>,<FORCENOFRAME>
fforce = 2
endif
endm
IF (parambytes+localbytes) NE 0
if fforce ne 2
push ebp
mov ebp,esp
endif
IF localbytes NE 0
add esp,-localbytes
ENDIF
elseif fforce eq 1
push ebp
mov ebp,esp
ENDIF
IFNB <reglist>
FOR r, reglist
push r
ENDM
ENDIF
xprocname textequ <&procname>
EXITM %localbytes
ENDM
OPTION PROLOGUE:xProlog
.LIST
.code
.listall
TestProc proc
nop
%echo testing xprocname
.data ; just to test with messagebox
%xxproc db "&xprocname&",0
.code
invoke MessageBox,0,addr xxproc,0,0
ret
TestProc endp
TestBProc proc
nop
%echo testing xprocname
.data ; just to test with messagebox
%x1proc db "&xprocname&",0
.code
invoke MessageBox,0,addr x1proc,0,0
ret
TestBProc endp
TestCProc proc
nop
%echo testing xprocname
.data ; just to test with messagebox
%x2proc db "&xprocname&",0
.code
invoke MessageBox,0,addr x2proc,0,0
ret
TestCProc endp
start:
call TestBProc
call TestProc
call TestCProc
; .err
invoke ExitProcess,0
end start
The only option I can see that is obviously missing is LOADDS, which I would never use, but would want to support.
jj-
I don't see what you are saying. If you look at the output listing, the procs are listed in the order that they appear. At execution time, the messageboxes show in the order the procs were executed. The advantage over what you posted earlier is that you don't have to put anything in the proc that contains any part of the proc name, e.g. CurProcCt = 1
So if you want to trace, you only have to add to each proc the same macro statement, e.g. TRACELOG, you don't have to manually copy each proc name to pass to a macro. I've done this in a large program and it's really a pain to copy all the proc names to pass them to a macro.
For example, this is what I use now:
PaintGrid proc
trlog PaintGrid
where trlog=
trlog macro pname,lev:vararg ;; print each proc name in log as executed
routine textequ <*pname>
if Trace and PrintLog
ifb <lev>
inc indent
indentflag=1
else
indentflag=0
endif
%plogm "&routine"
endif
EndM
the other support macros are:
if PrintLog
include \WinAsm\Progs\AllMyStuff\PrtLog.inc
indentflag=1
endif
plog macro args:vararg
if PrintLog
plogm args
endif
EndM
dedent macro lev:vararg
if Trace and PrintLog
ifb <lev>
dec indent ;; do not affect carry flag
endif
endif
EndM
prtlog is too big to show in it's entirety here, but it starts-
prtlog proto umsg:dword,cmt:dword,hctrl:dword,DoIndent:dword ; umsg=-1 means just print comment in cmt
plogm macro val,strgadd ;; print to log, String and Value
Local LocalText,pstr
pusha
if indentflag eq 1
indentamt textequ <indent>
else
indentamt textequ <0>
endif
ifb <strgadd>
quote substr <val>,1,1
ifidn quote,<">
.data
LocalText db val,0
.code
invoke prtlog,-1,offset LocalText,-1,indentamt
popa
exitm
endif
arg2 catstr <">,<val>,<">
.data
LocalText db arg2,0
.code
pstr equ <offset LocalText>
else
quote SUBSTR <strgadd>,1,1
IFIDN quote , <"> ;; if this is a quoted string
.data
LocalText db strgadd,0
.code
pstr equ <offset LocalText>
else
pstr equ strgadd
endif
endif
invoke prtlog,-1,pstr,val,indentamt
popa
EndM
.data?
hMsgLog dd ?
.data
ilfmtx db "%s%s=%li id=%li",0
lgfmtx db "%s%s %i",0
lgfmtx2 db "%s%s",0
firstprtmsg dd 1
LogName db ".\msg.log",0
unknownmsg db " unknown",0
indentblanks db 20 dup (" ")
endindents db 0
baddr dd 0
CloseLog = 99999999
.code
prtlog proc umsg,cmt,hctrl,numindents ; umsg=-1 means just print comment in cmt
local junkx:dword,llen:dword,prtdBuffx[512]:byte,dlgid:dword
pusha
m2m baddr,offset endindents ; assume no indents
mov eax,numindents
.if eax
sif eax > 0 && eax < 20
sub baddr,eax
.endif
.endif
mov dlgid,0
.if sdword ptr hctrl>0 && sdword ptr umsg != -1
inv GetDlgCtrlID,hctrl
mov dlgid,eax
.endif
.if firstprtmsg
mov firstprtmsg,0
inv CreateFile,addr LogName,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0
mov hMsgLog,eax
.elseif umsg==WM_NCDESTROY || umsg==99999999 ; one of the last messages, close handle
inv CloseHandle,hMsgLog
mov hMsgLog,0
.endif
.if sdword ptr umsg==-1
.if hctrl==-1 && sdword ptr umsg != -1
inv wsprintf,addr prtdBuffx,addr lgfmtx2,baddr,cmt
.else
inv wsprintf,addr prtdBuffx,addr lgfmtx,baddr,cmt,hctrl
.endif
.else
.if umsg < 401h
mov eax,umsg ; get offset to text description for this message
shl eax,2
add eax,Table
mov eax,[eax]
.if byte ptr[eax]==0
mov eax,offset unknownmsg
.endif
.else
.if cmt!=0
mov eax,cmt
.else
mov eax,offset unknownmsg
.endif
.endif
inv wsprintf,addr prtdBuffx,addr ilfmtx,baddr,eax,umsg,dlgid
.endif
lea esi,prtdBuffx
mov ecx,1
.repeat
lodsb
inc ecx
.until al==0
mov dword ptr [esi-1],0a0dh
mov llen,ecx
.if hMsgLog==0 ; near the end, has already been closed, append to existing
inv CreateFile,addr LogName,GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
mov hMsgLog,eax
inv SetFilePointer,eax,0,0,FILE_END
inv WriteFile,hMsgLog,addr prtdBuffx,llen,addr junkx,0
inv CloseHandle,hMsgLog
mov hMsgLog,0
.else
inv WriteFile,hMsgLog,addr prtdBuffx,llen,addr junkx,0
.endif
popa
ret
prtlog EndP
.data
wm0 db "WM_NULL",0
wm1 db "WM_CREATE",0
wm2 db "WM_DESTROY",0
wm3 db "WM_MOVE",0
wm4 db 0
wm5 db "WM_SIZE",0
followed by all the umsgs a dlgproc can get, so I can print out in the log each one as it is triggered.
This produces an output that looks like:
WM_ERASEBKGND=20 id=1005
*GridUProc -1
WM_PAINT=15 id=1006
*PaintGrid -1
*GridUProc -1
WM_NCPAINT=133 id=1006
*GridUProc -1
WM_ERASEBKGND=20 id=1006
*GridMsg -1
*pSetCellText -1
*GetCellAdr -1
*CheckSingleCol -1
*CheckSingleRow -1
*CreateAndPaint -1
*CreateGrid -1
*PaintGrid -1
*GridMsg -1
*pSetCellText -1
*GetCellAdr -1
*CheckSingleCol -1
*CheckSingleRow -1
*CreateAndPaint -1
*CreateGrid -1
*PaintGrid -1
*GridMsg -1
*pSetCellText -1
*GetCellAdr -1
*CheckSingleCol -1
*CheckSingleRow -1
*CreateAndPaint -1
*CreateGrid -1
*PaintGrid -1
*GridMsg -1
*pSetCellText -1
*GetCellAdr -1
*CheckSingleCol -1
*CheckSingleRow -1
*CreateAndPaint -1
This should be close enough (functionally identical) to default "macros".
PrologueDef32 MACRO procname, flags, parambytes, localbytes, reglist, userparms
LOCAL ff
ff = 0
IFNB <userparms>
ff = @InStr(,<userparms>,<FORCEFRAME>)
ENDIF
IF (parambytes+localbytes) NE 0 OR ff
push ebp
mov ebp,esp
ENDIF
IF localbytes NE 0
add esp,-localbytes
ENDIF
FOR reg,reglist
push reg
ENDM
EXITM %localbytes
ENDM
EpilogueDef32 MACRO procname, flags, parambytes, localbytes, reglist, userparms
LOCAL ff
ff = 0
IFNB <userparms>
ff = @InStr(,<userparms>,<FORCEFRAME>)
ENDIF
FOR reg,reglist
pop reg
ENDM
IF (parambytes+localbytes NE 0) OR ff
leave ;; mov esp,ebp / pop ebp
ENDIF
;; flags and 10000b = true :: caller cleans stack
IF (flags and 10000b);; OR ( parambytes EQ 0 )
ret
ELSE
ret parambytes
ENDIF
ENDM
PrologueDef16 MACRO procname, flags, parambytes, localbytes, reglist, userparms
LOCAL ff
ff = 0
IFNB <userparms>
ff = @InStr(,<userparms>,<FORCEFRAME>)
ENDIF
IF (parambytes+localbytes) NE 0 OR ff
push bp
mov bp,sp
ENDIF
IF localbytes NE 0
add sp,-localbytes
ENDIF
IFNB <userparms>
IF @InStr(1,<userparms>,<LOADDS>)
push ds ;; Save DS and point it to DGROUP
mov ax,DGROUP
mov ds,ax
ENDIF
ENDIF
FOR reg,reglist
push reg
ENDM
EXITM %localbytes
ENDM
EpilogueDef16 MACRO procname, flags, parambytes, localbytes, reglist, userparms
LOCAL ff
FOR reg,reglist
pop reg
ENDM
ff = 0
IFNB <userparms>
ff = @InStr(,<userparms>,<FORCEFRAME>)
IF @InStr(,<userparms>,<LOADDS>)
pop ds ;; Restore DS
ENDIF
ENDIF
IF (parambytes+localbytes NE 0) OR ff
leave
ENDIF
;; flags and 10000b = true :: caller cleans stack
IF (flags and 10000b);; OR ( parambytes EQ 0 )
ret
ELSE
ret parambytes
ENDIF
ENDM
IF @WordSize EQ DWORD
OPTION PROLOGUE:PrologueDef32
OPTION EPILOGUE:EpilogueDef32
ELSE
OPTION PROLOGUE:PrologueDef16
OPTION EPILOGUE:EpilogueDef16
ENDIF
EDIT: small typo and error
Wow, that's much simpler. Thanks alot :clap:
Do you see any problem with just using the prologue and letting masm use the default epilogue?
Quote from: Jimg on January 23, 2009, 10:04:23 PMDo you see any problem with just using the prologue and letting masm use the default epilogue?
FORCEFRAME will not work - masm fault. Everything else works.
This is going to come in real handy and totally replace my current tracking/logging system. Thank you very much Drizz. :U
Quote from: Jimg on January 23, 2009, 07:24:48 PM
I've done this in a large program and it's really a pain to copy all the proc names to pass them to a macro.
You convinced me :U
Kuhl!
It's almost what JWasm does. There is one difference: if parmbytes + localbytes is 0, but VARARG is true, then JWasm will also create a stack frame.
Details in proc.c, function write_default_prologue():
if( ( info->localsize != 0 ) || ( info->parasize != 0 ) || info->is_vararg || info->forceframe ) {
if( ModuleInfo.Use32 ) {
/* write 80386 prolog code
PUSH EBP
MOV EBP, ESP
SUB ESP, localsize
*/
AddLineQueue( "push ebp" );
AddLineQueue( "mov ebp, esp" );
if( info->localsize != 0 ) {
if ( Options.masm_compat_gencode )
sprintf( buffer, "add esp, %d", -info->localsize );
else
sprintf( buffer, "sub esp, %d", info->localsize );
AddLineQueue( buffer );
}
} else {
/* write 8086 prolog code
PUSH BP
MOV BP, SP
SUB SP, localsize
*/
AddLineQueue( "push bp" );
AddLineQueue( "mov bp, sp" );
if( info->localsize != 0 ) {
if ( Options.masm_compat_gencode )
sprintf( buffer, "add sp, %d", -info->localsize );
else
sprintf( buffer, "sub sp, %d", info->localsize );
AddLineQueue( buffer );
}
}
}
if ( info->loadds ) {
AddLineQueue( "push ds" );
AddLineQueue( "mov ax, DGROUP" );
if ( ModuleInfo.Use32 )
AddLineQueue( "mov ds, eax" );
else
AddLineQueue( "mov ds, ax" );
}
/* Push the registers */
if( info->regslist ) {
strcpy( buffer, "push " );
len = strlen( buffer );
for( regist = info->regslist; regist; regist = regist->next ) {
strcpy( buffer + len, regist->reg );
AddLineQueue( buffer );
}
}
Japheth-
How does one test for vararg in a prologue?
I ran a test using:
TestCProc proc SYSCALL x1:vararg
nop
ret
TestCProc endp
and the epilogue in this case does not do a "mov esp, ebp" like normal. Was this intentional?
EDIT:
Scratch that, I see that you never to that unless there are locals. I remember a discussion about that somewhere. Still want to know about vararg however.