From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 87040385703F; Wed, 24 Aug 2022 07:12:10 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 87040385703F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1661325130; bh=cWo/HC+cQcd72Fhxpz/JY35JXxBmrUAWkZ2/i/CB2AA=; h=From:To:Subject:Date:From; b=lILcDVZ9o+qFVWWk5GufSPPL4rI8DKZyd2+wHD7UthD9ppO6GmubwBEGcuzxNGB45 ioib0lyBTJQ1jcWtoX1WsMrNSrJfAK2SiZDMRNUVVoLZcQBgw2CBBH+zVwdBe5iDD9 GCYZwT7+YPp3tLbkfgjCiUssGzWRuXaumj3HT/Wg= From: "clayborg at gmail dot com" To: gdb-prs@sourceware.org Subject: [Bug gdb/29518] New: GDB doesn't handle DW_FORM_ref_addr DIE references correctly with .debug_types sections Date: Wed, 24 Aug 2022 07:12:09 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gdb X-Bugzilla-Component: gdb X-Bugzilla-Version: HEAD X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: clayborg at gmail dot com X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Resolution: X-Bugzilla-Priority: P2 X-Bugzilla-Assigned-To: unassigned at sourceware dot org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version bug_status bug_severity priority component assigned_to reporter target_milestone attachments.created Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://sourceware.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 List-Id: https://sourceware.org/bugzilla/show_bug.cgi?id=3D29518 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=3D14292&action=3Ded= it 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_u= nit: 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 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_a= ddr, which is an absolute offset in the .debug_info, it will end up binary searc= hing for the containing compile unit in dwarf2_find_containing_comp_unit(...). T= his function uses the dwarf2_per_bfd::all_comp_units vector, which is assumed t= o 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 w= ith 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. Mo= st 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 introdu= ces 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 fo= r by DIE offset. Type units are only referenced via their type signature which c= an easily map to the right type unit. So "all_comp_units" is being used as sto= rage for the dwarf2_per_cu_data_up and then being used in a binary search, but a= ny 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" structu= re 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 en= ough to know if this is the correct fix.=20 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_u= nit: 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_matchingEP7objfileN3gdb13functi= on_viewIFbPKcbEEEPK16lookup_name_infoNS3_IFbS5_EEENS3_IFbP15compunit_symtab= EEE10enum_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_v= iewIFbP7objfileEEES4_ ../../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_e= num ../../binutils-gdb/gdb/c-lang.c:997 0x954eb7 lookup_symbol_aux ../../binutils-gdb/gdb/symtab.c:2170 0x954668 _Z25lookup_symbol_in_languagePKcPK5block11domain_enum8languageP20field_of_t= his_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_u= nit: 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] =3D "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]=20=20 DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000e7] =3D "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 c= ause 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 =3D 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_objfil= e) 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 =3D per_objfile->per_bfd->all_comp_units.size() - 1; + for (dwarf2_section_info §ion : per_objfile->per_bfd->types) read_comp_units_from_section (per_objfile, §ion, &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. -=20=20=20 + 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 &all_comp_units) + const std::vector &all_comp_units, int high =3D = -1) { - int low, high; + int low; low =3D 0; - high =3D all_comp_units.size () - 1; + if (high =3D=3D -1) + high =3D 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 =3D 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 =3D per_bfd->all_comp_units[low].get (); if (this_cu->is_dwz !=3D 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 all_comp_units; + size_t last_debug_info_unit_idx =3D 0; /* Table of struct type_unit_group objects. The hash key is the DW_AT_stmt_list value. */ htab_up type_unit_groups; --=20 You are receiving this mail because: You are on the CC list for the bug.=