bombela / backward-cpp

A beautiful stack trace pretty printer for C++
MIT License
3.73k stars 471 forks source link

Does macos support ultimate stack trace ? #231

Closed Aincvy closed 3 years ago

Aincvy commented 3 years ago

In my case, the output is

Stack trace (most recent call last):
#4    Object "sight", at 0x1023aff0b, in main + 123
#3    Object "sight", at 0x1023c91bd, in sight::showMainWindow() + 653
#2    Object "sight", at 0x1023c8ba4, in sight::mainWindowFrame(sight::UIStatus&) + 20
#1    Object "sight", at 0x1023c8cc4, in sight::(anonymous namespace)::showMainMenuBar(sight::UIStatus&) + 228
#0    Object "sight", at 0x1023c9ef3, in sight::(anonymous namespace)::showMainCustomMenu() + 115
fish: './sight' terminated by signal SIGSEGV (Address boundary error)

I have installed libdwarf, and I have added #define BACKWARD_HAS_DWARF 1, but nothing works.

I have read some part of source code, it seems doesn't work on mac, does it ?

Lecrapouille commented 3 years ago

@Aincvy I hardly develop on Mac OS X but yes it working fine from my memories. When this kind of output is displayed this means that backward-cpp has not all information => you probably have missed -g -O2. Did you add compilation flags such as (the one which works on OSX with libs installed from homebrew):

g++ ... -g -O2 -DBACKWARD_HAS_DW=1 backward.cpp ... *.cpp -o a.out ... -ldw
Aincvy commented 3 years ago

I have tried to do something, but nothing works.

Here is my code.

// program.cpp
#define BACKWARD_HAS_BFD 1       // with or without this line
#define BACKWARD_HAS_DW 1
#include "backward.hpp"
# backward-cpp
target_include_directories(sight PRIVATE dependencies/backward-cpp)

I expect this can made some error, but it didn't.Because I didn't add the dynamic library. Then, I check the code, I think all of BACKWARD_HAS_XXX macros only works in Linux. Because the code about them only works if macro BACKWARD_SYSTEM_LINUX is defined.

https://github.com/bombela/backward-cpp/blob/3bb9240cb15459768adb3e7d963a20e1523a6294/backward.hpp#L187-L200 https://github.com/bombela/backward-cpp/blob/3bb9240cb15459768adb3e7d963a20e1523a6294/backward.hpp#L469-L501 https://github.com/bombela/backward-cpp/blob/3bb9240cb15459768adb3e7d963a20e1523a6294/backward.hpp#L3473-L3555

Maybe I am wrong at something.

And I have tried -g -O2 options, if I do not add them, it works like my first comment, if I added, then it's output like below.

Stack trace (most recent call last):
#2    Object "libsystem_platform.dylib", at 0x7fff675495fc, in _sigtramp + 28
#1    Object "sight", at 0x10cf3bfcd, in backward::SignalHandling::sig_handler(int, __siginfo*, void*) + 13
#0    Object "sight", at 0x10cf3c03c, in backward::SignalHandling::handleSignal(int, __siginfo*, void*) + 76
Stack trace (most recent call last):
#2    Object "libsystem_platform.dylib", at 0x7fff675495fc, in _sigtramp + 28
#1    Object "sight", at 0x10cf3bfcd, in backward::SignalHandling::sig_handler(int, __siginfo*, void*) + 13
#0    Object "sight", at 0x10cf3c03c, in backward::SignalHandling::handleSignal(int, __siginfo*, void*) + 76
Stack trace (most recent call last):
#2    Object "libsystem_platform.dylib", at 0x7fff675495fc, in _sigtramp + 28
#1    Object "sight", at 0x10cf3bfcd, in backward::SignalHandling::sig_handler(int, __siginfo*, void*) + 13
#0    Object "sight", at 0x10cf3c03c, in backward::SignalHandling::handleSignal(int, __siginfo*, void*) + 76
and more...

Here is the code.

# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_BUILD_TYPE "Debug")

add_executable(sight program.cpp)

#target_compile_options(
#        sight PRIVATE
#        -g
#        -O2
#)

Others info

Notice: I have tried them, but for now, I didn't add any of them to my project.

libdwarf

I get the code from https://git.code.sf.net/p/libdwarf/code. After a little change of CMakeLists.txt, I compiled success and I got two files libdwarf.a, libdwarf.dylib . I run command sudo make install, the library files was installed fine, but the header files not, so I copied it to /usr/local/include manually.

libelf

Use command brew install libelf. And I have tried brew install elfutils. Homebrew tells me elfutils: Linux is required for this software.

binutils

brew install binutils. It seems nothing different.

dw

I did not find this library.

Sorry about my poor English, and thank you for your response.

Lecrapouille commented 3 years ago

I'm personally never using Cmake. Can you try on a single file hello-world application and just testing on the g++ command I gave you. I'm using mine which is old but worked with OS X https://github.com/Lecrapouille/backward-cpp

Aincvy commented 3 years ago

No offence, but I think you're wrong.

I have checked the code again. It doesn't print code snippet on macos. Here it is.

// Line 3139 in your fork.   Line 3488 in this repo.

ResolvedTrace resolve(ResolvedTrace trace) {
  // parse:
  // <n>  <file>  <addr>  <mangled-name> + <offset>
  char* filename = _symbols[trace.idx];
  // printf("resolve:: %s\n", filename);    

  // skip "<n>  "
  while(*filename && *filename != ' ') filename++;
  while(*filename == ' ') filename++;

  // find start of <mangled-name> from end (<file> may contain a space)
  char* p = filename + strlen(filename) - 1;
  // skip to start of " + <offset>"
  while(p > filename && *p != ' ') p--;
  while(p > filename && *p == ' ') p--;
  while(p > filename && *p != ' ') p--;
  while(p > filename && *p == ' ') p--;
  char *funcname_end = p + 1;

  // skip to start of "<manged-name>"
  while(p > filename && *p != ' ') p--;
  char *funcname = p + 1;

  // skip to start of "  <addr>  "
  while(p > filename && *p == ' ') p--;
  while(p > filename && *p != ' ') p--;
  while(p > filename && *p == ' ') p--;

  // skip "<file>", handling the case where it contains a
  char* filename_end = p + 1;
  if (p == filename) {
    // something went wrong, give up
    filename_end = filename + strlen(filename);
    funcname = filename_end;
  }
  trace.object_filename.assign(filename, filename_end); // ok even if filename_end is the ending \0 (then we assign entire string)

  if (*funcname) { // if it's not end of string
    *funcname_end = '\0';

    trace.object_function = this->demangle(funcname);
    trace.object_function += " ";
    trace.object_function += (funcname_end + 1);
    trace.source.function = trace.object_function; // we cannot do better.             // Here !!!
  }

 // Test code from Aincvy.
  if (trace.idx == 0) {
    printf("here is end of line 0.\n"  );
    trace.source.filename = "test.cpp";
    trace.source.line = 9;
    trace.source.col = 6;
  }
  //  End of test code from Aincvy.

  return trace;
}

It seems cannot get the source code's filename, line and col.

And in my case, this line will enter an endless loop. https://github.com/bombela/backward-cpp/blob/3bb9240cb15459768adb3e7d963a20e1523a6294/backward.hpp#L4266-L4267

Additional

Here is my test file.

// filename: test.cpp

//
// Created by Aincvy(aincvy@gmail.com) on 2021/8/17.
//

#include "backward.hpp"

void test1(){
    int *p = nullptr;
    *p = 1;
}

void test2(){
    test1();
}

void test3(){
    test2();
}

void test4(){
    test3();
}

void test5(){
    test4();
}

int main(int argc, char* argv[]){
    backward::SignalHandling sh;

    test5();
    return 0;
}

Here is compile command: g++ --std=c++17 -I. -g -O0 test.cpp -o a.out Here is the output.

Stack trace (most recent call last):
#5    Object "a.out", at 0x107f7b705, in main + 69
#4    Object "a.out", at 0x107f7b6b8, in test5() + 8
#3    Object "a.out", at 0x107f7b6a8, in test4() + 8
#2    Object "a.out", at 0x107f7b698, in test3() + 8
#1    Object "a.out", at 0x107f7b688, in test2() + 8
here is end of line 0.
#0    Source "test.cpp", line 9, in test1() + 16 [0x107f7b670]
          7: void test1(){
          8:     int *p = nullptr;
      >   9:     *p = 1;
         10: }
         11:
         12: void test2(){

It outputs code snippet because of my test code.

Others test command.

g++ --std=c++17 -I. -g -O1 test.cpp -o a.out
g++ --std=c++17 -I. -g -O2 test.cpp -o a.out
g++ --std=c++17 -I. -g -O1 -DBACKWARD_HAS_DW=1 test.cpp -o a.out
g++ --std=c++17 -I. -g -O2 -DBACKWARD_HAS_DW=1 test.cpp -o a.out

Again, with or without -DBACKWARD_HAS_DW=1 is no different.

bombela commented 3 years ago

backward::SignalHandling sh must live as long as the process itself. It should be leaked.

SeeRich commented 1 year ago

What was the resolution to this? I am having the same issue.

bear24rw commented 1 year ago

I think all of BACKWARD_HAS_XXX macros only works in Linux. Because the code about them only works if macro BACKWARD_SYSTEM_LINUX is defined.

I have the same issue and came to the same conclusion before finding this issue. Would love to know if there is planned support for detailed tracebacks on macOS!