Unwind cycle detection false positive mixing frame view and backtrace
Carlos Sánchez de La Lama via Gdb <[email protected]>
| Newsgroups | gmane.comp.gdb.devel |
|---|---|
| Message-ID | <CA+KcR8C+_YN8hJfU6jfX-RpOL=J3fgy5O7z8Tq8_xKN4gGL18g@mail.gmail.com> |
I have found a problem which cases a false positive detection of cycles when "frame view" specifier is used in combination with "bt"; the consequence is affected frames are (wrongly) reported as impossible to be further traversed. To reproduce, I use a debug build of GNU hello-2.12 hello-2.12$ ./configure && make CFLAGS="-g -O0" Now I debug that with gdb (master branch, commit 53ff349e553fa9fc446a8711e37fd252282b088b) -------- CODE BEGIN -------- $ gdb ./hello [...] (gdb) break getopt_long Breakpoint 1 at 0x2480 (gdb) run Starting program: /home/carlossanchez/src/hello-2.12/hello Breakpoint 1, 0x00007ffff7eb05d0 in getopt_long () from /lib/x86_64-linux-gnu/libc.so.6 (gdb) bt #0 0x00007ffff7eb05d0 in getopt_long () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x0000555555556a8d in parse_options (argc=1, argv=0x7fffffffde98, greeting_msg=0x7fffffffdd68) at src/hello.c:99 #2 0x0000555555556bf9 in main (argc=1, argv=0x7fffffffde98) at src/hello.c:157 (gdb) info frame 1 Stack frame at 0x7fffffffdd50: rip = 0x555555556a8d in parse_options (src/hello.c:99); saved rip = 0x555555556bf9 called by frame at 0x7fffffffddb0, caller of frame at 0x7fffffffdcf0 source language c. Arglist at 0x7fffffffdd40, args: argc=1, argv=0x7fffffffde98, greeting_msg=0x7fffffffdd68 Locals at 0x7fffffffdd40, Previous frame's sp is 0x7fffffffdd50 Saved registers: rbx at 0x7fffffffdd28, rbp at 0x7fffffffdd40, r12 at 0x7fffffffdd30, r13 at 0x7fffffffdd38, rip at 0x7fffffffdd48 (gdb) info frame view 0x7fffffffdd50 0x555555556a8d Stack frame at 0x7fffffffdd50: rip = 0x555555556a8d in parse_options (src/hello.c:99); saved rip = <not saved> Outermost frame: previous frame identical to this frame (corrupt stack?) source language c. Arglist at 0x7fffffffdd40, args: argc=1, argv=0x7fffffffde98, greeting_msg=0x7fffffffdd68 Locals at 0x7fffffffdd40, Previous frame's sp is 0x7fffffffdd50 Saved registers: rbx at 0x7fffffffdd28, rbp at 0x7fffffffdd40, r12 at 0x7fffffffdd30, r13 at 0x7fffffffdd38, rip at 0x7fffffffdd48 -------- CODE END -------- The frame at 0x7fffffffdd50 gets reported ad being called out of nowhere (corrupt stack) when inspected with "frame wiew". Now I try doing the "frame view" first: -------- CODE BEGIN -------- $ gdb ./hello [...] (gdb) break getopt_long Breakpoint 1 at 0x2480 (gdb) run Starting program: /home/carlossanchez/src/hello-2.12/hello Breakpoint 1, 0x00007ffff7eb05d0 in getopt_long () from /lib/x86_64-linux-gnu/libc.so.6 (gdb) info frame view 0x7fffffffdd50 0x555555556a8d Stack frame at 0x7fffffffdd50: rip = 0x555555556a8d in parse_options (src/hello.c:99); saved rip = 0x555555556bf9 called by frame at 0x7fffffffddb0 source language c. Arglist at 0x7fffffffdd40, args: argc=1, argv=0x7fffffffde98, greeting_msg=0x7fffffffdd68 Locals at 0x7fffffffdd40, Previous frame's sp is 0x7fffffffdd50 Saved registers: rbx at 0x7fffffffdd28, rbp at 0x7fffffffdd40, r12 at 0x7fffffffdd30, r13 at 0x7fffffffdd38, rip at 0x7fffffffdd48 (gdb) bt #0 0x00007ffff7eb05d0 in getopt_long () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x0000555555556a8d in parse_options (argc=1, argv=0x7fffffffde98, greeting_msg=0x7fffffffdd68) at src/hello.c:99 Backtrace stopped: previous frame identical to this frame (corrupt stack?) -------- CODE END -------- Inspecting with "frame view" works, but now the backtrace stops prematurely! I have debugged gdb itself and found the problem to be in gdb/frame.c:2250. frame_stash_add is called to detect cycles in the frame sequence: if the same frame id is already in the stash, it means we are traversing the same frame twice (we found a cycle) and the stack is corrupt. When calling "bt" twice, the higher level dwarf2 frame cache prevents creation of new frame_info structs, so frame_stash_add is not really called twice and the problem is not observed. But when mixing "frame view" and "bt", different frame_info structures which refer to the same frame in memory are created. As the hash used by frame_stash_add is based on CFA and PC (so based on the real frame in memory, and not on the frame_info pointer) a cycle is wrongly detected. I was going to create a bug report, but I want to hear comments on the expected behaviour here: Option 1) this works as expected, you are not supposed to "frame view" frames which are on your current backtrace Option 2) make "frame view" reset the frame stash before and after running Option 3) condition the frame traverser to skip the cycle detection when using "frame view" Suggestions? Carlos