public inbox for gdb-prs@sourceware.org
help / color / mirror / Atom feed
* [Bug gdb/29518] New: GDB doesn't handle DW_FORM_ref_addr DIE references correctly with .debug_types sections
@ 2022-08-24  7:12 clayborg at gmail dot com
  2022-08-24  7:13 ` [Bug gdb/29518] " clayborg at gmail dot com
  2022-08-24  7:29 ` clayborg at gmail dot com
  0 siblings, 2 replies; 3+ messages in thread
From: clayborg at gmail dot com @ 2022-08-24  7:12 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=29518

            Bug ID: 29518
           Summary: GDB doesn't handle DW_FORM_ref_addr DIE references
                    correctly with .debug_types sections
           Product: gdb
           Version: HEAD
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: gdb
          Assignee: unassigned at sourceware dot org
          Reporter: clayborg at gmail dot com
  Target Milestone: ---

Created attachment 14292
  --> https://sourceware.org/bugzilla/attachment.cgi?id=14292&action=edit
Binary that reproduces the bug.

We have binaries that have .debug_types sections, so they are compiled with
DWARF4 or earlier, and they use DW_FORM_ref_addr for DIE references. These
DW_FORM_ref_addr are added by an LTO pass. When we load these binaries into
GDB, we end up with internal errors like:

Dwarf Error: Cannot find DIE at 0x37a8eb8

Or we can run into an internal error where we find a type unit that contains
the offset incorrectly:

../../binutils-gdb/gdb/dwarf2/read.c:7702: internal-error: load_full_comp_unit:
Assertion `! this_cu->is_debug_types' failed.



I found the root cause: for each DWARF there is a "dwarf2_per_bfd" structure
defined in gdb/dwarf2/read.h that has a member:

  /* Table of all the compilation units.  This is used to locate
     the target compilation unit of a particular reference.  */
  std::vector<dwarf2_per_cu_data_up> all_comp_units;

This member gets populated with all units from the .debug_info, and if there
are one or more .debug_types sections, they get appended to this list. The
issue is if we ever need to locate a referenced DIE that uses DW_FORM_ref_addr,
which is an absolute offset in the .debug_info, it will end up binary searching
for the containing compile unit in dwarf2_find_containing_comp_unit(...). This
function uses the dwarf2_per_bfd::all_comp_units vector, which is assumed to be
sorted. But since it has both entries from the .debug_info (which start with
offset zero and increase) and any .debug_types sections (which also start with
a section offset of zero and increase), this list is no longer sorted and a
binary search can fail can cause a the "Dwarf Error: Cannot find DIE at"
errors.

This only happens when you have an attribute that uses DW_FORM_ref_addr. Most
references in DWARF use a compile unit related offset like DW_FORM_ref4, so
this is the main reason this issue has not been seen a lot. Our LTO introduces
these absolute references into the DWARF.

Another thing to note is that any type unit from a .debug_types section, or
ones from DWARF5 that are in the .debug_info section, are never searched for by
DIE offset. Type units are only referenced via their type signature which can
easily map to the right type unit. So "all_comp_units" is being used as storage
for the dwarf2_per_cu_data_up and then being used in a binary search, but any
type units should never need to actually be in this list.

I have a quick fix that adds an extra entry to the "dwarf2_per_bfd" structure
that is the index of the last debug info entry from .debug_info. Then it
modifies dwarf2_find_containing_comp_unit(...) to use this index as a high
index when doing the binary search. I don't know GDB's DWARF parser well enough
to know if this is the correct fix. 

I will attach my quick fix in case this helps, but would appreciate any
guidance or help it getting this fixed the right way.

I have a reproduction case attached as a "b.out" binary. To reproduce the
issue:
$ gdb b.out
(gdb) maintenance print type main
../../binutils-gdb/gdb/dwarf2/read.c:7702: internal-error: load_full_comp_unit:
Assertion `! this_cu->is_debug_types' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
----- Backtrace -----
0x50a5fc gdb_internal_backtrace_1
        ../../binutils-gdb/gdb/bt-utils.c:122
0x50a69f _Z22gdb_internal_backtracev
        ../../binutils-gdb/gdb/bt-utils.c:168
0xa401bb internal_vproblem
        ../../binutils-gdb/gdb/utils.c:396
0xa4058a _Z15internal_verrorPKciS0_P13__va_list_tag
        ../../binutils-gdb/gdb/utils.c:476
0xbdf9de _Z14internal_errorPKciS0_z
        ../../binutils-gdb/gdbsupport/errors.cc:55
0x65f816 load_full_comp_unit
        ../../binutils-gdb/gdb/dwarf2/read.c:7702
0x685619 follow_die_offset
        ../../binutils-gdb/gdb/dwarf2/read.c:22307
0x68575e follow_die_ref
        ../../binutils-gdb/gdb/dwarf2/read.c:22340
0x683906 lookup_die_type
        ../../binutils-gdb/gdb/dwarf2/read.c:21460
0x683472 die_type
        ../../binutils-gdb/gdb/dwarf2/read.c:21320
0x6778fc read_subroutine_type
        ../../binutils-gdb/gdb/dwarf2/read.c:16524
0x683a3b read_type_die_1
        ../../binutils-gdb/gdb/dwarf2/read.c:21519
0x6839b5 read_type_die
        ../../binutils-gdb/gdb/dwarf2/read.c:21494
0x66b028 read_func_scope
        ../../binutils-gdb/gdb/dwarf2/read.c:12047
0x662956 process_die
        ../../binutils-gdb/gdb/dwarf2/read.c:8648
0x664980 read_file_scope
        ../../binutils-gdb/gdb/dwarf2/read.c:9634
0x6628d3 process_die
        ../../binutils-gdb/gdb/dwarf2/read.c:8635
0x662057 process_full_comp_unit
        ../../binutils-gdb/gdb/dwarf2/read.c:8404
0x65f6a2 process_queue
        ../../binutils-gdb/gdb/dwarf2/read.c:7650
0x6513f1 dw2_do_instantiate_symtab
        ../../binutils-gdb/gdb/dwarf2/read.c:2063
0x65149a dw2_instantiate_symtab
        ../../binutils-gdb/gdb/dwarf2/read.c:2085
0x656911 dw2_expand_symtabs_matching_one
        ../../binutils-gdb/gdb/dwarf2/read.c:3977
0x67d671
_ZN22cooked_index_functions23expand_symtabs_matchingEP7objfileN3gdb13function_viewIFbPKcbEEEPK16lookup_name_infoNS3_IFbS5_EEENS3_IFbP15compunit_symtabEEE10enum_flagsI24block_search_flag_valuesE11domain_enum13search_domain
        ../../binutils-gdb/gdb/dwarf2/read.c:18739
0x936d8f _ZN7objfile13lookup_symbolE10block_enumPKc11domain_enum
        ../../binutils-gdb/gdb/symfile-debug.c:276
0x9558c5 lookup_symbol_via_quick_fns
        ../../binutils-gdb/gdb/symtab.c:2451
0x955d16 lookup_symbol_in_objfile
        ../../binutils-gdb/gdb/symtab.c:2600
0x955e7d operator()
        ../../binutils-gdb/gdb/symtab.c:2666
0x96166b operator()
        ../../binutils-gdb/gdb/../gdbsupport/function-view.h:304
0x961692 _FUN
        ../../binutils-gdb/gdb/../gdbsupport/function-view.h:298
0x84dd25 _ZNK3gdb13function_viewIFbP7objfileEEclES2_
        ../../binutils-gdb/gdb/../gdbsupport/function-view.h:288
0x90392e svr4_iterate_over_objfiles_in_search_order
        ../../binutils-gdb/gdb/solib-svr4.c:3161
0x49c1b3
_Z45gdbarch_iterate_over_objfiles_in_search_orderP7gdbarchN3gdb13function_viewIFbP7objfileEEES4_
        ../../binutils-gdb/gdb/gdbarch.c:5027
0x956007 lookup_global_or_static_symbol
        ../../binutils-gdb/gdb/symtab.c:2662
0x956170 _Z20lookup_global_symbolPKcPK5block11domain_enum
        ../../binutils-gdb/gdb/symtab.c:2717
0x5c86f9 cp_lookup_bare_symbol
        ../../binutils-gdb/gdb/cp-namespace.c:205
0x5c969a lookup_namespace_scope
        ../../binutils-gdb/gdb/cp-namespace.c:719
0x5c97c5 _Z25cp_lookup_symbol_nonlocalPK13language_defnPKcPK5block11domain_enum
        ../../binutils-gdb/gdb/cp-namespace.c:754
0x5449ad _ZNK14cplus_language22lookup_symbol_nonlocalEPKcPK5block11domain_enum
        ../../binutils-gdb/gdb/c-lang.c:997
0x954eb7 lookup_symbol_aux
        ../../binutils-gdb/gdb/symtab.c:2170
0x954668
_Z25lookup_symbol_in_languagePKcPK5block11domain_enum8languageP20field_of_this_result
        ../../binutils-gdb/gdb/symtab.c:1965
0x9546e2 _Z13lookup_symbolPKcPK5block11domain_enumP20field_of_this_result
        ../../binutils-gdb/gdb/symtab.c:1977
0x5282ca classify_name
        ../../binutils-gdb/gdb/c-exp.y:3046
0x528968 c_yylex
        ../../binutils-gdb/gdb/c-exp.y:3255
0x51ff8b _Z9c_yyparsev
        /home/gclayton/local/gdb/Debug/gdb/c-exp.c.tmp:1991
0x529427 _Z7c_parseP12parser_state
        ../../binutils-gdb/gdb/c-exp.y:3421
0x7930a3 _ZNK13language_defn6parserEP12parser_state
        ../../binutils-gdb/gdb/language.c:623
0x862973 parse_exp_in_context
        ../../binutils-gdb/gdb/parse.c:515
0x862b4f _Z16parse_expressionPKcP23innermost_block_trackerb
        ../../binutils-gdb/gdb/parse.c:551
0x9f16de _Z22maintenance_print_typePKci
        ../../binutils-gdb/gdb/typeprint.c:709
0x55e2a9 do_simple_func
        ../../binutils-gdb/gdb/cli/cli-decode.c:95
0x562ed5 _Z8cmd_funcP16cmd_list_elementPKci
        ../../binutils-gdb/gdb/cli/cli-decode.c:2516
0x9aa0a2 _Z15execute_commandPKci
        ../../binutils-gdb/gdb/top.c:699
0x6d8250 _Z15command_handlerPKc
        ../../binutils-gdb/gdb/event-top.c:598
0x6d86f7 _Z20command_line_handlerOSt10unique_ptrIcN3gdb13xfree_deleterIcEEE
        ../../binutils-gdb/gdb/event-top.c:842
0x9d2fd7 tui_command_line_handler
        ../../binutils-gdb/gdb/tui/tui-interp.c:104
0x6d7a50 gdb_rl_callback_handler
        ../../binutils-gdb/gdb/event-top.c:230
0xaa6f10 rl_callback_read_char
        ../../../binutils-gdb/readline/readline/callback.c:290
0x6d78cd gdb_rl_callback_read_char_wrapper_noexcept
        ../../binutils-gdb/gdb/event-top.c:188
0x6d7954 gdb_rl_callback_read_char_wrapper
        ../../binutils-gdb/gdb/event-top.c:205
0x6d80a1 _Z19stdin_event_handleriPv
        ../../binutils-gdb/gdb/event-top.c:525
0xbe06ef handle_file_event
        ../../binutils-gdb/gdbsupport/event-loop.cc:549
0xbe0c77 gdb_wait_for_event
        ../../binutils-gdb/gdbsupport/event-loop.cc:670
0xbdfb86 _Z16gdb_do_one_eventv
        ../../binutils-gdb/gdbsupport/event-loop.cc:235
0x7e2d47 start_event_loop
        ../../binutils-gdb/gdb/main.c:411
0x7e2e67 captured_command_loop
        ../../binutils-gdb/gdb/main.c:471
0x7e4635 captured_main
        ../../binutils-gdb/gdb/main.c:1329
0x7e469b _Z8gdb_mainP18captured_main_args
        ../../binutils-gdb/gdb/main.c:1344
0x40de2c main
        ../../binutils-gdb/gdb/gdb.c:32
---------------------
../../binutils-gdb/gdb/dwarf2/read.c:7702: internal-error: load_full_comp_unit:
Assertion `! this_cu->is_debug_types' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) y


The .debug_info has been modified to have a DW_FORM_ref_addr on the first
subprogram:

0x0000002a:   DW_TAG_subprogram [7] *
                DW_AT_low_pc [DW_FORM_addr]     (0x0000000000000630)
                DW_AT_high_pc [DW_FORM_data4]   (0x0000007c)
                DW_AT_frame_base [DW_FORM_exprloc]      (DW_OP_reg6 RBP)
                DW_AT_name [DW_FORM_strp]       ( .debug_str[0x000000ca] =
"main")
                DW_AT_decl_file [DW_FORM_data1]
("/home/gclayton/local/debug-types-absolute-refs/main.cpp")
                DW_AT_decl_line [DW_FORM_data1] (24)
                DW_AT_type [DW_FORM_ref_addr]   (0x0000000000000122 "int")
                DW_AT_external [DW_FORM_flag_present]   (true)

which points to a "int" type in another compile unit:

0x00000122:   DW_TAG_base_type [3]  
                DW_AT_name [DW_FORM_strp]       ( .debug_str[0x000000e7] =
"int")
                DW_AT_encoding [DW_FORM_data1]  (DW_ATE_signed)
                DW_AT_byte_size [DW_FORM_data1] (0x04)

This program also has enough types in .debug_types to trigger the bug and cause
the binary search to actually succeed but find the wrong thing: it finds a type
unit.


In case I can't attach the gdb patch I will include it here:

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 84faeb45238..c8c0628e979 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2703,6 +2703,8 @@ dwarf2_read_gdb_index
   create_cus_from_index (per_bfd, cu_list, cu_list_elements, dwz_list,
                         dwz_list_elements);

+  per_bfd->last_debug_info_unit_idx = per_bfd->all_comp_units.size() - 1;
+
   if (types_list_elements)
     {
       /* We can only handle a single .debug_types when we have an
@@ -7263,6 +7265,9 @@ create_all_comp_units (dwarf2_per_objfile *per_objfile)
   read_comp_units_from_section (per_objfile, &per_objfile->per_bfd->info,
                                &per_objfile->per_bfd->abbrev, 0,
                                types_htab, rcuh_kind::COMPILE);
+
+  per_objfile->per_bfd->last_debug_info_unit_idx =
per_objfile->per_bfd->all_comp_units.size() - 1;
+
   for (dwarf2_section_info &section : per_objfile->per_bfd->types)
     read_comp_units_from_section (per_objfile, &section,
                                  &per_objfile->per_bfd->abbrev, 0,
@@ -7350,7 +7355,7 @@ skip_children (const struct die_reader_specs *reader,
const gdb_byte *info_ptr)
    INFO_PTR should point just after the initial uleb128 of a DIE, and the
    abbrev corresponding to that skipped uleb128 should be passed in
    ABBREV.
-   
+
    If DO_SKIP_CHILDREN is true, or if the DIE has no children, this
    returns a pointer to this DIE's sibling, skipping any children.
    Otherwise, returns a pointer to the DIE's first child.  */
@@ -23490,12 +23495,14 @@ static int
 dwarf2_find_containing_comp_unit
   (sect_offset sect_off,
    unsigned int offset_in_dwz,
-   const std::vector<dwarf2_per_cu_data_up> &all_comp_units)
+   const std::vector<dwarf2_per_cu_data_up> &all_comp_units, int high = -1)
 {
-  int low, high;
+  int low;

   low = 0;
-  high = all_comp_units.size () - 1;
+  if (high == -1)
+    high = all_comp_units.size() - 1;
+
   while (high > low)
     {
       struct dwarf2_per_cu_data *mid_cu;
@@ -23522,7 +23529,8 @@ dwarf2_find_containing_comp_unit (sect_offset sect_off,
                                  dwarf2_per_bfd *per_bfd)
 {
   int low = dwarf2_find_containing_comp_unit
-    (sect_off, offset_in_dwz, per_bfd->all_comp_units);
+    (sect_off, offset_in_dwz, per_bfd->all_comp_units,
+     per_bfd->last_debug_info_unit_idx);
   dwarf2_per_cu_data *this_cu = per_bfd->all_comp_units[low].get ();

   if (this_cu->is_dwz != offset_in_dwz || this_cu->sect_off > sect_off)
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index c2f86a9d367..c6e0376a48c 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -491,6 +491,7 @@ struct dwarf2_per_bfd
      the target compilation unit of a particular reference.  */
   std::vector<dwarf2_per_cu_data_up> all_comp_units;

+  size_t last_debug_info_unit_idx = 0;
   /* Table of struct type_unit_group objects.
      The hash key is the DW_AT_stmt_list value.  */
   htab_up type_unit_groups;

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Bug gdb/29518] GDB doesn't handle DW_FORM_ref_addr DIE references correctly with .debug_types sections
  2022-08-24  7:12 [Bug gdb/29518] New: GDB doesn't handle DW_FORM_ref_addr DIE references correctly with .debug_types sections clayborg at gmail dot com
@ 2022-08-24  7:13 ` clayborg at gmail dot com
  2022-08-24  7:29 ` clayborg at gmail dot com
  1 sibling, 0 replies; 3+ messages in thread
From: clayborg at gmail dot com @ 2022-08-24  7:13 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=29518

--- Comment #1 from Greg Clayton <clayborg at gmail dot com> ---
Created attachment 14293
  --> https://sourceware.org/bugzilla/attachment.cgi?id=14293&action=edit
Patch that fixes absolute die lookups

This is a simple patch that fixes the bug, though I don't know enough about the
GDB DWARF parser to know if this is the correct fix.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Bug gdb/29518] GDB doesn't handle DW_FORM_ref_addr DIE references correctly with .debug_types sections
  2022-08-24  7:12 [Bug gdb/29518] New: GDB doesn't handle DW_FORM_ref_addr DIE references correctly with .debug_types sections clayborg at gmail dot com
  2022-08-24  7:13 ` [Bug gdb/29518] " clayborg at gmail dot com
@ 2022-08-24  7:29 ` clayborg at gmail dot com
  1 sibling, 0 replies; 3+ messages in thread
From: clayborg at gmail dot com @ 2022-08-24  7:29 UTC (permalink / raw)
  To: gdb-prs

https://sourceware.org/bugzilla/show_bug.cgi?id=29518

--- Comment #2 from Greg Clayton <clayborg at gmail dot com> ---
Another way to fix this would be to artificially increase the "sect_offset" of
any type units from .debug_types that are added to the
"dwarf2_per_bfd::all_comp_units" to start at sizeof(.debug_info) + .debug_types
offset. If there are multiple .debug_types sections, then you would need to
increase any subsequent ones by the previous sizes. Since type units can only
have CU relative references and there is nothing that can reference anything
inside of the type unit from outside the type unit, it would most likely be
harmless. This would allow the "dwarf2_per_bfd::all_comp_units" to stay sorted
as things are added.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-08-24  7:29 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-24  7:12 [Bug gdb/29518] New: GDB doesn't handle DW_FORM_ref_addr DIE references correctly with .debug_types sections clayborg at gmail dot com
2022-08-24  7:13 ` [Bug gdb/29518] " clayborg at gmail dot com
2022-08-24  7:29 ` clayborg at gmail dot com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).