The coredumpctl utility displays a stack trace of the program when the coredump has been created.

For example, on a firefox coredump:

Stack trace of thread 14469:
#0  0x00007f0ac652d3bd pthread_cond_wait@@GLIBC_2.3.2 (libpthread.so.0)
#1  0x0000560f2ab95488 _ZN7mozilla6detail21ConditionVariableImpl4waitERNS0_9MutexImplE (firefox)
#2  0x0000560f2ab95646 _ZN7mozilla6detail21ConditionVariableImpl8wait_forERNS0_9MutexImplERKNS_16BaseTimeDurationINS_27TimeDurati>
#3  0x00007f0aba9799f9 n/a (libxul.so)
#4  0x00007f0aba96eb9a n/a (libxul.so)
#5  0x00007f0ac652708c start_thread (libpthread.so.0)
#6  0x00007f0ac5abce7f __clone (libc.so.6)

Considering that this is C code, and thus it is compiled, the symbols are not directly embedded in the binary file: so how is this possible?
And also, how is this done in practice by readelf?

(My guess, this is related to the symbol table embedded in the ELF file)


As you correctly guess, the symbols come from the symbol information embedded in the ELF files. Some symbol information is needed to be able to do dynamic linking, even if the full symbol table is not present.

As far as the actual stacktrace is concerned, when a function is called the place for the cpu to return to is saved. For cpus like the x86 it is pushed on a stack. For RISC machines it is typically put into a register. If the function wants to call any other functions (i.e. it is not a leaf function) then this register is pushed onto a stack. The stacktrace code finds these addresses on the stack, looks up the nearest address in the symbols which is before it and reports it. Some stacktrace code prints both the symbol name and how far away it is, which can give you more confidence in how accurate it is. For example if the symbol is only 40 bytes before the return address then one has much more confidence that it is in that code, compared to it being 40,000 bytes before. In the latter case one might suspect that the return address points into a different function but that function doesn't have an entry in the symbol table.

Lots of things can make this inaccurate. If a compiler inlines say function a into function b, then you might be in function a but the stacktrace will report you are in b.

If the compiler does "Tail Call Optimization" where function a ends with something like return b(); and function c calls function a, you might expect the trace to show c->a->b, but you will only see c->b. This can be confusing if you look at the source for c and you see it never calls b directly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.