1

I'm trying to add simple crash logging to my C++ application for Mac OS and Linux. I'm not happy with backtrace_symbols output. I'd like to take whatever backtrace() returns and build stack trace (with symbolic names) manually. How to do it? I couldn't find a single example, or even explanation of what exactly it is that backtrace() returns.

Upd: found this code snippet, but it doesn't compile on OS X.

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
  • @n.m.: I don't think it even has the ability to improve. Jokes aside, I'd like to get a list of mangled function names without having to parse strings, for starters. – Violet Giraffe Jan 22 '14 at 12:53
  • @n.m.: also, I don't see a way to see which thread has actually caused the signal, but I guess that's a problem of `backtrace` itself. – Violet Giraffe Jan 22 '14 at 13:14
  • "Don't want to parse strings" is a bit like "don't want to add numbers". Parsing strings is what programmers do, there's no getting around it. – n. m. could be an AI Jan 22 '14 at 13:55
  • 1
    @n.m.: awesome. Let's get some data, compile into a human-readable string, then forget we had that data in the first place and parse the string to get our pieces of info back. Sounds totally like what programmers do all the time. – Violet Giraffe Jan 22 '14 at 13:59
  • The thread that crashes (invalid opcode, bus error, segmentation error...) receives the signal. It's not a problem of `backtrace`. – n. m. could be an AI Jan 22 '14 at 14:04
  • Yes, in this world programmers do that all the time. Perhaps in some ideal far away world they don't, but I hadn't got a chance to visit one yet. – n. m. could be an AI Jan 22 '14 at 14:06
  • @n.m.: I don't believe so. From what I gather, signals are process-wide, and any arbitrary thread can be called to execute signal handling. The first in line is the main thread. Which makes the stack trace much less useful - all the threads' traces seem to be dumped, but you can't tell which one has actually failed. See http://stackoverflow.com/questions/11679568/signal-handling-with-multiple-threads-in-linux – Violet Giraffe Jan 22 '14 at 14:08
  • "any arbitrary thread can be called to execute signal handling" --- that's the case with asynchronous signals (ones that you send from another process with "kill"). Synchronous signals are delivered to the thread that caused them. – n. m. could be an AI Jan 22 '14 at 14:27
  • @n.m.: Thanks, I didn't realize that. So I can assume that `SIGSEGV` will arrive to a thread that caused the fault? – Violet Giraffe Jan 22 '14 at 14:33
  • Yes, see e.g. [here](http://stackoverflow.com/questions/4451478/posix-threads-and-sigsegv). – n. m. could be an AI Jan 22 '14 at 14:42

2 Answers2

2

libunwind has unw_get_proc_name function that will give you the mangled function name for a stack frame. The documentation claims that unw_get_proc_name is safe in a signal handler. According to this, backtrace_symbols uses malloc and is therefore not safe to use in a POSIX signal handler.

I don't know how to call that with whatever backtrace returns, so you'd probably need to use libunwind for that aswell.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Thanks, I was looking at libunwind. I got a hint that it does something architecture-specific and will not work on ARM, and I'm trying to write POSIX-compliant cross-platform code first, if I can. – Violet Giraffe Jan 22 '14 at 14:50
  • I don't know if the project is officially supported on arm/osx, but there is a copy of the source hosted on [apple.com](http://www.opensource.apple.com/source/libunwind/) so I would assume it's used by people and they provide patches. I'm sure the situation is similar on arm. – eerorika Jan 22 '14 at 15:17
1

Looking at man page for backtrace(), I see that the backtrace returns pointer to an array containing bunch of addresses.

The backtrace_symbols() converts those addresses into symbols, as it sees it if there are debug symbols. Otherwise you get an address.

Having said that, it makes no sense to not use backtrace_symbols(). If you do not like the output, feel free to modify it, but you are not going to get more useful backtrace information.

In the example you found, they are mimicking backtrace_symbols() in a bad way. Also, mind the first comment :

A hacky replacement for backtrace_symbols in glibc
BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • Modifying output means parsing the string (not to mention allocating a lot of new strings!), and there's no clear delimiter, as far as I can see. But looks like I'll have to parse it, after all. – Violet Giraffe Jan 22 '14 at 12:37
  • I did mind the comment. Don't care how hacky it is if it would work. But half the includes needed there don't even exist on my OS X 10.9. – Violet Giraffe Jan 22 '14 at 12:38
  • @VioletGiraffe The output of `backtrace_symbols()` is array of c-strings, but I do not mean parsing c strings. Create `std::vector>` and parse that instead. Should be easy to do. – BЈовић Jan 22 '14 at 12:40