The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: korte on January 23, 2009, 04:00:27 PM

Title: echo procedure name
Post by: korte on January 23, 2009, 04:00:27 PM


proc1 proc
   .echo procedure name
proc1 endp


how I can detect the name of the procedure (inside a procedure).
I want to echo

Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 04:21:02 PM
I've often wanted such a function for tracing, but have never found a way, so I'm anxiously awaiting the answer also.
Title: Re: echo procedure name
Post by: jj2007 on January 23, 2009, 04:43:23 PM
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
Title: Re: echo procedure name
Post by: drizz on January 23, 2009, 04:56:43 PM
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.
Title: Re: echo procedure name
Post by: drizz on January 23, 2009, 04:57:39 PM
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
Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 05:02:51 PM
Mind boggling :eek
Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 05:17:04 PM
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 ......
Title: Re: echo procedure name
Post by: drizz on January 23, 2009, 05:20:43 PM
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

Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 05:26:52 PM
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.
Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 05:29:58 PM
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
Title: Re: echo procedure name
Post by: drizz on January 23, 2009, 05:35:21 PM
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
Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 05:39:59 PM
It works. :U  Now to figure out how.
Title: Re: echo procedure name
Post by: drizz on January 23, 2009, 05:43:52 PM
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.
Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 06:01:21 PM
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.
Title: Re: echo procedure name
Post by: drizz on January 23, 2009, 06:23:04 PM
Check out this page and code by Zooba
http://msdn.microsoft.com/en-us/library/4zc781yh(VS.80).aspx
Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 06:49:52 PM
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.


Title: Re: echo procedure name
Post by: jj2007 on January 23, 2009, 07:04:27 PM
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
Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 07:07:26 PM
The only option I can see that is obviously missing is LOADDS, which I would never use, but would want to support.
Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 07:24:48 PM
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.
Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 07:42:34 PM
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


Title: Re: echo procedure name
Post by: drizz on January 23, 2009, 09:23:49 PM
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
Title: Re: echo procedure name
Post by: Jimg on January 23, 2009, 10:04:23 PM
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?
Title: Re: echo procedure name
Post by: drizz on January 23, 2009, 10:21:24 PM
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.
Title: Re: echo procedure name
Post by: Jimg on January 24, 2009, 12:42:29 AM
This is going to come in real handy and totally replace my current tracking/logging system.  Thank you very much Drizz. :U
Title: Re: echo procedure name
Post by: jj2007 on January 24, 2009, 12:44:44 AM
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
Title: Re: echo procedure name
Post by: japheth on January 24, 2009, 09:42:08 AM

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 );
        }
    }

Title: Re: echo procedure name
Post by: Jimg on January 24, 2009, 03:59:04 PM
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.