Showing posts with label debug. Show all posts
Showing posts with label debug. Show all posts

Saturday, February 25, 2012

How to get function's name from function's pointer in C? (GCC extensions)

In my previous post I described how to get function's name from function's pointer in C under Windows for debug purposes.

In GCC you may use backtrace_symbolos declared in <execinfo.h>. An example looks like:

#include <execinfo.h>

void *pfunc = ...; /* pointer to some function */

void *buffer[1] = {pfunc};
char **strings = backtrace_symbols(buffer, 1);
if (strings == NULL) {
  perror("backtrace_symbols");
} else {
  printf("%s\n", strings[0]);
  free(strings);
}

You have to link with -rdynamic flag. The output looks like:

./a.out(myfunc+0) [0x400987]

If function is static name is omitted.

I recommend to use the things like this for debugging only.

How to print stack trace in C / C++ (GCC)

While discovering and debugging a large project it may be quite useful to print a stack trace. In Java I could use something like
new Exception().printStackTrace()
for that purpose. (Yes, I know, it looks stupid and I prefer not to commit a code like that to CVS, but this dirty hack can still be quite useful while debugging).

Is their anyway to achieve the same goal in C / C++?

Of course there is no portable solution. But several platforms provide their extensions. I recently discovered that GCC provides functions backtrace() and backtrace_symbols() declared in <execinfo.h>. An example is available here: http://linux.die.net/man/3/backtrace_symbols. We need to link with -rdynamic option. The output contains the name of executable file, the name of function (if available) and looks like:

./a.out(myfunc3+0x1c) [0x400904]
./a.out [0x400985]
./a.out(myfunc+0x23) [0x4009aa]
./a.out(main+0x78) [0x400a24]
/lib64/libc.so.6(__libc_start_main+0xf4) [0x377281d974]
./a.out [0x400839]

Or, in case of C++, the output can be:

a.out(_Z7myfunc3v+0x1c) [0x4009b4]
a.out(__gxx_personality_v0+0x18d) [0x400a35]
a.out(_Z6myfunci+0x23) [0x400a5b]
a.out(_Z6myfunci+0x1c) [0x400a54]
a.out(main+0x76) [0x400ad4]
/lib64/libc.so.6(__libc_start_main+0xf4) [0x377281d974]
a.out(__gxx_personality_v0+0x41) [0x4008e9]

Note that static function name is omitted in case of C or replaced with some dummy name in case of C++.

I still miss the information like source file names and line numbers. But at least this could give an idea of what to debug next.

However, I still wouldn't commit a code like that to production.

Sunday, February 19, 2012

How to get function's name from function's pointer in C? (Windows)

Suppose that I am debugging a code written on C which deals with a pointer to function. This pointer is initialized somewhere else and may actually point to function1, function2 etc. I need to find out
the real name of the function and print this information to the log, ideally together with source file name and line number (all this information is available if debugging information is turned on).

Yes, I know that I can set a breakpoint and see the actual value of pointer in debug windows. But sometimes I find a log a bit more useful.

Of course there is no reliable and cross-platform solution. The C language itself does not provide the possibilities like this. However, we may find API for certain platforms and/or certain debugging information.

For instance, in case of Windows the solution can be found with the help of DbgHelp functions: SymGetSymFromAddr64 and SymGetLineFromAddr64.

To be able to call both of them, we need to enable debug information. To be able to use SymGetLineFromAddr64, we need to turn on profile information as well (although it is not mentioned in the documentation, but it seems that SymGetLineFromAddr64 is not working without profile information).

The program needs to be linked with Dbghelp.lib.

Before their use we must call SymInitialize.

Now let's put it all together:

#if defined _DEBUG

#include <dbghelp.h>

BOOL InitDebug()
{
    BOOL initRes;

  SymSetOptions(SYMOPT_LOAD_LINES);

    initRes = SymInitialize(GetCurrentProcess(), NULL, TRUE);

    if (!initRes)
    {
        printf(_T("SymInitialize failed with error %d"), GetLastError());
    }

    return initRes;
}

BOOL TracePointerInfo(DWORD64 addr)
{
    char symbolName[MAX_SYM_NAME + 1];
    char buffer[sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME*sizeof(TCHAR)] = {0};
    IMAGEHLP_LINE64 line;
    DWORD64 dis64 = 0;
    DWORD dis = 0;
    IMAGEHLP_SYMBOL64 *pSym = NULL;
    BOOL res;

    pSym = (IMAGEHLP_SYMBOL64 *) buffer;
    pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
    pSym->MaxNameLength = MAX_PATH;

    res = SymGetSymFromAddr64(GetCurrentProcess(), addr, &dis64, pSym);
    if (!res)
    {
        /* TODO: call your trace function instead of printf */
        printf("SymGetSymFromAddr64 fails, error=%ld\n", GetLastError());
        return FALSE;
    }
    else
    {
        strcpy(symbolName, pSym->Name);
    }

    memset(&line, 0, sizeof(line));
    line.SizeOfStruct = sizeof(line);
    res = SymGetLineFromAddr64(GetCurrentProcess(), addr, &dis, &line);

    if (!res)
    {
        printf("SymGetLineFromAddr64 fails, error=%ld\n", GetLastError());
        return FALSE;
    }
    else
    {
        printf("function=%s (%s, %d)\n", symbolName, line.FileName, line.LineNumber);
    }

    return TRUE;
}

#define TRACE_POINTER_INIT InitDebug()
#define TRACE_POINTER(f) TracePointerInfo((DWORD64)(f))
#else

#define TRACE_POINTER_INIT
#define TRACE_POINTER(f)

#endif

To use it, call TRACE_POINTER_INIT somewhere in the beginning of your program.
To trace information about function pointer myfunction, use
TRACE_POINTER(myfunction);

Possible problems and how to fix them:
1. SymGetSymFromAddr64 fails, last error is 487 (Attempt to access invalid address. ). Answer: most likely debug information is not found. Rebuild the project for Debug.

2. SymGetSymFromAddr64 fails, last error is 6 (The handle is invalid). Answer: most likely SymInitialize was not called.

3. SymGetSymFromAddr64 succeed but SymGetLineFromAddr64 fails, last error is 487. That was the most tricky for me: documentation says nothing about it. It seems that you have to enable profile information (Project->Properties, Configuration Properties, Linker, Advanced, make sure that Profile is "Enable ..."). However I found it by playing with options. I didn't find any explanation in the documentation.

Friday, November 18, 2011

MS Visual Studio: debugging tips

How to cause a debug break of a Windows process.

Sometimes it's impossible to start a process under debugger. Instead, I want the debugger to be started when a process reaches some point.

To cause a debug break from the code, choose any of the following:
  1. Call DebugBreak() API.
  2. Call the built-in function __debugbreak().
  3. __asm int 3;
When any of this instruction is reached, a special window is usually displayed with a possibility to start debugger.

Why it is not working:

1. If you have Windows 7, go to Control Panel->Action Center->Change Action Center Settings->Problem Report Settings and make sure "Each time a problem occurs, ask me before checking for solutions" is checked (thanks to http://stackoverflow.com/questions/890890/debug-program-option-in-windows-7). Actually this is very important option. If it is not selected, the program crash can be silent, which is terrible for developers and testers.
2. In fact, all these commands cause breakpoint exception. So it is possible to ignore these exceptions with the help of Structured Exception Handling (SEH). For instance, the following code ignores debug break:

_try {
    DebugBreak();
} _except(EXCEPTION_EXECUTE_HANDLER) {
}

(of course, _except block can be located anywhere in call stack).

How to launch the Debugger Automatically when the application with the specified name starts.

It is possible to automatically debug an application of the specified name (for instance make "my_test.exe" always run under debugger). For details, see http://msdn.microsoft.com/en-us/library/a329t4ed%28v=vs.80%29.aspx