From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gnu.wildebeest.org (gnu.wildebeest.org [45.83.234.184]) by sourceware.org (Postfix) with ESMTPS id 4AC6F3858409 for ; Tue, 10 Jan 2023 17:45:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4AC6F3858409 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=klomp.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=klomp.org Received: from r6.localdomain (83-87-18-245.cable.dynamic.v4.ziggo.nl [83.87.18.245]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id E76DD302BBEC; Tue, 10 Jan 2023 18:45:13 +0100 (CET) Received: by r6.localdomain (Postfix, from userid 1000) id B93B8340264; Tue, 10 Jan 2023 18:45:13 +0100 (CET) From: Mark Wielaard To: elfutils-devel@sourceware.org Cc: =?UTF-8?q?Martin=20Li=C5=A1ka?= , Mark Wielaard Subject: [PATCH] readelf: Check compression status of .debug section data Date: Tue, 10 Jan 2023 18:44:57 +0100 Message-Id: <20230110174457.524148-1-mark@klomp.org> X-Mailer: git-send-email 2.39.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3038.3 required=5.0 tests=BAYES_00,GIT_PATCH_0,JMQ_SPF_NEUTRAL,KAM_DMARC_STATUS,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: The various print_debug_*_section functions didn't get the section data in the same way. Add a new get_debug_elf_data function that gets the (possibly relocated) section data and that checks (and warns) if the data might still be compressed in a way that we cannot decompress. Signed-off-by: Mark Wielaard --- src/ChangeLog | 19 +++++ src/readelf.c | 213 ++++++++++++++++++++++++++------------------------ 2 files changed, 130 insertions(+), 102 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index db8a81ee..0490088e 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,22 @@ +2023-01-10 Mark Wielaard + + * readelf.c (get_debug_elf_data): New function. + (print_debug_abbrev_section): Use get_debug_elf_data. + (print_debug_addr_section): Likewise. + (print_debug_aranges_section): Likewise. + (print_debug_rnglists_section): Likewise. + (print_debug_ranges_section): Likewise. + (print_debug_frame_section): Likewise. + (print_debug_units): Likewise. + (print_debug_line_section): Likewise. + (print_debug_loclists_section): Likewise. + (print_debug_loc_section): Likewise. + (print_debug_macinfo_section): Likewise. + (print_debug_macro_section): Likewise. + (print_debug_str_section): Likewise. + (print_debug_str_offsets_section): Likewise. + (print_debug_pubnames_section): Likewise. + 2022-12-21 Shahab Vahedi * elflint.c (valid_e_machine): Add EM_ARCV2. diff --git a/src/readelf.c b/src/readelf.c index 451f8400..51b0e8b9 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -3857,6 +3857,39 @@ print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr) } } +/* Returns either the (relocated) data from the Dwarf, or tries to get + the "raw" (uncompressed) data from the Elf section. Produces a + warning if the data cannot be found (or decompressed). */ +static Elf_Data * +get_debug_elf_data (Dwarf *dbg, Ebl *ebl, int idx, Elf_Scn *scn) +{ + /* We prefer to get the section data from the Dwarf because that + might have been relocated already. Note this is subtly wrong if + there are multiple sections with the same .debug name. */ + if (dbg->sectiondata[idx] != NULL) + return dbg->sectiondata[idx]; + + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL && (shdr->sh_flags & SHF_COMPRESSED) != 0) + { + if (elf_compress (scn, 0, 0) < 0) + { + error (0, 0, "%s [%zd] '%s'\n", + _("Couldn't uncompress section"), + elf_ndxscn (scn), section_name (ebl, shdr)); + return NULL; + } + } + + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL) + error (0, 0, "%s [%zd] '%s': %s\n", + _("Couldn't get data from section"), + elf_ndxscn (scn), section_name (ebl, shdr), elf_errmsg (-1)); + + return elf_getdata (scn, NULL); +} void print_dwarf_addr (Dwfl_Module *dwflmod, @@ -5271,8 +5304,11 @@ print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)), Ebl *ebl, GElf_Ehdr *ehdr __attribute__ ((unused)), Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { - const size_t sh_size = (dbg->sectiondata[IDX_debug_abbrev] ? - dbg->sectiondata[IDX_debug_abbrev]->d_size : 0); + Elf_Data *elf_data = get_debug_elf_data (dbg, ebl, IDX_debug_abbrev, scn); + if (elf_data == NULL) + return; + + const size_t sh_size = elf_data->d_size; printf (_("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n" " [ Code]\n"), @@ -5344,6 +5380,10 @@ print_debug_addr_section (Dwfl_Module *dwflmod __attribute__ ((unused)), Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { + Elf_Data *data = get_debug_elf_data (dbg, ebl, IDX_debug_addr, scn); + if (data == NULL) + return; + printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), elf_ndxscn (scn), section_name (ebl, shdr), @@ -5352,16 +5392,6 @@ print_debug_addr_section (Dwfl_Module *dwflmod __attribute__ ((unused)), if (shdr->sh_size == 0) return; - /* We like to get the section from libdw to make sure they are relocated. */ - Elf_Data *data = (dbg->sectiondata[IDX_debug_addr] - ?: elf_rawdata (scn, NULL)); - if (unlikely (data == NULL)) - { - error (0, 0, _("cannot get .debug_addr section data: %s"), - elf_errmsg (-1)); - return; - } - size_t idx = 0; sort_listptr (&known_addrbases, "addr_base"); @@ -5643,15 +5673,9 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)), return; } - Elf_Data *data = (dbg->sectiondata[IDX_debug_aranges] - ?: elf_rawdata (scn, NULL)); - - if (unlikely (data == NULL)) - { - error (0, 0, _("cannot get .debug_aranges content: %s"), - elf_errmsg (-1)); - return; - } + Elf_Data *data = get_debug_elf_data (dbg, ebl, IDX_debug_aranges, scn); + if (data == NULL) + return; printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), @@ -5820,20 +5844,15 @@ print_debug_rnglists_section (Dwfl_Module *dwflmod, Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg __attribute__((unused))) { + Elf_Data *data = get_debug_elf_data (dbg, ebl, IDX_debug_rnglists, scn); + if (data == NULL) + return; + printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), elf_ndxscn (scn), section_name (ebl, shdr), (uint64_t) shdr->sh_offset); - Elf_Data *data =(dbg->sectiondata[IDX_debug_rnglists] - ?: elf_rawdata (scn, NULL)); - if (unlikely (data == NULL)) - { - error (0, 0, _("cannot get .debug_rnglists content: %s"), - elf_errmsg (-1)); - return; - } - /* For the listptr to get the base address/CU. */ sort_listptr (&known_rnglistptr, "rnglistptr"); size_t listptr_idx = 0; @@ -6196,14 +6215,9 @@ print_debug_ranges_section (Dwfl_Module *dwflmod, Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { - Elf_Data *data = (dbg->sectiondata[IDX_debug_ranges] - ?: elf_rawdata (scn, NULL)); - if (unlikely (data == NULL)) - { - error (0, 0, _("cannot get .debug_ranges content: %s"), - elf_errmsg (-1)); - return; - } + Elf_Data *data = get_debug_elf_data (dbg, ebl, IDX_debug_ranges, scn); + if (data == NULL) + return; printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), @@ -6804,16 +6818,22 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, } bool is_eh_frame = strcmp (scnname, ".eh_frame") == 0; - Elf_Data *data = (is_eh_frame - ? elf_rawdata (scn, NULL) - : (dbg->sectiondata[IDX_debug_frame] - ?: elf_rawdata (scn, NULL))); - - if (unlikely (data == NULL)) + Elf_Data *data; + if (is_eh_frame) { - error (0, 0, _("cannot get %s content: %s"), - scnname, elf_errmsg (-1)); - return; + data = elf_rawdata (scn, NULL); + if (data == NULL) + { + error (0, 0, _("cannot get %s content: %s"), + scnname, elf_errmsg (-1)); + return; + } + } + else + { + data = get_debug_elf_data (dbg, ebl, IDX_debug_frame, scn); + if (data == NULL) + return; } if (is_eh_frame) @@ -7912,6 +7932,13 @@ print_debug_units (Dwfl_Module *dwflmod, const bool silent = !(print_debug_sections & section_info) && !debug_types; const char *secname = section_name (ebl, shdr); + /* Check section actually exists. */ + if (!silent) + if (get_debug_elf_data (dbg, ebl, + debug_types ? IDX_debug_types : IDX_debug_info, + scn) == NULL) + return; + if (!silent) printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n [Offset]\n"), @@ -8576,6 +8603,10 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, return; } + Elf_Data *data = get_debug_elf_data (dbg, ebl, IDX_debug_line, scn); + if (data == NULL) + return; + printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), elf_ndxscn (scn), section_name (ebl, shdr), @@ -8586,14 +8617,6 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, /* There is no functionality in libdw to read the information in the way it is represented here. Hardcode the decoder. */ - Elf_Data *data = (dbg->sectiondata[IDX_debug_line] - ?: elf_rawdata (scn, NULL)); - if (unlikely (data == NULL)) - { - error (0, 0, _("cannot get line data section data: %s"), - elf_errmsg (-1)); - return; - } const unsigned char *linep = (const unsigned char *) data->d_buf; const unsigned char *lineendp; @@ -9322,20 +9345,15 @@ print_debug_loclists_section (Dwfl_Module *dwflmod, Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { + Elf_Data *data = get_debug_elf_data (dbg, ebl, IDX_debug_loclists, scn); + if (data == NULL) + return; + printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), elf_ndxscn (scn), section_name (ebl, shdr), (uint64_t) shdr->sh_offset); - Elf_Data *data = (dbg->sectiondata[IDX_debug_loclists] - ?: elf_rawdata (scn, NULL)); - if (unlikely (data == NULL)) - { - error (0, 0, _("cannot get .debug_loclists content: %s"), - elf_errmsg (-1)); - return; - } - /* For the listptr to get the base address/CU. */ sort_listptr (&known_loclistsptr, "loclistsptr"); size_t listptr_idx = 0; @@ -9795,15 +9813,9 @@ print_debug_loc_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { - Elf_Data *data = (dbg->sectiondata[IDX_debug_loc] - ?: elf_rawdata (scn, NULL)); - - if (unlikely (data == NULL)) - { - error (0, 0, _("cannot get .debug_loc content: %s"), - elf_errmsg (-1)); - return; - } + Elf_Data *data = get_debug_elf_data (dbg, ebl, IDX_debug_loc, scn); + if (data == NULL) + return; printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), @@ -10056,6 +10068,10 @@ print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)), GElf_Ehdr *ehdr __attribute__ ((unused)), Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { + Elf_Data *data = get_debug_elf_data (dbg, ebl, IDX_debug_macinfo, scn); + if (data == NULL) + return; + printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), elf_ndxscn (scn), section_name (ebl, shdr), @@ -10064,14 +10080,6 @@ print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)), /* There is no function in libdw to iterate over the raw content of the section but it is easy enough to do. */ - Elf_Data *data = (dbg->sectiondata[IDX_debug_macinfo] - ?: elf_rawdata (scn, NULL)); - if (unlikely (data == NULL)) - { - error (0, 0, _("cannot get macro information section data: %s"), - elf_errmsg (-1)); - return; - } /* Get the source file information for all CUs. */ Dwarf_Off offset; @@ -10222,20 +10230,16 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)), GElf_Ehdr *ehdr __attribute__ ((unused)), Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { + Elf_Data *data = get_debug_elf_data (dbg, ebl, IDX_debug_macro, scn); + if (data == NULL) + return; + printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), elf_ndxscn (scn), section_name (ebl, shdr), (uint64_t) shdr->sh_offset); putc_unlocked ('\n', stdout); - Elf_Data *data = elf_getdata (scn, NULL); - if (unlikely (data == NULL)) - { - error (0, 0, _("cannot get macro information section data: %s"), - elf_errmsg (-1)); - return; - } - /* Get the source file information for all CUs. Uses same datastructure as macinfo. But uses offset field to directly match .debug_line offset. And just stored in a list. */ @@ -10609,6 +10613,10 @@ print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)), GElf_Ehdr *ehdr __attribute__ ((unused)), Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { + /* Check section actually exists. */ + if (get_debug_elf_data (dbg, ebl, IDX_debug_pubnames, scn) == NULL) + return; + printf (_("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), elf_ndxscn (scn), section_name (ebl, shdr), (uint64_t) shdr->sh_offset); @@ -10617,7 +10625,8 @@ print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)), (void) dwarf_getpubnames (dbg, print_pubnames, &n, 0); } -/* Print the content of the DWARF string section '.debug_str'. */ +/* Print the content of the DWARF string section '.debug_str' + or 'debug_line_str'. */ static void print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)), Ebl *ebl, @@ -10625,8 +10634,14 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)), Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg __attribute__ ((unused))) { - Elf_Data *data = elf_rawdata (scn, NULL); - const size_t sh_size = data ? data->d_size : 0; + const char *name = section_name (ebl, shdr); + int idx = ((name != NULL && strstr (name, "debug_line_str") != NULL) + ? IDX_debug_line_str : IDX_debug_str); + Elf_Data *data = get_debug_elf_data (dbg, ebl, idx, scn); + if (data == NULL) + return; + + const size_t sh_size = data->d_size; /* Compute floor(log16(shdr->sh_size)). */ GElf_Addr tmp = sh_size; @@ -10669,6 +10684,10 @@ print_debug_str_offsets_section (Dwfl_Module *dwflmod __attribute__ ((unused)), GElf_Ehdr *ehdr __attribute__ ((unused)), Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) { + Elf_Data *data = get_debug_elf_data (dbg, ebl, IDX_debug_str_offsets, scn); + if (data == NULL) + return; + printf (_("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), elf_ndxscn (scn), section_name (ebl, shdr), @@ -10677,16 +10696,6 @@ print_debug_str_offsets_section (Dwfl_Module *dwflmod __attribute__ ((unused)), if (shdr->sh_size == 0) return; - /* We like to get the section from libdw to make sure they are relocated. */ - Elf_Data *data = (dbg->sectiondata[IDX_debug_str_offsets] - ?: elf_rawdata (scn, NULL)); - if (unlikely (data == NULL)) - { - error (0, 0, _("cannot get .debug_str_offsets section data: %s"), - elf_errmsg (-1)); - return; - } - size_t idx = 0; sort_listptr (&known_stroffbases, "str_offsets"); -- 2.39.0