Bug 33679 - [gdb] FAIL: gdb.base/annota1.exp: send SIGUSR1 (timeout)
Summary: [gdb] FAIL: gdb.base/annota1.exp: send SIGUSR1 (timeout)
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: gdb (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: 18.1
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2025-11-30 16:12 UTC by Tom de Vries
Modified: 2026-01-27 02:52 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
Project(s) to access:
ssh public key:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tom de Vries 2025-11-30 16:12:39 UTC
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
...
Comment 1 Tom de Vries 2025-11-30 19:14:14 UTC
Reproduces with Leap 16.0 as well.

Didn't reproduce with gdb-17-branch, I'll try a bisect.
Comment 2 Tom de Vries 2025-12-01 07:21:08 UTC
(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"").
Comment 3 Tom de Vries 2025-12-01 08:07:11 UTC
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;
     }
...
Comment 4 Tom de Vries 2025-12-01 09:43:03 UTC
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
...
Comment 5 Tom de Vries 2025-12-01 10:40:29 UTC
[ 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.
Comment 6 Tom Tromey 2025-12-04 16:22:31 UTC
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.
Comment 7 Jan Vrany 2025-12-04 17:03:31 UTC
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.
Comment 8 Tom de Vries 2025-12-04 20:08:32 UTC
(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.
Comment 9 Thiago Jung Bauermann 2025-12-04 22:13:03 UTC
(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
Comment 10 Jan Vrany 2025-12-05 07:19:04 UTC
(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.
Comment 11 Jan Vrany 2025-12-05 17:53:18 UTC
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.
Comment 12 Jan Vrany 2025-12-05 18:22:15 UTC
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/).
Comment 13 Thiago Jung Bauermann 2025-12-05 19:01:43 UTC
(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?
Comment 14 Jan Vrany 2025-12-05 21:27:42 UTC
(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...
Comment 15 Jan Vrany 2025-12-19 12:29:25 UTC
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
Comment 16 Jan Vrany 2025-12-19 19:22:01 UTC
> ... 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.
Comment 17 Sourceware Commits 2025-12-25 18:13:19 UTC
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
Comment 18 Tom de Vries 2025-12-26 15:55:56 UTC
Fixed.