2
void printStack(void) {
     HANDLE process = GetCurrentProcess();
     SymInitialize( process, NULL, TRUE );

     SymSetOptions(SYMOPT_LOAD_LINES);


     void *stack[64];
     unsigned short frames = CaptureStackBackTrace( 0, 64, stack, NULL );

     SYMBOL_INFO *symbol = (SYMBOL_INFO*) calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
     symbol->MaxNameLen = 255;
     symbol->SizeOfStruct = sizeof(SYMBOL_INFO);

     IMAGEHLP_LINE64 *line = NULL;
     DWORD lastError = 0;
     DWORD displacement;

  
     printf("Backtrace\n");
     for(int i = 0; i < frames; i++) {
         SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
         printf("\t %i: %s\n", frames - i - 1, symbol->Name);
         line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64));
         line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
         if (SymGetLineFromAddr64(process, (DWORD64)(stack[i]), &displacement, line)) {
                printf("%s %i\n", line->FileName, line->LineNumber);
         } else {
                printf("failed\n");
         }
        lastError = GetLastError();
        printf("errcode: %i\n", lastError);
        
        free(line);
        line = NULL;
     }

     free(symbol);
}


Backtrace
         5: _printStack
failed
errcode: 487
         4: _main
failed
errcode: 487
         3: __scrt_common_main_seh
failed
errcode: -1073741819
         2: BaseThreadInitThunk
failed
errcode: 487
         1: RtlGetAppContainerNamedObjectPath
failed
errcode: 487
         0: RtlGetAppContainerNamedObjectPath
failed
errcode: 487

I am trying to extract line numbers and file names from SymGetLineFromAddr64 but the address I am inputting is invalid. I am using (DWORD64)(stack[i]) for the address. What address do I use to be able to extract line information?

eat_a_lemon
  • 3,158
  • 11
  • 34
  • 50
  • Use the [StackWalk64 function](https://stackoverflow.com/questions/5705650/stackwalk64-on-windows-get-symbol-name). – Hans Passant Oct 17 '21 at 12:54
  • You can't rely on the `GetLastError()` result unless the API function failed. – 500 - Internal Server Error Oct 18 '21 at 20:52
  • SymGetLineFromAddr64 failed – eat_a_lemon Oct 18 '21 at 21:05
  • My bad, I was mislead by your reference to `lastError` on the "failed\n" line (before it gets set), but you're not actually printing out the value there. – 500 - Internal Server Error Oct 18 '21 at 21:23
  • Does adding a call to `SymSetOptions(SYMOPT_LOAD_LINES);` after the call to `SymInitialize()` help? – 500 - Internal Server Error Oct 18 '21 at 21:30
  • It does not help. I just tried it and I get the same result. – eat_a_lemon Oct 18 '21 at 21:34
  • I removed line = NULL and got some results. It looks to be a memory issue with this function it results in erratic behavior. – eat_a_lemon Oct 19 '21 at 16:30
  • I ran your code in minimal program, it gets filenames and line numbers, I don't get any error until it hits `BaseThreadInitThunk`. Your error handling is wrong. `GetLastError()` should be called immediately after fail. Change `printf("failed\n");` to `lastError = GetLastError(); printf("error %d", lastError);` Also end with `SymCleanup(process)` (but it won't change things in this case) – Barmak Shemirani Oct 20 '21 at 00:53
  • I am getting results some of the time but I am getting behavior that would be desribed as a memory issue. Erratic results. It might be my computer but I switched to StackWalk64 and the memory issues went away. – eat_a_lemon Oct 20 '21 at 14:52
  • I think it is because I am not using Visual Studio and I needed to add some compile options to the compile command. I am going to post my own answer soon. – eat_a_lemon Oct 20 '21 at 14:57

1 Answers1

2

I was using cl.exe in my Makefile without the /Zi compile option. When I added /Zi the line numbers and filenames appeared.

eat_a_lemon
  • 3,158
  • 11
  • 34
  • 50