On Tumbleweed I run into a few new failures, the first one in test-case gdb.base/annota1.exp, due to: ... (warning: (Error: pc 0x7ffff7c4290f in address map, but not in symtab.)^M ... The address is in libc, in the code for__sigaction: ... 000000000004282e <__sigaction>: 4282e: f3 0f 1e fa endbr64 ... 428f3: eb cd jmp 428c2 <__sigaction+0x94> 428f5: e8 e4 c0 0e 00 call 12e9de <__stack_chk_fail> 428fa: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 42900: 90 nop 42901: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1) 42908: 00 00 00 00 4290c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000042910 <__restore_rt>: ... The dwarf for __sigaction: ... <1><823f7>: Abbrev Number: 76 (DW_TAG_subprogram) <823f8> DW_AT_external : 1 <823f8> DW_AT_name : __sigaction <823ff> DW_AT_linkage_name: __GI___sigaction <82403> DW_AT_prototyped : 1 <82403> DW_AT_type : <0x32> <82407> DW_AT_low_pc : 0x4282e <8240f> DW_AT_high_pc : 204 <82411> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa) <82413> DW_AT_call_all_calls: 1 ... states that the range for the function is [0x4282e, 0x428fa), which indeed doesn't include 0x4290f. I wonder if the warning is about this .debug_aranges bit: ... Length: 44 Version: 2 Offset into .debug_info: 0x8250f Pointer Size: 8 Segment Size: 0 Address Length 0000000000042900 0000000000000200 0000000000000000 0000000000000000 ...
Reproduces with Leap 16.0 as well. Didn't reproduce with gdb-17-branch, I'll try a bisect.
(In reply to Tom de Vries from comment #1) > I'll try a bisect. FAILs start with commit cc1fc6af415 ("gdb: change blockvector::contains() to handle blockvectors with "holes"").
The address is constructed here in call_site_for_pc, from the address of __restore_rt: ... 164 /* -1 as tail call PC can be already after the compilation unit range. */ 165 cust = find_compunit_symtab_for_pc (pc - 1); 166 ... This makes the warning go away: ... diff --git a/gdb/symtab.c b/gdb/symtab.c index 5754d944b6c..c64cb1c9b9a 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -2824,7 +2824,7 @@ find_compunit_symtab_for_pc_sect (CORE_ADDR pc, struct obj_section *secti on) for (objfile &objf : current_program_space->objfiles ()) { struct compunit_symtab *result - = objf.find_pc_sect_compunit_symtab (msymbol, pc, section, 1); + = objf.find_pc_sect_compunit_symtab (msymbol, pc, section, 0); if (result != NULL) return result; } ...
Backtrace at warning: ... (gdb) bt #0 warning (fmt=0x1b15570 "(Error: pc %s in address map, but not in symtab.)") at /data/vries/gdb/src/gdbsupport/errors.cc:29 #1 0x00000000008a1448 in dwarf2_base_index_functions::find_pc_sect_compunit_symtab (this=0x3523ed0, objfile=0x355f8c0, msymbol=..., pc=140737351000207, section=0x0, warn_if_readin=1) at /data/vries/gdb/src/gdb/dwarf2/read.c:2208 #2 0x000000000087c086 in cooked_index_functions::find_pc_sect_compunit_symtab (this=0x3523ed0, objfile=0x355f8c0, msymbol=..., pc=140737351000207, section=0x0, warn_if_readin=1) at /data/vries/gdb/src/gdb/dwarf2/cooked-index.h:256 #3 0x0000000000f392dc in objfile::find_pc_sect_compunit_symtab (this=0x355f8c0, msymbol=..., pc=140737351000207, section=0x0, warn_if_readin=1) at /data/vries/gdb/src/gdb/symfile-debug.c:442 #4 0x0000000000f63a01 in find_compunit_symtab_for_pc_sect (pc=140737351000207, section=0x0) at /data/vries/gdb/src/gdb/symtab.c:2827 #5 0x0000000000f63a9f in find_compunit_symtab_for_pc (pc=140737351000207) at /data/vries/gdb/src/gdb/symtab.c:2842 #6 0x00000000005d061e in call_site_for_pc (gdbarch=0x3304950, pc=140737351000208) at /data/vries/gdb/src/gdb/block.c:165 #7 0x0000000000864858 in call_site_find_chain_1 (gdbarch=0x3304950, caller_pc=140737351000208, callee_pc=4198726) at /data/vries/gdb/src/gdb/dwarf2/loc.c:1056 #8 0x0000000000864aa9 in call_site_find_chain (gdbarch=0x3304950, caller_pc=140737351000208, callee_pc=4198733) at /data/vries/gdb/src/gdb/dwarf2/loc.c:1095 #9 0x000000000081bee6 in dwarf2_tailcall_sniffer_first (this_frame=..., tailcall_cachep=0x3749ce0, entry_cfa_sp_offsetp=0x7fffffffaec0) at /data/vries/gdb/src/gdb/dwarf2/frame-tailcall.c:389 #10 0x000000000082018d in dwarf2_frame_cache (this_frame=..., this_cache=0x3749bf8) at /data/vries/gdb/src/gdb/dwarf2/frame.c:1108 #11 0x0000000000820311 in dwarf2_frame_this_id (this_frame=..., this_cache=0x3749bf8, this_id=0x3749c40) at /data/vries/gdb/src/gdb/dwarf2/frame.c:1136 #12 0x0000000000987438 in frame_unwind_legacy::this_id (this=0x2f093c0 <dwarf2_frame_unwind>, this_frame=..., this_prologue_cache=0x3749bf8, id=0x3749c40) at /data/vries/gdb/src/gdb/frame-unwind.c:399 #13 0x000000000098d143 in compute_frame_id (fi=...) at /data/vries/gdb/src/gdb/frame.c:642 #14 0x000000000098d442 in get_frame_id (fi=...) at /data/vries/gdb/src/gdb/frame.c:685 #15 0x0000000000992fbf in get_prev_frame_always_1 (this_frame=...) at /data/vries/gdb/src/gdb/frame.c:2394 #16 0x0000000000993802 in get_prev_frame_always (this_frame=...) at /data/vries/gdb/src/gdb/frame.c:2526 #17 0x00000000009959d3 in get_frame_unwind_stop_reason (frame=...) at /data/vries/gdb/src/gdb/frame.c:3253 #18 0x0000000000820e63 in dwarf2_frame_cfa (initial_this_frame=...) at /data/vries/gdb/src/gdb/dwarf2/frame.c:1418 #19 0x00000000008165f8 in dwarf_expr_context::execute_stack_op (this=0x7fffffffb9f0, op_ptr=0x33c540f "\024sig", op_end=0x33c540f "\024sig") at /data/vries/gdb/src/gdb/dwarf2/expr.c:2185 #20 0x0000000000813c65 in dwarf_expr_context::eval (this=0x7fffffffb9f0, addr=0x33c540e "\234\024sig", len=1) at /data/vries/gdb/src/gdb/dwarf2/expr.c:1297 #21 0x00000000008155b0 in dwarf_expr_context::execute_stack_op (this=0x7fffffffb9f0, op_ptr=0x33c541e "", op_end=0x33c541e "") at /data/vries/gdb/src/gdb/dwarf2/expr.c:1901 #22 0x0000000000813c65 in dwarf_expr_context::eval (this=0x7fffffffb9f0, addr=0x33c541c "\221l", len=2) at /data/vries/gdb/src/gdb/dwarf2/expr.c:1297 #23 0x0000000000813564 in dwarf_expr_context::evaluate (this=0x7fffffffb9f0, addr=0x33c541c "\221l", len=2, as_lval=true, per_cu=0x7fffe0004850, frame=..., addr_info=0x0, type=0x32f0f10, subobj_type=0x32f0f10, subobj_offset=0) at /data/vries/gdb/src/gdb/dwarf2/expr.c:1135 #24 0x0000000000865ecb in dwarf2_evaluate_loc_desc_full (type=0x32f0f10, frame=..., data=0x33c541c "\221l", size=2, per_cu=0x7fffe0004850, per_objfile=0x3320b50, subobj_type=0x32f0f10, subobj_byte_offset=0, as_lval=true) at /data/vries/gdb/src/gdb/dwarf2/loc.c:1521 #25 0x0000000000866122 in dwarf2_evaluate_loc_desc (type=0x32f0f10, frame=..., data=0x33c541c "\221l", size=2, per_cu=0x7fffe0004850, per_objfile=0x3320b50, as_lval=true) at /data/vries/gdb/src/gdb/dwarf2/loc.c:1565 #26 0x000000000086a03b in locexpr_read_variable (symbol=0x33064b0, frame=...) at /data/vries/gdb/src/gdb/dwarf2/loc.c:3087 #27 0x0000000000983c56 in language_defn::read_var_value (this=0x2f05940 <c_language_defn>, var=0x33064b0, var_block=0x0, frame_param=...) at /data/vries/gdb/src/gdb/findvar.c:308 #28 0x00000000009848f1 in read_var_value (var=0x33064b0, var_block=0x0, frame=...) at /data/vries/gdb/src/gdb/findvar.c:518 #29 0x0000000000f1e9b7 in read_frame_arg (fp_opts=..., sym=0x33064b0, frame=..., argp=0x7fffffffbed0, entryargp=0x7fffffffbef0) at /data/vries/gdb/src/gdb/stack.c:535 #30 0x0000000000f1f6b4 in print_frame_args (fp_opts=..., func=0x3306430, frame=..., num=-1, stream=0x36025e8) at /data/vries/gdb/src/gdb/stack.c:873 #31 0x0000000000f20e4d in print_frame (uiout=0x3389c30, fp_opts=..., frame=..., print_level=0, print_what=SRC_AND_LOC, print_args=1, sal=...) at /data/vries/gdb/src/gdb/stack.c:1387 #32 0x0000000000f20114 in do_print_frame_info (uiout=0x3389c30, fp_opts=..., frame=..., print_level=0, print_what=SRC_AND_LOC, print_args=1, set_current_sal=1) at /data/vries/gdb/src/gdb/stack.c:1100 #33 0x0000000000f2b159 in do_with_buffered_output<void (*)(ui_out*, frame_print_options const&, frame_info_ptr const&, int, print_what, int, int), frame_print_options, frame_info_ptr, int, print_what, int, int> ( func=0xf1fc89 <do_print_frame_info(ui_out*, frame_print_options const&, frame_info_ptr const&, int, print_what, int, int)>, uiout=0x3389c30) at /data/vries/gdb/src/gdb/ui-out.h:546 #34 0x0000000000f2052b in print_frame_info (fp_opts=..., frame=..., print_level=0, print_what=SRC_AND_LOC, print_args=1, set_current_sal=1) at /data/vries/gdb/src/gdb/stack.c:1190 #35 0x0000000000f1e127 in print_stack_frame (frame=..., print_level=0, print_what=SRC_AND_LOC, set_current_sal=1) at /data/vries/gdb/src/gdb/stack.c:362 #36 0x0000000000a9a853 in print_stop_location (ws=...) at /data/vries/gdb/src/gdb/infrun.c:9395 #37 0x0000000000a9a98f in do_print_stop_event (uiout=0x3389c30, displays=true) at /data/vries/gdb/src/gdb/infrun.c:9411 #38 0x0000000000aa34f5 in do_with_buffered_output<void (*)(ui_out*, bool), bool> ( func=0xa9a916 <do_print_stop_event(ui_out*, bool)>, uiout=0x3389c30) at /data/vries/gdb/src/gdb/ui-out.h:546 #39 0x0000000000a9aabd in print_stop_event (uiout=0x3389c30, displays=true) at /data/vries/gdb/src/gdb/infrun.c:9437 #40 0x00000000006d20e6 in cli_interp_base::on_normal_stop (this=0x33406c0, bs=0x377e9b0, print_frame=1) at /data/vries/gdb/src/gdb/cli/cli-interp.c:118 #41 0x0000000000ab83b6 in interps_notify<void (interp::*)(bpstat*, int), bpstat*&, int&> ( method=&virtual interp::on_normal_stop(bpstat*, int)) at /data/vries/gdb/src/gdb/interps.c:369 #42 0x0000000000ab6a49 in interps_notify_normal_stop (bs=0x377e9b0, print_frame=1) at /data/vries/gdb/src/gdb/interps.c:402 #43 0x0000000000a938bb in notify_normal_stop (bs=0x377e9b0, print_frame=1) at /data/vries/gdb/src/gdb/infrun.c:6839 #44 0x0000000000a9b4f4 in normal_stop () at /data/vries/gdb/src/gdb/infrun.c:9740 #45 0x0000000000a8d60a in fetch_inferior_event () at /data/vries/gdb/src/gdb/infrun.c:4764 #46 0x0000000000a5b8ae in inferior_event_handler (event_type=INF_REG_EVENT) at /data/vries/gdb/src/gdb/inf-loop.c:42 #47 0x0000000000b02034 in handle_target_event (error=0, client_data=0x0) at /data/vries/gdb/src/gdb/linux-nat.c:4448 #48 0x0000000001a0bbdb in handle_file_event (file_ptr=0x34c8980, ready_mask=1) at /data/vries/gdb/src/gdbsupport/event-loop.cc:551 #49 0x0000000001a0c21e in gdb_wait_for_event (block=0) at /data/vries/gdb/src/gdbsupport/event-loop.cc:672 #50 0x0000000001a0aff2 in gdb_do_one_event (mstimeout=-1) at /data/vries/gdb/src/gdbsupport/event-loop.cc:216 #51 0x00000000006d3482 in interp::do_one_event (this=0x33406c0, mstimeout=-1) at /data/vries/gdb/src/gdb/interps.h:87 #52 0x0000000000feaa96 in wait_sync_command_done () at /data/vries/gdb/src/gdb/top.c:418 #53 0x0000000000feab5a in maybe_wait_sync_command_done (was_sync=0) at /data/vries/gdb/src/gdb/top.c:435 #54 0x0000000000feb23c in execute_command (p=0x7fffffffd13d "1", from_tty=0) at /data/vries/gdb/src/gdb/top.c:566 #55 0x0000000000944a22 in command_handler (command=0x7fffffffd130 "signal SIGUSR1") at /data/vries/gdb/src/gdb/event-top.c:613 #56 0x0000000000fea731 in read_command_file (stream=0x31d4a70) at /data/vries/gdb/src/gdb/top.c:333 #57 0x00000000006dff8b in script_from_file (stream=0x31d4a70, file=0x7fffffffdd7d "gdb.in") at /data/vries/gdb/src/gdb/cli/cli-script.c:1704 #58 0x00000000006b6e79 in source_script_from_stream (stream=0x31d4a70, file=0x7fffffffdd7d "gdb.in", file_to_open=0x7fffffffd2f0 "gdb.in") at /data/vries/gdb/src/gdb/cli/cli-cmds.c:706 #59 0x00000000006b7027 in source_script_with_search (file=0x7fffffffdd7d "gdb.in", from_tty=0, search_path=0) at /data/vries/gdb/src/gdb/cli/cli-cmds.c:751 #60 0x00000000006b70d6 in source_script (file=0x7fffffffdd7d "gdb.in", from_tty=0) at /data/vries/gdb/src/gdb/cli/cli-cmds.c:760 #61 0x0000000000b734b9 in catch_command_errors (command=0x6b70a2 <source_script(char const*, int)>, arg=0x7fffffffdd7d "gdb.in", from_tty=0, do_bp_actions=false) at /data/vries/gdb/src/gdb/main.c:510 #62 0x0000000000b73740 in execute_cmdargs (cmdarg_vec=0x7fffffffd530, file_type=CMDARG_FILE, cmd_type=CMDARG_COMMAND, ret=0x7fffffffd460) at /data/vries/gdb/src/gdb/main.c:606 #63 0x0000000000b7509d in captured_main_1 (context=0x7fffffffd720) at /data/vries/gdb/src/gdb/main.c:1351 #64 0x0000000000b75342 in captured_main (context=0x7fffffffd720) at /data/vries/gdb/src/gdb/main.c:1374 #65 0x0000000000b75443 in gdb_main (args=0x7fffffffd720) at /data/vries/gdb/src/gdb/main.c:1403 #66 0x00000000004196f5 in main (argc=7, argv=0x7fffffffd858) at /data/vries/gdb/src/gdb/gdb.c:38 ...
[ Continuing on Leap 16.0, with different addresses. ] In glibc sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c we find: ... #define RESTORE(name, syscall) RESTORE2 (name, syscall) # define RESTORE2(name, syscall) \ asm \ ( \ /* `nop' for debuggers assuming `call' should not disalign the code. */ \ " nop\n" \ ".align 16\n" \ ".LSTART_" #name ":\n" \ " .type __" #name ",@function\n" \ "__" #name ":\n" \ " movq $" #syscall ", %rax\n" \ " syscall\n" \ ".LEND_" #name ":\n" \ ... which translates to __restore_rt starting at 0x41090, but the CU starting at the nop at 0x41080: ... 41074: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1) 4107b: 00 00 00 4107e: 66 90 xchg %ax,%ax 41080: 90 nop 41081: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1) 41088: 00 00 00 00 4108c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000041090 <__restore_rt>: 41090: 48 c7 c0 0f 00 00 00 mov $0xf,%rax 41097: 0f 05 syscall 41099: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) ... So the warning: ... warning: (Error: pc 0x7ffff7d0208f in address map, but not in symtab.) ... is correct: - pc 0x7ffff7d0208f (unrelocated, 0x4108f == __restore_rt - 1) is part of the address map, pointing to the CU for libc_sigaction.c, and - there is no symbol in the CU matching 0x4108f. I wondered if it could be possible to skip the warning by detecting that we're dealing with the signal trampoline, but that code takes a frame_info_ptr as argument: ... static int amd64_linux_sigtramp_p (const frame_info_ptr &this_frame) { ... and AFAIU we're in the process of calculating that frame id, so I suppose that's no possible.
See the other bug I linked to... I tend to think these warnings aren't really correct, in that they normally arise from incorrect debug information and not a bug in gdb.
I just installed Tumbleweed into an x86_64 virtual machine, checked out commit cc1fc6af415, build using just plain ./configure (no extra args). With this, I could not reproduce the issue.
(In reply to Jan Vrany from comment #7) > I just installed Tumbleweed into an x86_64 virtual machine, checked out > commit cc1fc6af415, build using just plain ./configure (no extra args). > > With this, I could not reproduce the issue. The failure requires glibc debuginfo, so without: - installing it (sudo zypper install glibc-debuginfo), and - using it (configure --with-separate-debug-dir=/usr/lib/debug) you won't be able to reproduce it.
(In reply to Tom de Vries from comment #2) > (In reply to Tom de Vries from comment #1) > > I'll try a bisect. > > FAILs start with commit cc1fc6af415 ("gdb: change blockvector::contains() to > handle blockvectors with "holes""). FYI, at least on arm-linux-gnueabihf this commit causes this failure and also other failures mentioned here: https://gitlab.com/LinaroLtd/tcwg/ci/interesting-commits/-/raw/master/gdb/sha1/cc1fc6af4150b19f9c4c70d0463ff498703fb637/tcwg_gdb_check/master-arm/details.txt
(In reply to Tom de Vries from comment #8) > The failure requires glibc debuginfo, so without: > - installing it (sudo zypper install glibc-debuginfo), and > - using it (configure --with-separate-debug-dir=/usr/lib/debug) > you won't be able to reproduce it. Ah, that was the bit I missed! Thanks a lot. With this, I can reproduce it even on Debian x86_64.
I thought that in a blockvector, each function has its own block (possibly with other nested blocks) and global/static block start is merely minimum of starts of all function blocks and similarly end is maximum. But it turned out that this is not true in all cases and the code in libc_sigaction.c is just an example. Consider following C program (case A): __asm__( "foo: \n" " mov %rdi, %rax \n" " ret \n" ); extern int foo(int i); int main(int argc, char **argv) { return foo(argc); } When compiled by GCC and loaded in GDB the global and static block will cover the mov and ret of "function" foo but no such function exists in debug info nor in GDB's CU: Symtab for file contains.c at 0x5591f82cbf00 ... Blockvector: no map block #000, object at 0x5591f82cc620, 1 symbols in 0x1129..0x1148 int main(int, char **); block object 0x5591f82cc490, 0x112d..0x1148 section .text block #001, object at 0x5591f82cc580 under 0x5591f82cc620, 2 symbols in 0x1129..0x1148 typedef int int; typedef char char; block #002, object at 0x5591f82cc490 under 0x5591f82cc580, 2 symbols in 0x112d..0x1148, function main int argc; computed at runtime char **argv; computed at runtime (gdb) x /4i 0x1129 0x1129 <foo>: mov %rdi,%rax 0x112c <foo+3>: ret 0x112d <main>: push %rbp 0x112e <main+1>: mov %rsp,%rbp In above case, the compunit clearly contains code at address 0x1129 so find_pc_sect_compunit_symtab() should return it. Then there's the issue with "holes" that dragged me down this rabbit hole. Consider situation like this (case B): Symtab for file py-compunit-2.c at 0x5642797d19b0 ... Blockvector: map 0x0 -> 0x0 0x80000 -> 0x55fcdd7fbb00 0x8000e -> 0x0 0xf00000 -> 0x55fcdd7fbcc0 0xf0000b -> 0x0 block #000, object at 0x5642797d1e80, 2 symbols in 0x80000..0xf0000b int give_me_zero(void); block object 0x5642797d1ba0, 0x80000..0x8000e section .text int give_me_one(void); block object 0x5642797d1d60, 0xf00000..0xf0000b section .text block #001, object at 0x5642797d1db0 under 0x5642797d1e80, 1 symbols in 0x80000..0xf0000b typedef int int; block #002, object at 0x5642797d1ba0 under 0x5642797d1db0, 0 symbols in 0x80000..0x8000e, function give_me_zero block #003, object at 0x5642797d1d60 under 0x5642797d1db0, 0 symbols in 0xf00000..0xf0000b, function give_me_one Symtab for file py-compunit-1.c at 0x5642797d1460 ... Blockvector: no map block #000, object at 0x5642797d1790, 1 symbols in 0x80625..0x80630 int main(void); block object 0x5642797d16a0, 0x80625..0x80630 section .text block #001, object at 0x5642797d16f0 under 0x5642797d1790, 1 symbols in 0x80625..0x80630 typedef int int; block #002, object at 0x5642797d16a0 under 0x5642797d16f0, 0 symbols in 0x80625..0x80630, function main There compunit2 has a "hole", its code is in two disjoint regions and compunit1's code is placed in between. But merely looking at compunit2 one cannot say whether there's a hole or a "free-standing code" like in case A.
Looking further into DWARF of the examples above, for case A, the "free-standing" code is captured by aranges: <0><c>: Abbrev Number: 3 (DW_TAG_compile_unit) <d> DW_AT_producer : (indirect string, offset: 0x5): GNU C23 15.2.0 -mtune=generic -march=x86-64 -g -fasynchronous-unwind-tables <11> DW_AT_language : 29 (C11) <12> Unknown AT value: 90: 3 <13> Unknown AT value: 91: 0x31647 <17> DW_AT_name : (indirect line string, offset: 0x2b): contains.c <1b> DW_AT_comp_dir : (indirect line string, offset: 0): /... <1f> DW_AT_low_pc : 0x1129 <27> DW_AT_high_pc : 0x1f <2f> DW_AT_stmt_list : 0 Contents of the .debug_aranges section: Length: 44 Version: 2 Offset into .debug_info: 0 Pointer Size: 8 Segment Size: 0 Address Length 0000000000001129 000000000000001f 0000000000000000 0000000000000000 Whereas in second case B, if I put some "free-standing" code before just function give_me_one, it is not covered in aranges: <0><71>: Abbrev Number: 1 (DW_TAG_compile_unit) <72> DW_AT_producer : (indirect string, offset: 0): GNU C23 15.2.0 -mtune=generic -march=x86-64 -g -fno-stack-protector -fasynchronous-unwind-tables <76> DW_AT_language : 29 (C11) <77> Unknown AT value: 90: 3 <78> Unknown AT value: 91: 0x31647 <7c> DW_AT_name : (indirect line string, offset: 0xc5): py-compunit-2.c <80> DW_AT_comp_dir : (indirect line string, offset: 0x50): /... <84> DW_AT_ranges : 0xc <88> DW_AT_low_pc : 0 <90> DW_AT_stmt_list : 0x55 ... <1><b9>: Abbrev Number: 4 (DW_TAG_subprogram) <ba> DW_AT_external : 1 <ba> DW_AT_name : (indirect string, offset: 0x73): give_me_one <be> DW_AT_decl_file : 1 <bf> DW_AT_decl_line : 25 <c0> DW_AT_decl_column : 1 <c1> DW_AT_prototyped : 1 <c1> DW_AT_type : <0xb2> <c5> DW_AT_low_pc : 0xf00004 <cd> DW_AT_high_pc : 0xb <d5> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa) <d7> DW_AT_call_all_calls: 1 Contents of the .debug_aranges section: Length: 44 Version: 2 Offset into .debug_info: 0 Pointer Size: 8 Segment Size: 0 Address Length 0000000000080625 000000000000000b 0000000000000000 0000000000000000 Length: 60 Version: 2 Offset into .debug_info: 0x65 Pointer Size: 8 Segment Size: 0 Address Length 0000000000f00004 000000000000000b 0000000000080000 000000000000000e 0000000000000000 0000000000000000 So I do not see the way to reliably tell case A from case B. Which makes me think perhaps I should just revert that commit. At the very least, what would make blockvector::lookup() and blockvector::contains() consistent (though not as in https://inbox.sourceware.org/gdb-patches/87ecpc93xk.fsf@tromey.com/).
(In reply to Jan Vrany from comment #12) > So I do not see the way to reliably tell case A from case B. This isn't something I am very familiar with so perhaps it's not a very good question, but can't you rely on a minimal symbol to point to the "freestanding" code? E.g., in your case A from comment #11, isn't there a "foo" minimal symbol whose addr + size covers that code?
(In reply to Thiago Jung Bauermann from comment #13) > (In reply to Jan Vrany from comment #12) > > So I do not see the way to reliably tell case A from case B. > > This isn't something I am very familiar with so perhaps it's not a very good Neither am I, really. > question, but can't you rely on a minimal symbol to point to the > "freestanding" code? > > E.g., in your case A from comment #11, isn't there a "foo" minimal symbol > whose addr + size covers that code? Yeah. I guess this is what find_compunit_symtab_for_pc_sect is trying to do (the code above the comment saying "Not found in symtabs, search"). The problem is that it only sees compunits that have been expanded. But even if we expand all CUs whose global blocks overlap given PC, then how to tell to which CU the minsymbol belongs? Imagine (rather extreme) situation like: 0x100 .. 0x200 f1 from CU1 0x201 .. 0x300 f2 from CU2 0x301 .. 0x350 "freestanding" code from CU1 0x351 .. 0x400 f3 crom CU1 0x401 .. 0x500 f1 from CU2 then CU1 is 0x100 .. 0x400 and CU2 is 0x201 .. 0x500 and how to tell where 0x301 belongs? But perhaps I'm missing something obvious...
I found out that if I force symtab expansion the test passes: diff --git a/gdb/testsuite/gdb.base/annota1.exp b/gdb/testsuite/gdb.base/annota1.exp index 56708c94d75..697902a6b99 100644 --- a/gdb/testsuite/gdb.base/annota1.exp +++ b/gdb/testsuite/gdb.base/annota1.exp @@ -347,6 +347,11 @@ if {[target_info exists gdb,nosignals]} { unsupported "send SIGUSR1" unsupported "backtrace @ signal handler" } else { + gdb_test_multiple "maint expand-symtabs" "expand-symtabs" { + -re .*$gdb_prompt$ { + pass $gdb_test_name + } + } gdb_test_multiple "signal SIGUSR1" "send SIGUSR1" { -re "\r\n\032\032post-prompt\r\nContinuing with signal SIGUSR1.\r\n\r\n\032\032starting\(\(\r\n\r\n\032\032frames-invalid\)|\(\r\n\r\n\032\032breakpoints-invalid\)\)+\r\n\r\n\032\032breakpoint 2\r\n\r\nBreakpoint 2, \r\n\032\032frame-begin 0 $hex\r\n\r\n\032\032frame-function-name\r\nhandle_USR1\r\n\032\032frame-args\r\n \\(\r\n\032\032arg-begin\r\nsig\r\n\032\032arg-name-end\r\n=\r\n\032\032arg-value -\r\n$decimal\r\n\032\032arg-end\r\n\\)\r\n\032\032frame-source-begin\r\n at \r\n\032\032frame-source-file\r\n${escapedsrcfile}\r\n\032\032frame-source-file-end\r\n:\r\n\032\032frame-source-line\r\n.*\r\n\032\032frame-source-end\r\n\r\n\r\n\032\032source.*annota1.c:.*:.*:beg:$hex\r\n\r\n\032\032frame-end\r\n\r\n\032\032stopped\r\n$gdb_prompt$" { pass $gdb_test_name
> ... if I force symtab expansion the test passes: This is because in that case, symtab for libc_sigaction.c is already expanded and the code in find_compunit_symtab_for_pc_sect() uses different logic to check if a CU contains given PC: if (bv->map () != nullptr) { if (bv->map ()->find (pc) == nullptr) continue; return &cust; } Interestingly, the map for that CU maps the particular PC to a static block: (top-gdb) p bv->m_map->transitions[0] $20 = { addr = 0x0, value = 0x0 } (top-gdb) p bv->m_map->transitions[1] $21 = { addr = 0x7ffff7c40580, value = 0x5560624992a0 } (top-gdb) p bv->m_blocks[1] $22 = (__gnu_cxx::__alloc_traits<std::allocator<block*>, block*>::value_type &) @0x5560621b2978: 0x5560624992a0 This was not the case in my example programs, see (my) comment #11.
The master branch has been updated by Jan Vrany <jv@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=777ed49815ee98690190b0478893ac225f1923eb commit 777ed49815ee98690190b0478893ac225f1923eb Author: Jan Vrany <jan.vrany@labware.com> Date: Thu Dec 25 18:12:06 2025 +0000 Revert "gdb: change blockvector::contains() to handle blockvectors with "holes"" This reverts commit cc1fc6af4150b19f9c4c70d0463ff498703fb637, since it causes a number of regressions that seem not to be easily fixable. The problem lies in existence of "freestanding" code, a code that is part of a CU but does not have any block associated with it. Consider following program: __asm__( ".type foo,@function \n" "foo: \n" " mov %rdi, %rax \n" " ret \n" ); static int foo(int i); int main(int argc, char **argv) { return foo(argc); } When compiled, the foo function has no block of itself: Blockvector: no map block #000, object at 0x55978957b510, 1 symbols in 0x1129..0x1148 int main(int, char **); block object 0x55978957b380, 0x112d..0x1148 section .text block #001, object at 0x55978957b470 under 0x55978957b510, 2 symbols in 0x1129..0x1148 typedef int int; typedef char char; block #002, object at 0x55978957b380 under 0x55978957b470, 2 symbols in 0x112d..0x1148, function main int argc; computed at runtime char **argv; computed at runtime In this case lookup(0x1129) returns static block and, because of the change in cc1fc6af4, contains(0x1129) which is wrong. Such "freestanding" code is perhaps not common but it does exist, especially in system code. In fact the regressions were at least in part caused by such "freestanding" code in glibc (libc_sigaction.c). The whole idea of commit cc1fc6af4 was to handle "holes" in CUs, a case where one CU spans over multiple disjoint regions, possibly interleaved with other CUs. Consider somewhat extreme case with two CUs: /* hole-1.c */ int give_me_zero (); int main () { return give_me_zero (); } /* hole-2.c */ int __attribute__ ((section (".text_give_me_one"))) __attribute__((noinline)) baz () { return 42; } __asm__( ".section .text_give_me_one,\"ax\",@progbits\n" ".type foo,@function \n" "foo: \n" " mov %rdi, %rax \n" " ret \n" " nop \n" " nop \n" " nop \n" ); int __attribute__ ((section (".text_give_me_one"))) __attribute__((noinline)) give_me_one () { return 1; } __asm__( ".section .text_give_me_zero,\"ax\",@progbits\n" "bar: \n" " jmp give_me_one \n" " nop \n" " nop \n" " nop \n" ); int __attribute__ ((section (".text_give_me_zero"))) give_me_zero () { extern int bar(); return give_me_one() - 1; } This when compiled with a carefully crafted linker script to force code at certain positions, creates following layout: 0x080000..0x080007 # "freestanding" bar from hole-2.c 0x080008..0x080016 # give_me_zero() from hole-2.c 0x080109..0x080114 # main from hole-1.c 0xf00000..0xf0000b # baz() from hole-2.c 0xf0000b..0xf00011 # "freestanding" foo from hole-2. 0xf0000b..0xf0001c # gice_me_one() from hole-2. The block vector for hole-1.c looks: Blockvector: no map block #000, object at 0x555a5d85fb90, 1 symbols in 0x80109..0x80114 int main(void); block object 0x555a5d85faa0, 0x80109..0x80114 section .text block #001, object at 0x555a5d85faf0 under 0x555a5d85fb90, 1 symbols in 0x80109..0x80114 typedef int int; block #002, object at 0x555a5d85faa0 under 0x555a5d85faf0, 0 symbols in 0x80109..0x80114, function main And for hole-2.c: Blockvector: map 0x0 -> 0x0 0x80008 -> 0x555a5d85ff50 0x80016 -> 0x0 0xf00000 -> 0x555a5d860280 0xf0000b -> 0x0 0xf00012 -> 0x555a5d860110 0xf0001d -> 0x0 block #000, object at 0x555a5d8603b0, 3 symbols in 0x80008..0xf0001d int give_me_zero(void); block object 0x555a5d85ff50, 0x80008..0x80016 section .text int give_me_one(void); block object 0x555a5d860110, 0xf00012..0xf0001d section .text int baz(void); block object 0x555a5d860280, 0xf00000..0xf0000b section .text block #001, object at 0x555a5d8602d0 under 0x555a5d8603b0, 1 symbols in 0x80008..0xf0001d typedef int int; block #002, object at 0x555a5d85ff50 under 0x555a5d8602d0, 0 symbols in 0x80008..0x80016, function give_me_zero block #003, object at 0x555a5d860280 under 0x555a5d8602d0, 0 symbols in 0xf00000..0xf0000b, function baz block #004, object at 0x555a5d860110 under 0x555a5d8602d0, 0 symbols in 0xf00012..0xf0001d, function give_me_one Note that despite the fact "freestanding" bar belongs to hole-2.c, the corresponding CU's global and static blocks start at 0x80008! Looking at DWARF for the second program, it looks like that the compiler (GCC 15) did not record the presence of "freestanding" code: <0><71>: Abbrev Number: 1 (DW_TAG_compile_unit) <72> DW_AT_producer : (indirect string, offset: 0): GNU C23 15.2.0 -mtune=generic -march=x86-64 -g -fasynchronous-unwind-tables <76> DW_AT_language : 29 (C11) <77> Unknown AT value: 90: 3 <78> Unknown AT value: 91: 0x31647 <7c> DW_AT_name : (indirect line string, offset: 0x2d): hole-2.c <80> DW_AT_comp_dir : (indirect line string, offset: 0): test_programs <84> DW_AT_ranges : 0xc <88> DW_AT_low_pc : 0 <90> DW_AT_stmt_list : 0x51 and corresponding part of .debug_aranges: Length: 76 Version: 2 Offset into .debug_info: 0x65 Pointer Size: 8 Segment Size: 0 Address Length 0000000000f00000 000000000000000b 0000000000f00012 000000000000000b 0000000000080008 000000000000000e 0000000000000000 0000000000000000 Thiago suggested to use minsymbols to tell whether or a CU contains given address. I do not think this would work reliably as minsymbols do no know to which CU they belong. In slightly more complicated case of interleaved CUs it does not seem to be possible to tell for sure to which one a given minsymbol belongs. Moreover, Tom suggested that the comment in find_compunit_symtab_for_pc_sect (which led to cc1fc6af4) may be outdated [2]. Given all that, I'm just reverting the change. [1]: https://sourceware.org/bugzilla/show_bug.cgi?id=33679#c13 [2]: https://inbox.sourceware.org/gdb-patches/87cy6xzd3j.fsf@tromey.com/ Approved-By: Tom Tromey <tom@tromey.com> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33679
Fixed.