News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Get Function Name

Started by 2-Bit Chip, August 23, 2009, 03:32:45 AM

Previous topic - Next topic

2-Bit Chip

Would there be a way to get the function name (as a string) that called SetLastError? Or, will I just have to live with the
"0xXXXXXXXX - Error description here"?

Sincerely,

Chip

dedndave

i was looking at that myself
all the text is right there in the data segment - you just have to find a way to connect the dots
when the pe format exe gets loaded, windows looks through the list to resolve externals
problem is, it wasn't meant to be used the other way around
but, i think a routine could be written to create a "reverse" list
for smaller programs, you may be just as well off to create the list yourself
but, for larger programs that use a lot of different functions, the routine might save some space

2-Bit Chip

I really would like to display an error as "[Function Name] - [Error Code] - [Error Description]."

I guess it would be more informative.

2-Bit Chip

Well.. I am using this simple, little piece of code to show the errors:


fThrowError:
    mov edi, alloc$(MAX_PATH)
    mov edx, alloc$(MAX_PATH)
    invoke GetLastError
    invoke dw2hex, eax, edx
    invoke wsprintf, edi, CADD("0x%s - %s"), edx, LastError$()
    invoke MessageBoxA, NULL, edi, NULL, MB_OK or MB_ICONERROR
    exit

dedndave

it gets a bit wordy, but you can also display the address of the invoke
it shouldn't be too difficult to create an error routine that can be used for all invokes in the program
it could call GetLastError and give the error code
pass it the address of a string that identifies the invoke, as well as the address

.
.
        INVOKE  GetPriorityClass,
                hProc
LabelA:
        or      eax,eax
        jnz     Success

        mov     edx,offset GetPrioClsStr  ;"GetPriorityClass",0
        mov     ecx,offset LabelA
        call    DisplayError
        jmp     ErrorExit

Success:
.
.
ErrorExit:
.
.
DisplayError    PROC

        push    ecx
        push    edx
        INVOKE  GetLastError
        push    eax
        print   chr$('Error: ')
        pop     eax
        print   str$(eax),' in Function: '
        pop     eax
        print   eax
        print   chr$(' at Address: ')
        pop     eax
        sub     eax,5
        print   uhex$(eax),13,10
        ret

DisplayError    ENDP

2-Bit Chip

Thank you Dan. I'm not real hip with wordiness :P

Tedd

This might be useful..

;hWnd = global handle to your main app window (you could just add it as a param to this function)
;AppName = a string giving the name of your main app (for the messagebox titlebar)

ErrorMessageBox proc pMsg:DWORD,errCode:DWORD
    LOCAL buff[512]:BYTE
    push edi
    lea edi,[buff]
    invoke lstrcpy, edi,pMsg
    mov ecx,SIZEOF buff
    lea edx,[edi+eax]
    sub ecx,eax
    invoke FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM,NULL,errCode,0,edx,ecx,NULL
    invoke MessageBox, hWnd,edi,ADDR AppName,MB_OK or MB_ICONERROR
    pop edi
    ret
ErrorMessageBox endp


Example usage..

errFileOpen     db "Error opening file.",13,10,0

    invoke GetLastError
    invoke ErrorMessageBox, ADDR errFileOpen,eax



As for getting the function name, it's quite a bit extra as they're not (normally) stored in the exe. You could add them as debug info and then extract them from that. Or, build a table of the offsets of functions in your code, then use that in the error function to see who the caller was (get the return address from the stack, and see where that falls in the table.)
No snowflake in an avalanche feels responsible.

dedndave

Hi Tedd
i see them in my exe file
in this case, it is a console app using these command lines

ml /c /coff %1.asm
Link /SUBSYSTEM:CONSOLE /OPT:NOREF %1.obj

ExitProcess.¥.FillConsoleOutputAttribute..Æ.FlushConsoleInputBuffer.ï.GetConsoleCursorInfo..ò.
GetConsoleMode..õ.GetConsoleScreenBufferInfo....GetCurrentProcess...GetCurrentThread..H.
GetPriorityClass..T.GetProcessAffinityMask..j.GetStdHandle..y.GetSystemTimeAsFileTime.p.
SetConsoleCursorInfo..q.SetConsoleCursorPosition..r.SetConsoleMode..u.SetConsoleTextAttribute.v.
SetConsoleTitleA....SetPriorityClass..ž.SetProcessAffinityMask..­.SetThreadPriority.».Sleep.â.
VirtualProtect..û.WriteFile.kernel32.dll..Î._getch...._kbhit..msvcrt.dll

Tedd

Ah, my mistake - I read it wrong; I took it as 'which of the functions in my code produced the error.'

Yeah, all the imported functions have their names stored in the executable so they can be imported. There's also a table produced when the program is loaded that receives the addresses of each of those functions, so they can be called. So that could potentially be used for finding which function was called last, but it would be quite hackish and depend on not doing anything at all after calling the function.

I presume the reason for checking where the error was produced is for debugging, so you can find where you went wrong in your code. A much easier way would be to use the _LINE_ directive to tell the error reporter which line it was called from, but masm doesn't appear to have one (or I can't find it) ::)
But, given a source address, you can still easily find where it was called from, and look what was called before that - it should be clear from the error message what caused it (should :bdg)
No snowflake in an avalanche feels responsible.

dedndave

what i was thinking was writing a little routine that locates the address of the text string for a specific function call
that way, you do not have to duplicate the text in data (saves space AND some typing - lol)
as i mentioned in an earlier post, the tables are made backwards for that purpose, of course
besides the IAT that gets filled with resolved addresses, each string has an offset into the IAT (presumably)
also, at the end of each group of text strings is the library
in other words, all the kernel32.dll's are listed, then text that says "kernel32.dll"
then, as in my example, the msvcrt.dll functions are listed
you could write an error routine that had a disply like this

Error: 5 in Function: SetProcessAffinityMask from Library: kernel32.dll at Address 40201234

the text for "SetProcessAffinityMask" and "kernel32.dll" could come from the already existing list
i know this isn't that hard, and when i get done working on my current project, i may have a look at it
EDIT - the list should always contain ExitProcess and is alphabetically arranged, too

sinsi

>the text for "SetProcessAffinityMask" and "kernel32.dll" could come from the already existing list
I think the only way in masm is to use GetProcAddress and import all of your functions, but that would be a pain.
Is there any way of making a .obj file with the import section to link with? Lots of externdef's for the .inc file though...
Light travels faster than sound, that's why some people seem bright until you hear them.

dedndave

the text exists in the .data section
no reason you couldn't locate it and use it
the IAT entry is easy enough - the invoke has that address
lol Sinsi - you're gonna make me stop working on my current project and make this - lol

jj2007

Quote from: Tedd on August 24, 2009, 11:51:47 AM
A much easier way would be to use the _LINE_ directive to tell the error reporter which line it was called from, but masm doesn't appear to have one

Try this one :bg

include \masm32\include\masm32rt.inc

.code
start:

MsgBox 0, str$(@Line), "The error line", MB_OK

exit

end start

dedndave

#13
that's cool Jochen - a masm "pre-assigned equate"
it needs a little adjustment - lol
the line where you get the line number is at least one more than the error line (actually, 3 would be good)

        mov     eax,@Line
        dec     eax

i was looking in the masm manual - there are a few other useful values, also
@Date and @Time can be used to mark a file with assembly time info

EDIT - what i meant by "actually, 3 would be good" - a typical example

        INVOKE  SomeErrorProneFunction,parm2,parm1
        or      eax,eax
        jnz     Successful
        push dword ptr @Line
        INVOKE  GetLastError
        pop     edx
        sub     edx,3           ;adjust to point to the invoke line

Tedd

I thought I'd seen one before :cheekygreen:
No snowflake in an avalanche feels responsible.