Hi,
git://git.jankratochvil.net/elfutils
branch jankratochvil/unwind
git clone -b jankratochvil/unwind
git://git.jankratochvil.net/elfutils elfutils-unwind;cd
elfutils-unwind;autoreconf -f -i;./configure --enable-maintainer-mode;make;cd tests;make
backtrace backtrace-child;LD_LIBRARY_PATH=../backends:../libdw:../libelf ./backtrace
OR
git remote add jankratochvilgit
git://git.jankratochvil.net/elfutils; git fetch
jankratochvilgit; git checkout jankratochvil/unwind
TID 20043:
# 0 0x7fed6e187880 (null)
# 1 0x7fed6e187c86 - 1 sigusr2
# 2 0x7fed6d9c5300 __restore_rt
# 3 0x7fed6e187d80 jmp
# 4 0x7fed6e187d0a - 1 stdarg
# 5 0x7fed6e187d70 - 1 backtracegen
# 6 0x7fed6e187d79 - 1 start
# 7 0x7fed6dd4ed90 - 1 start_thread
# 8 0x7fed6da8019d - 1 clone
TID 20042:
# 0 0x7fed6dd563cb raise
# 1 0x7fed6e187a9d - 1 main
# 2 0x7fed6d9b069d - 1 __libc_start_main
# 3 0x7fed6e187b3d - 1 _start
It is 1.2MB due to non-x86* core file testcases, I can push it as
jankratochvil/unwind to the main repo upon request.
User API is to unwind PC, nothing more. It requires CFI now, no per-arch
frames unwinding possible now. Live PIDs and core files are supported.
Archs supported: i386 x86_64 ppc ppc64 s390 s390x (+planned arm)
New testcase: run-backtrace.sh
Going to post along some independent elfutils extensions (s390{,x} core notes,
ppc64 .opd support) and fixes (bias adjustments, uninitialized data).
I have some issues with the API, what is libdw vs. libdwfl etc. I have put
now mostly all to libdwfl, should I really keep it there? There is some mess
with libdw/cfi.h where are:
Dwarf_Frame_State -> Dwarf_Frame_State_Thread -> Dwarf_Frame_State_Process
User can see only opaque Dwarf_Frame_State. Current API for it follows.
Maybe there were already some ideas for elfutils unwinding API, I have no
problem to refactor it to some completely different model.
# /* Get innermost frame of first thread of live process PID. Returns NULL on
# failure. */
# extern Dwarf_Frame_State *dwfl_frame_state_pid (Dwfl *dwfl, pid_t pid);
#
# /* Get innermost frame of first thread of core file COREFILE. Returns NULL on
# failure. */
# extern Dwarf_Frame_State *dwfl_frame_state_core (Dwfl *dwfl,
# const char *corefile);
#
# /* Return TRUE and update *STATEP for the unwound frame for successful unwind.
# Return TRUE and set *STATEP to NULL for the outermost frame. Return FALSE
# (and call __libdwfl_seterrno) otherwise. */
# extern bool dwfl_frame_unwind (Dwarf_Frame_State **statep);
#
# /* Get return address register value for frame. Return TRUE if *PC set and
# optionally *MINUSONE is also set, if MINUSONE is not NULL. Return FALSE
# (and call __libdw_seterrno) otherwise. *MINUSONE is TRUE for normal calls
# where *PC should be decremented by one to get the call instruction, it is
# FALSE if this frame was interrupted by a signal handler. */
# extern bool dwfl_frame_state_pc (Dwarf_Frame_State *state, Dwarf_Addr *pc,
# bool *minusone);
#
# /* Get innermost frame of the next thread from STATE. STATE can be any frame
# of (the previous) thread. */
# extern Dwarf_Frame_State *dwfl_frame_thread_next (Dwarf_Frame_State *state);
#
# /* Get Task ID of the thread of STATE. This is PID for the thread started by
# function main and gettid () for the other threads. */
# extern pid_t dwfl_frame_tid_get (Dwarf_Frame_State *state);
Sample code for unwinding (without error checks) is:
# Initialize Dwfl *dwfl, including reporting PID process or a core file. This
# is a bit unclear to me whether dwfl_frame_state_pid / dwfl_frame_state_core
# should report it themselves or not. See also tests/backtrace.c report_core.
#
# Dwarf_Frame_State *state = dwfl_frame_state_pid (dwfl, pid);
# OR
# Dwarf_Frame_State *state = dwfl_frame_state_core (dwfl, corefile);
# do
# {
# Dwarf_Frame_State *thread = state;
# pid_t tid = dwfl_frame_tid_get (thread);
# # TID for printing.
# while (state)
# {
# Dwarf_Addr pc;
# bool minusone;
# dwfl_frame_state_pc (state, &pc, &minusone);
# Dwarf_Addr pc_adjusted = pc - (minusone ? 1 : 0);
# ### Print PC and dwfl_module_addrname (PC_ADJUSTED).
# dwfl_frame_unwind (&state);
# }
# state = dwfl_frame_thread_next (thread);
# }
# while (state);
The initial reporting is a bit problematic for me. For example
src/stack -e ~/t/sleep6000-32 --core=$HOME/t/sleep6000-32.core
# 1 0xf75e64f0 - 1 __nanosleep
# 2 0xf75e632f - 1 sleep
# 3 0x80483d9 - 1 (null)
^^^^^^ main is not resolved, we need to use:
src/stack --core=$HOME/t/sleep6000-32.core -e ~/t/sleep6000-32
- as otherwise dwfl_addrmodule will find the one from a core file without
symbols first which dwfl_module_addrname will not work for.
Still currently does not work after uncommenting run-backtrace.sh line:
# mytestrun ./backtrace ./$child ./$core
./backtrace ./backtrace-child ./core.20860
0x7fa68624b000 0x7fa68644d000 [pie]
0x7fffa49ff000 0x7fffa4a00000 linux-vdso.so.1
0x7fa685e0b000 0x7fa686027000 libpthread.so.0
0x7fa685a53000 0x7fa685e0b000 libc.so.6
0x7fa686027000 0x7fa68624b000 ld-linux-x86-64.so.2
0x200000 0x401558 <executable>
TID 20860:
# 0 0x7fa685e14080 pthread_join
# 1 0x7fa68624beba - 1 (null)
No DWARF information found
Because <executable> which is PIE is reported with different VMA than [pie].
I had this case working in the past but apparently the bias adjustments are
still not right, I will try more.
Thanks,
Jan