-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Objective C support #6
Comments
Thanks! Are any of the patches good candidates for upstreaming to GDB? If not, I'll be glad to look at them. |
Good question. I'm not sure. We've been basing from darchons lately, since it seems a better Android starting point than the pure upstream gdb version. Most of the changes are for Objective C support, along with a few miscellaneous Android and/or ARM bug fixes. The Objective-C is work in progress, and may have some dependencies on our Clang branch. A summary of the non-Objective C items:
|
…story). Before the changes starting at http://sourceware.org/ml/gdb-patches/2012-08/msg00020.html, the 'set listsize' command only accepted "0" as special value, meaning "unlimited". The testsuite actually tried "set listsize -1" and expected that to mean unlimited too. If you tried testing list.exp at the time of that patch above, you'd get: (gdb) PASS: gdb.base/list.exp: list line 10 with listsize 100 set listsize 0 (gdb) PASS: gdb.base/list.exp: setting listsize to 0 #6 show listsize Number of source lines gdb will list by default is unlimited. (gdb) PASS: gdb.base/list.exp: show listsize unlimited #6 list 1 1 #include "list0.h" 2 ... 42 /* Not used for anything */ 43 } (gdb) PASS: gdb.base/list.exp: listsize of 0 suppresses output set listsize -1 integer 4294967295 out of range (gdb) PASS: gdb.base/list.exp: setting listsize to -1 #7 show listsize Number of source lines gdb will list by default is unlimited. (gdb) PASS: gdb.base/list.exp: show listsize unlimited #7 list 1 1 #include "list0.h" Notice that "set listsize -1" actually failed with "integer 4294967295 out of range", but we issued a PASS anyway. (and notice how the "listsize of 0 suppresses output" test passes bogusly too.) This patch fixes that testsuite problem in the obvious way. gdb/testsuite/ 2013-03-28 Pedro Alves <palves@redhat.com> * gdb.base/list.exp (set_listsize): Use gdb_test_no_output for "set listsize".
PR tui/14880 shows a reproducer that triggers this assertion: int value_available_contents_eq (const struct value *val1, int offset1, const struct value *val2, int offset2, int length) { int idx1 = 0, idx2 = 0; /* This routine is used by printing routines, where we should already have read the value. Note that we only know whether a value chunk is available if we've tried to read it. */ gdb_assert (!val1->lazy && !val2->lazy); (top-gdb) bt #0 internal_error (file=0x88a26c "../../src/gdb/value.c", line=549, string=0x88a220 "%s: Assertion `%s' failed.") at ../../src/gdb/utils.c:844 #1 0x000000000057b9cd in value_available_contents_eq (val1=0x10fa900, offset1=0, val2=0x10f9e10, offset2=0, length=8) at ../../src/gdb/value.c:549 #2 0x00000000004fd756 in tui_get_register (frame=0xd5c430, data=0x109a548, regnum=0, changedp=0x109a560) at ../../src/gdb/tui/tui-regs.c:736 #3 0x00000000004fd111 in tui_check_register_values (frame=0xd5c430) at ../../src/gdb/tui/tui-regs.c:521 #4 0x0000000000501884 in tui_check_data_values (frame=0xd5c430) at ../../src/gdb/tui/tui-windata.c:234 #5 0x00000000004f976f in tui_selected_frame_level_changed_hook (level=1) at ../../src/gdb/tui/tui-hooks.c:222 #6 0x00000000006f0681 in select_frame (fi=0xd5c430) at ../../src/gdb/frame.c:1490 #7 0x00000000005dd94b in up_silently_base (count_exp=0x0) at ../../src/gdb/stack.c:2268 #8 0x00000000005dd985 in up_command (count_exp=0x0, from_tty=1) at ../../src/gdb/stack.c:2280 #9 0x00000000004dc5cf in do_cfunc (c=0xd3f720, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:113 #10 0x00000000004df664 in cmd_func (cmd=0xd3f720, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:1888 #11 0x00000000006e43e1 in execute_command (p=0xc7e6c2 "", from_tty=1) at ../../src/gdb/top.c:489 The fix is to fetch the value before comparing the contents. The comment additions to value.h explain why it can't be value_available_contents_eq itself that fetches the contents. Tested on x86_64 Fedora 17. gdb/ 2013-06-28 Pedro Alves <palves@redhat.com> PR tui/14880 * tui/tui-regs.c (tui_get_register): Fetch register value contents before checking whether they're available. * value.c (value_available_contents_eq): Change comment. * value.h (value_available_contents_eq): Expand comment.
…story). Before the changes starting at <http://sourceware.org/ml/gdb-patches/2012-08/msg00020.html>, the 'set listsize' command only accepted "0" as special value, meaning "unlimited". The testsuite actually tried "set listsize -1" and expected that to mean unlimited too. If you tried testing list.exp at the time of that patch above, you'd get: (gdb) PASS: gdb.base/list.exp: list line 10 with listsize 100 set listsize 0 (gdb) PASS: gdb.base/list.exp: setting listsize to 0 #6 show listsize Number of source lines gdb will list by default is unlimited. (gdb) PASS: gdb.base/list.exp: show listsize unlimited #6 list 1 1 #include "list0.h" 2 ... 42 /* Not used for anything */ 43 } (gdb) PASS: gdb.base/list.exp: listsize of 0 suppresses output set listsize -1 integer 4294967295 out of range (gdb) PASS: gdb.base/list.exp: setting listsize to -1 #7 show listsize Number of source lines gdb will list by default is unlimited. (gdb) PASS: gdb.base/list.exp: show listsize unlimited #7 list 1 1 #include "list0.h" Notice that "set listsize -1" actually failed with "integer 4294967295 out of range", but we issued a PASS anyway. (and notice how the "listsize of 0 suppresses output" test passes bogusly too.) This patch fixes that testsuite problem in the obvious way. gdb/testsuite/ 2013-03-28 Pedro Alves <palves@redhat.com> * gdb.base/list.exp (set_listsize): Use gdb_test_no_output for "set listsize".
This patch does the following: - Puts the startfunc and "Sleep func" info on the same line; - Renames "Sleep func" into "sleepfunc" to be consistent with "startfunc" - Avoids the use of a '-' as a separate before the "sleepfunc" output, because the '-' looks odd and out of place when the "startfunc" field is not printed (ti.ti_startfunc is nul). - Use a '=' instead of ':' and avoids the space between the name of the value and its value, mostly to help group the value with its name. For the record, this is how the new outout now looks like: (gdb) maintenance info sol-threads user thread #1, lwp 1, (active) system thread #2, lwp 2, (active) system thread #3, lwp 0, (asleep) sleepfunc=0xff32d9e0 user thread #4, lwp 4, (asleep) startfunc=[...].task_wrapper sleepfunc=0xff3290f0 system thread #5, lwp 7, (active) startfunc=_co_timerset user thread #6, lwp 8, (active) startfunc=[...].task_wrapper gdb/ChangeLog: * sol-thread.c (info_cb): Rework the output of the "maintenance info sol-threads" command a bit.
PR tui/14880 shows a reproducer that triggers this assertion: int value_available_contents_eq (const struct value *val1, int offset1, const struct value *val2, int offset2, int length) { int idx1 = 0, idx2 = 0; /* This routine is used by printing routines, where we should already have read the value. Note that we only know whether a value chunk is available if we've tried to read it. */ gdb_assert (!val1->lazy && !val2->lazy); (top-gdb) bt #0 internal_error (file=0x88a26c "../../src/gdb/value.c", line=549, string=0x88a220 "%s: Assertion `%s' failed.") at ../../src/gdb/utils.c:844 #1 0x000000000057b9cd in value_available_contents_eq (val1=0x10fa900, offset1=0, val2=0x10f9e10, offset2=0, length=8) at ../../src/gdb/value.c:549 #2 0x00000000004fd756 in tui_get_register (frame=0xd5c430, data=0x109a548, regnum=0, changedp=0x109a560) at ../../src/gdb/tui/tui-regs.c:736 #3 0x00000000004fd111 in tui_check_register_values (frame=0xd5c430) at ../../src/gdb/tui/tui-regs.c:521 #4 0x0000000000501884 in tui_check_data_values (frame=0xd5c430) at ../../src/gdb/tui/tui-windata.c:234 #5 0x00000000004f976f in tui_selected_frame_level_changed_hook (level=1) at ../../src/gdb/tui/tui-hooks.c:222 #6 0x00000000006f0681 in select_frame (fi=0xd5c430) at ../../src/gdb/frame.c:1490 #7 0x00000000005dd94b in up_silently_base (count_exp=0x0) at ../../src/gdb/stack.c:2268 #8 0x00000000005dd985 in up_command (count_exp=0x0, from_tty=1) at ../../src/gdb/stack.c:2280 #9 0x00000000004dc5cf in do_cfunc (c=0xd3f720, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:113 #10 0x00000000004df664 in cmd_func (cmd=0xd3f720, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:1888 #11 0x00000000006e43e1 in execute_command (p=0xc7e6c2 "", from_tty=1) at ../../src/gdb/top.c:489 The fix is to fetch the value before comparing the contents. The comment additions to value.h explain why it can't be value_available_contents_eq itself that fetches the contents. Tested on x86_64 Fedora 17. gdb/ 2013-06-28 Pedro Alves <palves@redhat.com> PR tui/14880 * tui/tui-regs.c (tui_get_register): Fetch register value contents before checking whether they're available. * value.c (value_available_contents_eq): Change comment. * value.h (value_available_contents_eq): Expand comment.
In entry-values.exp, we have a test where the entry value of 'j' is unavailable, so it is expected that printing j@entry yields "<unavailable>". However, the actual output is: (gdb) frame #0 0x0000000000400540 in foo (i=0, i@entry=2, j=2, j@entry=<error reading variable: Cannot access memory at address 0x6009e8>) The error is thrown here: #0 throw_it (reason=RETURN_ERROR, error=MEMORY_ERROR, fmt=0x8cd550 "Cannot access memory at address %s", ap=0x7fffffffc8e8) at ../../src/gdb/exceptions.c:373 #1 0x00000000005e2f9c in throw_error (error=MEMORY_ERROR, fmt=0x8cd550 "Cannot access memory at address %s") at ../../src/gdb/exceptions.c:422 #2 0x0000000000673a5f in memory_error (status=5, memaddr=6293992) at ../../src/gdb/corefile.c:204 #3 0x0000000000673aea in read_memory (memaddr=6293992, myaddr=0x7fffffffca60 "\200\316\377\377\377\177", len=4) at ../../src/gdb/corefile.c:223 #4 0x00000000006784d1 in dwarf_expr_read_mem (baton=0x7fffffffcd50, buf=0x7fffffffca60 "\200\316\377\377\377\177", addr=6293992, len=4) at ../../src/gdb/dwarf2loc.c:334 #5 0x000000000067645e in execute_stack_op (ctx=0x1409480, op_ptr=0x7fffffffce87 "\237<\005@", op_end=0x7fffffffce88 "<\005@") at ../../src/gdb/dwarf2expr.c:1045 #6 0x0000000000674e29 in dwarf_expr_eval (ctx=0x1409480, addr=0x7fffffffce80 "\003\350\t`", len=8) at ../../src/gdb/dwarf2expr.c:364 #7 0x000000000067c5b2 in dwarf2_evaluate_loc_desc_full (type=0x10876d0, frame=0xd8ecc0, data=0x7fffffffce80 "\003\350\t`", size=8, per_cu=0xf24c40, byte_offset=0) at ../../src/gdb/dwarf2loc.c:2236 #8 0x000000000067cc65 in dwarf2_evaluate_loc_desc (type=0x10876d0, frame=0xd8ecc0, data=0x7fffffffce80 "\003\350\t`", size=8, per_cu=0xf24c40) at ../../src/gdb/dwarf2loc.c:2407 #9 0x000000000067a5d4 in dwarf_entry_parameter_to_value (parameter=0x13a7960, deref_size=18446744073709551615, type=0x10876d0, caller_frame=0xd8ecc0, per_cu=0xf24c40) at ../../src/gdb/dwarf2loc.c:1160 #10 0x000000000067a962 in value_of_dwarf_reg_entry (type=0x10876d0, frame=0xd8de70, kind=CALL_SITE_PARAMETER_DWARF_REG, kind_u=...) at ../../src/gdb/dwarf2loc.c:1310 #11 0x000000000067aaca in value_of_dwarf_block_entry (type=0x10876d0, frame=0xd8de70, block=0xf1c2d4 "Q", block_len=1) at ../../src/gdb/dwarf2loc.c:1363 #12 0x000000000067e7c9 in locexpr_read_variable_at_entry (symbol=0x13a7540, frame=0xd8de70) at ../../src/gdb/dwarf2loc.c:3326 #13 0x00000000005daab6 in read_frame_arg (sym=0x13a7540, frame=0xd8de70, argp=0x7fffffffd0e0, entryargp=0x7fffffffd100) at ../../src/gdb/stack.c:362 #14 0x00000000005db384 in print_frame_args (func=0x13a7470, frame=0xd8de70, num=-1, stream=0xea3890) at ../../src/gdb/stack.c:669 #15 0x00000000005dc338 in print_frame (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC, print_args=1, sal=...) at ../../src/gdb/stack.c:1199 #16 0x00000000005db8ee in print_frame_info (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC, print_args=1) at ../../src/gdb/stack.c:851 #17 0x00000000005da2bb in print_stack_frame (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC) at ../../src/gdb/stack.c:169 #18 0x00000000005de236 in frame_command (level_exp=0x0, from_tty=1) at ../../src/gdb/stack.c:2265 dwarf2_evaluate_loc_desc_full (frame #7) knows to handle NOT_AVAILABLE_ERROR errors, but read_memory always throws a generic error. Presently, only the value machinery knows to handle unavailable memory. We need to push the awareness down to the target_xfer layer, making it return a finer grained error indication. We can only return a generic -1 nowadays, which leaves the upper layers with no clue on why the xfer failed. Use target_xfer_partial directly, rather than propagating the error through target_read_memory so as to get a better address to display in the error message. (target_read_memory & friends build on top of target_read (thus the target_xfer machinery), but turn all errors to EIO, an errno value. I think this is a mistake, and we'd better convert all these to return a target_xfer_error too, but that can be done separately. I looked around a bit over memory_error calls, and the need to handle random errno values, other than the EIOs gdb itself hardcodes, probably comes (only) from deprecated_xfer_memory, which uses errno for error indication, but I didn't look exhaustively. We should really get rid of deprecated_xfer_memory and of passing down errno values as error indication in target_read & friends methods). Tested on x86_64 Fedora 17, native and gdbserver. Fixes the test in the PR, which will be added to the testsuite later. gdb/ 2013-08-22 Pedro Alves <palves@redhat.com> PR gdb/15871 * corefile.c (target_xfer_memory_error): New function. (memory_error): Defer EIO to target_memory_error. (read_memory): Use target_xfer_partial, and handle finer-grained target xfer errors. * target.c (target_xfer_error_to_string): New function. (memory_xfer_partial_1): If memory is known to be unavailable, return TARGET_XFER_E_UNAVAILABLE instead of -1. (target_xfer_partial): Make extern. * target.h (enum target_xfer_error): New enum. (target_xfer_error_to_string): Declare function. (target_xfer_partial): Declare function. (struct target_ops) <xfer_partial>: Adjust describing comment.
…sniffer (move dwarf2_tailcall_sniffer_first elsewhere). Two rationales, same patch. TL;DR 1: dwarf2_frame_cache recursion is evil. dwarf2_frame_cache calls dwarf2_tailcall_sniffer_first which then recurses into dwarf2_frame_cache. TL;DR 2: An unwinder trying to unwind is evil. dwarf2_frame_sniffer calls dwarf2_frame_cache which calls dwarf2_tailcall_sniffer_first which then tries to unwind the PC of the previous frame. Avoid all that by deferring dwarf2_tailcall_sniffer_first until it's really necessary. Rationale 1 =========== A frame sniffer should not try to unwind, because that bypasses all the validation checks done by get_prev_frame. The UNWIND_SAME_ID scenario is one such case where GDB is currently broken because (in part) of this (the next patch adds a test that would fail without this). GDB goes into an infinite loop in value_fetch_lazy, here: while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val)) { frame = frame_find_by_id (VALUE_FRAME_ID (new_val)); ... new_val = get_frame_register_value (frame, regnum); } (top-gdb) bt #0 value_fetch_lazy (val=0x11516d0) at ../../src/gdb/value.c:3510 #1 0x0000000000584bd8 in value_optimized_out (value=0x11516d0) at ../../src/gdb/value.c:1096 #2 0x00000000006fe7a1 in frame_register_unwind (frame=0x1492600, regnum=16, optimizedp=0x7fffffffcdec, unavailablep=0x7fffffffcde8, lvalp=0x7fffffffcdd8, addrp= 0x7fffffffcde0, realnump=0x7fffffffcddc, bufferp=0x7fffffffce10 "@\316\377\377\377\177") at ../../src/gdb/frame.c:940 #3 0x00000000006fea3a in frame_unwind_register (frame=0x1492600, regnum=16, buf=0x7fffffffce10 "@\316\377\377\377\177") at ../../src/gdb/frame.c:990 #4 0x0000000000473b9b in i386_unwind_pc (gdbarch=0xf54660, next_frame=0x1492600) at ../../src/gdb/i386-tdep.c:1771 #5 0x0000000000601dfa in gdbarch_unwind_pc (gdbarch=0xf54660, next_frame=0x1492600) at ../../src/gdb/gdbarch.c:2870 #6 0x0000000000693db5 in dwarf2_tailcall_sniffer_first (this_frame=0x1492600, tailcall_cachep=0x14926f0, entry_cfa_sp_offsetp=0x7fffffffcf00) at ../../src/gdb/dwarf2-frame-tailcall.c:389 #7 0x0000000000690928 in dwarf2_frame_cache (this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/dwarf2-frame.c:1245 #8 0x0000000000690f46 in dwarf2_frame_sniffer (self=0x8e4980, this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/dwarf2-frame.c:1423 #9 0x000000000070203b in frame_unwind_find_by_frame (this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/frame-unwind.c:112 #10 0x00000000006fd681 in get_frame_id (fi=0x1492600) at ../../src/gdb/frame.c:408 #11 0x00000000007006c2 in get_prev_frame_1 (this_frame=0xdc1860) at ../../src/gdb/frame.c:1826 #12 0x0000000000700b7a in get_prev_frame (this_frame=0xdc1860) at ../../src/gdb/frame.c:2056 #13 0x0000000000514588 in frame_info_to_frame_object (frame=0xdc1860) at ../../src/gdb/python/py-frame.c:322 #14 0x000000000051784c in bootstrap_python_frame_filters (frame=0xdc1860, frame_low=0, frame_high=-1) at ../../src/gdb/python/py-framefilter.c:1396 #15 0x0000000000517a6f in apply_frame_filter (frame=0xdc1860, flags=7, args_type=CLI_SCALAR_VALUES, out=0xed7a90, frame_low=0, frame_high=-1) at ../../src/gdb/python/py-framefilter.c:1492 #16 0x00000000005e77b0 in backtrace_command_1 (count_exp=0x0, show_locals=0, no_filters=0, from_tty=1) at ../../src/gdb/stack.c:1777 #17 0x00000000005e7c0f in backtrace_command (arg=0x0, from_tty=1) at ../../src/gdb/stack.c:1891 #18 0x00000000004e37a7 in do_cfunc (c=0xda4fa0, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:107 #19 0x00000000004e683c in cmd_func (cmd=0xda4fa0, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:1882 #20 0x00000000006f35ed in execute_command (p=0xcc66c2 "", from_tty=1) at ../../src/gdb/top.c:468 #21 0x00000000005f8853 in command_handler (command=0xcc66c0 "bt") at ../../src/gdb/event-top.c:435 #22 0x00000000005f8e12 in command_line_handler (rl=0xfe05f0 "@") at ../../src/gdb/event-top.c:632 #23 0x000000000074d2c6 in rl_callback_read_char () at ../../src/readline/callback.c:220 #24 0x00000000005f8375 in rl_callback_read_char_wrapper (client_data=0x0) at ../../src/gdb/event-top.c:164 #25 0x00000000005f876a in stdin_event_handler (error=0, client_data=0x0) at ../../src/gdb/event-top.c:375 #26 0x00000000005f72fa in handle_file_event (data=...) at ../../src/gdb/event-loop.c:768 #27 0x00000000005f67a3 in process_event () at ../../src/gdb/event-loop.c:342 #28 0x00000000005f686a in gdb_do_one_event () at ../../src/gdb/event-loop.c:406 #29 0x00000000005f68bb in start_event_loop () at ../../src/gdb/event-loop.c:431 #30 0x00000000005f83a7 in cli_command_loop (data=0x0) at ../../src/gdb/event-top.c:179 #31 0x00000000005eeed3 in current_interp_command_loop () at ../../src/gdb/interps.c:327 #32 0x00000000005ef8ff in captured_command_loop (data=0x0) at ../../src/gdb/main.c:267 #33 0x00000000005ed2f6 in catch_errors (func=0x5ef8e4 <captured_command_loop>, func_args=0x0, errstring=0x8b6554 "", mask=RETURN_MASK_ALL) at ../../src/gdb/exceptions.c:524 #34 0x00000000005f0d21 in captured_main (data=0x7fffffffd9e0) at ../../src/gdb/main.c:1067 #35 0x00000000005ed2f6 in catch_errors (func=0x5efb9b <captured_main>, func_args=0x7fffffffd9e0, errstring=0x8b6554 "", mask=RETURN_MASK_ALL) at ../../src/gdb/exceptions.c:524 #36 0x00000000005f0d57 in gdb_main (args=0x7fffffffd9e0) at ../../src/gdb/main.c:1076 #37 0x000000000045bb6a in main (argc=4, argv=0x7fffffffdae8) at ../../src/gdb/gdb.c:34 (top-gdb) GDB is trying to unwind the PC register of the previous frame (frame #5 above), starting from the frame being sniffed (the THIS frame). But the THIS frame's unwinder says the PC of the previous frame is actually the same as the previous's frame's next frame (which is the same frame we started with, the THIS frame), therefore it returns an lval_register lazy value with frame set to THIS frame. And so the value_fetch_lazy loop never ends. Rationale 2 =========== As an experiment, I tried making dwarf2-frame.c:read_addr_from_reg use address_from_register. That caused a bunch of regressions, but it actually took me a long while to figure out what was going on. Turns out dwarf2-frame.c:read_addr_from_reg is called while computing the frame's CFA, from within dwarf2_frame_cache. address_from_register wants to create a register with frame_id set to the frame being constructed. To create the frame id, we again call dwarf2_frame_cache, which given: static struct dwarf2_frame_cache * dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) { ... if (*this_cache) return *this_cache; returns an incomplete object to the caller: static void dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache, struct frame_id *this_id) { struct dwarf2_frame_cache *cache = dwarf2_frame_cache (this_frame, this_cache); ... (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame)); } As cache->cfa is still 0 (we were trying to compute it!), and get_frame_id recalls this id from here on, we end up with a broken frame id in recorded for this frame. Later, when inspecting locals, the dwarf machinery needs to know the selected frame's base, which calls get_frame_base: CORE_ADDR get_frame_base (struct frame_info *fi) { return get_frame_id (fi).stack_addr; } which as seen above then returns 0 ... So I gave up using address_from_register. But, the pain of investigating this made me want to have GDB itself assert that recursion never happens here. So I wrote a patch to do that. But, it triggers on current mainline, because dwarf2_tailcall_sniffer_first, called from dwarf2_frame_cache, unwinds the this_frame. A sniffer shouldn't be trying to unwind, exactly because of this sort of tricky issue. The patch defers calling dwarf2_tailcall_sniffer_first until it's really necessary, in dwarf2_frame_prev_register (thus actually outside the sniffer path). As this makes the call to dwarf2_frame_sniffer in dwarf2_frame_cache unnecessary again, the patch removes that too. Tested on x86_64 Fedora 17. gdb/ 2013-11-22 Pedro Alves <palves@redhat.com> PR 16155 * dwarf2-frame.c (struct dwarf2_frame_cache) <checked_tailcall_bottom, entry_cfa_sp_offset, entry_cfa_sp_offset_p>: New fields. (dwarf2_frame_cache): Adjust to use the new cache fields instead of locals. Don't call dwarf2_tailcall_sniffer_first here. (dwarf2_frame_prev_register): Call it here, but only once.
…sniffer (move dwarf2_tailcall_sniffer_first elsewhere). Two rationales, same patch. TL;DR 1: dwarf2_frame_cache recursion is evil. dwarf2_frame_cache calls dwarf2_tailcall_sniffer_first which then recurses into dwarf2_frame_cache. TL;DR 2: An unwinder trying to unwind is evil. dwarf2_frame_sniffer calls dwarf2_frame_cache which calls dwarf2_tailcall_sniffer_first which then tries to unwind the PC of the previous frame. Avoid all that by deferring dwarf2_tailcall_sniffer_first until it's really necessary. Rationale 1 =========== A frame sniffer should not try to unwind, because that bypasses all the validation checks done by get_prev_frame. The UNWIND_SAME_ID scenario is one such case where GDB is currently broken because (in part) of this (the next patch adds a test that would fail without this). GDB goes into an infinite loop in value_fetch_lazy, here: while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val)) { frame = frame_find_by_id (VALUE_FRAME_ID (new_val)); ... new_val = get_frame_register_value (frame, regnum); } (top-gdb) bt #0 value_fetch_lazy (val=0x11516d0) at ../../src/gdb/value.c:3510 #1 0x0000000000584bd8 in value_optimized_out (value=0x11516d0) at ../../src/gdb/value.c:1096 #2 0x00000000006fe7a1 in frame_register_unwind (frame=0x1492600, regnum=16, optimizedp=0x7fffffffcdec, unavailablep=0x7fffffffcde8, lvalp=0x7fffffffcdd8, addrp= 0x7fffffffcde0, realnump=0x7fffffffcddc, bufferp=0x7fffffffce10 "@\316\377\377\377\177") at ../../src/gdb/frame.c:940 #3 0x00000000006fea3a in frame_unwind_register (frame=0x1492600, regnum=16, buf=0x7fffffffce10 "@\316\377\377\377\177") at ../../src/gdb/frame.c:990 #4 0x0000000000473b9b in i386_unwind_pc (gdbarch=0xf54660, next_frame=0x1492600) at ../../src/gdb/i386-tdep.c:1771 #5 0x0000000000601dfa in gdbarch_unwind_pc (gdbarch=0xf54660, next_frame=0x1492600) at ../../src/gdb/gdbarch.c:2870 #6 0x0000000000693db5 in dwarf2_tailcall_sniffer_first (this_frame=0x1492600, tailcall_cachep=0x14926f0, entry_cfa_sp_offsetp=0x7fffffffcf00) at ../../src/gdb/dwarf2-frame-tailcall.c:389 #7 0x0000000000690928 in dwarf2_frame_cache (this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/dwarf2-frame.c:1245 #8 0x0000000000690f46 in dwarf2_frame_sniffer (self=0x8e4980, this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/dwarf2-frame.c:1423 #9 0x000000000070203b in frame_unwind_find_by_frame (this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/frame-unwind.c:112 #10 0x00000000006fd681 in get_frame_id (fi=0x1492600) at ../../src/gdb/frame.c:408 #11 0x00000000007006c2 in get_prev_frame_1 (this_frame=0xdc1860) at ../../src/gdb/frame.c:1826 #12 0x0000000000700b7a in get_prev_frame (this_frame=0xdc1860) at ../../src/gdb/frame.c:2056 #13 0x0000000000514588 in frame_info_to_frame_object (frame=0xdc1860) at ../../src/gdb/python/py-frame.c:322 #14 0x000000000051784c in bootstrap_python_frame_filters (frame=0xdc1860, frame_low=0, frame_high=-1) at ../../src/gdb/python/py-framefilter.c:1396 #15 0x0000000000517a6f in apply_frame_filter (frame=0xdc1860, flags=7, args_type=CLI_SCALAR_VALUES, out=0xed7a90, frame_low=0, frame_high=-1) at ../../src/gdb/python/py-framefilter.c:1492 #16 0x00000000005e77b0 in backtrace_command_1 (count_exp=0x0, show_locals=0, no_filters=0, from_tty=1) at ../../src/gdb/stack.c:1777 #17 0x00000000005e7c0f in backtrace_command (arg=0x0, from_tty=1) at ../../src/gdb/stack.c:1891 #18 0x00000000004e37a7 in do_cfunc (c=0xda4fa0, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:107 #19 0x00000000004e683c in cmd_func (cmd=0xda4fa0, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:1882 #20 0x00000000006f35ed in execute_command (p=0xcc66c2 "", from_tty=1) at ../../src/gdb/top.c:468 #21 0x00000000005f8853 in command_handler (command=0xcc66c0 "bt") at ../../src/gdb/event-top.c:435 #22 0x00000000005f8e12 in command_line_handler (rl=0xfe05f0 "@") at ../../src/gdb/event-top.c:632 #23 0x000000000074d2c6 in rl_callback_read_char () at ../../src/readline/callback.c:220 #24 0x00000000005f8375 in rl_callback_read_char_wrapper (client_data=0x0) at ../../src/gdb/event-top.c:164 #25 0x00000000005f876a in stdin_event_handler (error=0, client_data=0x0) at ../../src/gdb/event-top.c:375 #26 0x00000000005f72fa in handle_file_event (data=...) at ../../src/gdb/event-loop.c:768 #27 0x00000000005f67a3 in process_event () at ../../src/gdb/event-loop.c:342 #28 0x00000000005f686a in gdb_do_one_event () at ../../src/gdb/event-loop.c:406 #29 0x00000000005f68bb in start_event_loop () at ../../src/gdb/event-loop.c:431 #30 0x00000000005f83a7 in cli_command_loop (data=0x0) at ../../src/gdb/event-top.c:179 #31 0x00000000005eeed3 in current_interp_command_loop () at ../../src/gdb/interps.c:327 #32 0x00000000005ef8ff in captured_command_loop (data=0x0) at ../../src/gdb/main.c:267 #33 0x00000000005ed2f6 in catch_errors (func=0x5ef8e4 <captured_command_loop>, func_args=0x0, errstring=0x8b6554 "", mask=RETURN_MASK_ALL) at ../../src/gdb/exceptions.c:524 #34 0x00000000005f0d21 in captured_main (data=0x7fffffffd9e0) at ../../src/gdb/main.c:1067 #35 0x00000000005ed2f6 in catch_errors (func=0x5efb9b <captured_main>, func_args=0x7fffffffd9e0, errstring=0x8b6554 "", mask=RETURN_MASK_ALL) at ../../src/gdb/exceptions.c:524 #36 0x00000000005f0d57 in gdb_main (args=0x7fffffffd9e0) at ../../src/gdb/main.c:1076 #37 0x000000000045bb6a in main (argc=4, argv=0x7fffffffdae8) at ../../src/gdb/gdb.c:34 (top-gdb) GDB is trying to unwind the PC register of the previous frame (frame #5 above), starting from the frame being sniffed (the THIS frame). But the THIS frame's unwinder says the PC of the previous frame is actually the same as the previous's frame's next frame (which is the same frame we started with, the THIS frame), therefore it returns an lval_register lazy value with frame set to THIS frame. And so the value_fetch_lazy loop never ends. Rationale 2 =========== As an experiment, I tried making dwarf2-frame.c:read_addr_from_reg use address_from_register. That caused a bunch of regressions, but it actually took me a long while to figure out what was going on. Turns out dwarf2-frame.c:read_addr_from_reg is called while computing the frame's CFA, from within dwarf2_frame_cache. address_from_register wants to create a register with frame_id set to the frame being constructed. To create the frame id, we again call dwarf2_frame_cache, which given: static struct dwarf2_frame_cache * dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) { ... if (*this_cache) return *this_cache; returns an incomplete object to the caller: static void dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache, struct frame_id *this_id) { struct dwarf2_frame_cache *cache = dwarf2_frame_cache (this_frame, this_cache); ... (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame)); } As cache->cfa is still 0 (we were trying to compute it!), and get_frame_id recalls this id from here on, we end up with a broken frame id in recorded for this frame. Later, when inspecting locals, the dwarf machinery needs to know the selected frame's base, which calls get_frame_base: CORE_ADDR get_frame_base (struct frame_info *fi) { return get_frame_id (fi).stack_addr; } which as seen above then returns 0 ... So I gave up using address_from_register. But, the pain of investigating this made me want to have GDB itself assert that recursion never happens here. So I wrote a patch to do that. But, it triggers on current mainline, because dwarf2_tailcall_sniffer_first, called from dwarf2_frame_cache, unwinds the this_frame. A sniffer shouldn't be trying to unwind, exactly because of this sort of tricky issue. The patch defers calling dwarf2_tailcall_sniffer_first until it's really necessary, in dwarf2_frame_prev_register (thus actually outside the sniffer path). As this makes the call to dwarf2_frame_sniffer in dwarf2_frame_cache unnecessary again, the patch removes that too. Tested on x86_64 Fedora 17. gdb/ 2013-11-22 Pedro Alves <palves@redhat.com> PR 16155 * dwarf2-frame.c (struct dwarf2_frame_cache) <checked_tailcall_bottom, entry_cfa_sp_offset, entry_cfa_sp_offset_p>: New fields. (dwarf2_frame_cache): Adjust to use the new cache fields instead of locals. Don't call dwarf2_tailcall_sniffer_first here. (dwarf2_frame_prev_register): Call it here, but only once.
Given we already have the frame id stash, which holds the ids of all frames in the chain, detecting corrupted stacks with wide stack cycles with non-consecutive dup frame ids is just as cheap as just detecting cycles in consecutive frames: #0 frame_id1 #1 frame_id2 #2 frame_id3 #3 frame_id1 #4 frame_id2 #5 frame_id3 #6 frame_id1 ... forever ... We just need to check whether the stash already knows about a given frame id instead of comparing the ids of the previous/this frames. Tested on x86_64 Fedora 17. gdb/ 2013-11-22 Pedro Alves <palves@redhat.com> Tom Tromey <tromey@redhat.com> * frame.c (frame_stash_add): Now returns whether a frame with the same ID was already known. (compute_frame_id): New function, factored out from get_frame_id. (get_frame_id): No longer lazilly compute the frame id here. (get_prev_frame_if_no_cycle): New function. Detects wider stack cycles. (get_prev_frame_1): Use it instead of get_prev_frame_raw directly, and checking for stack cycles here.
Remote servers may cut the connection abruptly since they are not required to reply to a 'k' (Kill) packet sent from GDB. This patch addresses any issues arising from such scenario, which leads to a GDB internal error due to an attempt to pop the target more than once. With the patch, this failure is handled gracefully. Here's the GDB backtrace Maciej got running the testsuite against QEMU. Full paths edited out for brevity. #0 0x55573430 in __kernel_vsyscall () #1 0x557a2951 in raise () from /lib32/libc.so.6 #2 0x557a5d82 in abort () from /lib32/libc.so.6 #3 0x0826e2e4 in dump_core () at .../gdb/utils.c:635 #4 0x0826e5b6 in internal_vproblem (problem=0x85200c0, file=0x8416be8 ".../gdb/target.c", line=2861, fmt=0x84174ac "could not find a target to follow mourn inferior", ap=0xffa4796c "\f") at .../gdb/utils.c:804 #5 0x0826e5fb in internal_verror ( file=0x8416be8 ".../gdb/target.c", line=2861, fmt=0x84174ac "could not find a target to follow mourn inferior", ap=0xffa4796c "\f") at .../gdb/utils.c:820 #6 0x0826e633 in internal_error ( file=0x8416be8 ".../gdb/target.c", line=2861, string=0x84174ac "could not find a target to follow mourn inferior") at .../gdb/utils.c:830 #7 0x081b4ad0 in target_mourn_inferior () at .../gdb/target.c:2861 #8 0x08082283 in remote_kill (ops=0x85245e0) at .../gdb/remote.c:7840 #9 0x081b06d1 in target_kill () at .../gdb/target.c:486 #10 0x081b42f6 in dispose_inferior (inf=0xa501c60, args=0x0) at .../gdb/target.c:2570 #11 0x08290cfc in iterate_over_inferiors ( callback=0x81b42af <dispose_inferior>, data=0x0) at .../gdb/inferior.c:396 #12 0x081b435a in target_preopen (from_tty=1) at .../gdb/target.c:2591 #13 0x0807c2c6 in remote_open_1 (name=0xa5538b6 "localhost:1237", from_tty=1, target=0x85245e0, extended_p=0) at .../gdb/remote.c:4292 #14 0x0807b7a8 in remote_open (name=0xa5538b6 "localhost:1237", from_tty=1) at .../gdb/remote.c:3655 #15 0x080a23d4 in do_cfunc (c=0xa464f30, args=0xa5538b6 "localhost:1237", from_tty=1) at .../gdb/cli/cli-decode.c:107 #16 0x080a4c3b in cmd_func (cmd=0xa464f30, args=0xa5538b6 "localhost:1237", from_tty=1) at .../gdb/cli/cli-decode.c:1882 #17 0x0826bebf in execute_command (p=0xa5538c3 "7", from_tty=1) at .../gdb/top.c:467 #18 0x08193f2d in command_handler (command=0xa5538a8 "") at .../gdb/event-top.c:435 #19 0x08194463 in command_line_handler ( rl=0xa778198 "target remote localhost:1237") at .../gdb/event-top.c:633 #20 0x082ba92b in rl_callback_read_char () at .../readline/callback.c:220 #21 0x08193adf in rl_callback_read_char_wrapper (client_data=0x0) at .../gdb/event-top.c:164 #22 0x08193e57 in stdin_event_handler (error=0, client_data=0x0) at .../gdb/event-top.c:375 #23 0x08192f29 in handle_file_event (data=...) at .../gdb/event-loop.c:768 #24 0x0819266a in process_event () at .../gdb/event-loop.c:342 #25 0x08192708 in gdb_do_one_event () at .../gdb/event-loop.c:394 #26 0x08192781 in start_event_loop () at .../gdb/event-loop.c:431 #27 0x08193b08 in cli_command_loop (data=0x0) at .../gdb/event-top.c:179 #28 0x0818bc26 in current_interp_command_loop () at .../gdb/interps.c:327 #29 0x0818c4e5 in captured_command_loop (data=0x0) at .../gdb/main.c:267 #30 0x0818a37f in catch_errors (func=0x818c4d0 <captured_command_loop>, func_args=0x0, errstring=0x8402108 "", mask=RETURN_MASK_ALL) at .../gdb/exceptions.c:524 #31 0x0818d736 in captured_main (data=0xffa47f10) at .../gdb/main.c:1067 #32 0x0818a37f in catch_errors (func=0x818c723 <captured_main>, func_args=0xffa47f10, errstring=0x8402108 "", mask=RETURN_MASK_ALL) at .../gdb/exceptions.c:524 #33 0x0818d76c in gdb_main (args=0xffa47f10) at .../gdb/main.c:1076 #34 0x0804dd1b in main (argc=5, argv=0xffa47fd4) at .../gdb/gdb.c:34 The corresponding gdb.log excerpt: (gdb) PASS: gdb.base/bitfields.exp: bitfield uniqueness (u9) cont Continuing. Breakpoint 1, break1 () at .../gdb/testsuite/gdb.base/bitfields.c:44 44 } (gdb) PASS: gdb.base/bitfields.exp: continuing to break1 #9 print flags $10 = {uc = 0 '\000', s1 = 0, u1 = 0, s2 = 0, u2 = 0, s3 = 0, u3 = 0, s9 = 0, u9 = 0, sc = 1 '\001'} (gdb) PASS: gdb.base/bitfields.exp: bitfield uniqueness (sc) delete breakpoints Delete all breakpoints? (y or n) y (gdb) info breakpoints No breakpoints or watchpoints. (gdb) delete breakpoints (gdb) info breakpoints No breakpoints or watchpoints. (gdb) break break2 Breakpoint 2 at 0x85f8: file .../gdb/testsuite/gdb.base/bitfields.c, line 48. (gdb) entering gdb_reload target remote localhost:1235 A program is being debugged already. Kill it? (y or n) y Remote connection closed .../gdb/target.c:2861: internal-error: could not find a target to follow mourn inferior A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) ^Ccontinue Please answer y or n. .../gdb/target.c:2861: internal-error: could not find a target to follow mourn inferior A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) Resyncing due to internal error. n .../gdb/target.c:2861: internal-error: could not find a target to follow mourn inferior A problem internal to GDB has been detected, further debugging may prove unreliable. Create a core file of GDB? (y or n) y Command aborted. (gdb) print/x flags $11 = {uc = 0x0, s1 = 0x0, u1 = 0x0, s2 = 0x0, u2 = 0x0, s3 = 0x0, u3 = 0x0, s9 = 0x0, u9 = 0x0, sc = 0x0} (gdb) FAIL: gdb.base/bitfields.exp: bitfield containment #1 cont The program is not being run. (gdb) FAIL: gdb.base/bitfields.exp: continuing to break2 (the program is no longer running) print/x flags $12 = {uc = 0x0, s1 = 0x0, u1 = 0x0, s2 = 0x0, u2 = 0x0, s3 = 0x0, u3 = 0x0, s9 = 0x0, u9 = 0x0, sc = 0x0} (gdb) FAIL: gdb.base/bitfields.exp: bitfield containment #2 delete breakpoints Delete all breakpoints? (y or n) y (gdb) info breakpoints No breakpoints or watchpoints. (gdb) delete breakpoints (gdb) info breakpoints No breakpoints or watchpoints. (gdb) break break3 Breakpoint 3 at 0x8604: file .../gdb/testsuite/gdb.base/bitfields.c, line 52. (gdb) entering gdb_reload target remote localhost:1236 Remote debugging using localhost:1236 Reading symbols from .../lib/ld-linux.so.3...done. Loaded symbols for .../lib/ld-linux.so.3 0x41001b80 in _start () from .../lib/ld-linux.so.3 (gdb) continue Continuing. Breakpoint 3, break3 () at .../gdb/testsuite/gdb.base/bitfields.c:52 52 } (gdb) print flags $13 = {uc = 0 '\000', s1 = 0, u1 = 1, s2 = 0, u2 = 3, s3 = 0, u3 = 7, s9 = 0, u9 = 511, sc = 0 '\000'} (gdb) PASS: gdb.base/bitfields.exp: unsigned bitfield ranges gdb/ 2013-12-02 Pedro Alves <pedro@codesourcery.com> Maciej W. Rozycki <macro@codesourcery.com> * remote.c (putpkt_for_catch_errors): Remove function. (remote_kill): Handle TARGET_CLOSE_ERROR from the kill packet gracefully.
We have a fork that adds in Objective-C support (although a bit hacky in places) at https://github.com/apportable/gdb. Let me know if you'd like a pull request.
The text was updated successfully, but these errors were encountered: