From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 98691 invoked by alias); 30 Mar 2018 15:57:31 -0000 Mailing-List: contact elfutils-devel-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Post: List-Help: List-Subscribe: Sender: elfutils-devel-owner@sourceware.org Received: (qmail 98672 invoked by uid 89); 30 Mar 2018 15:57:31 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.99.4 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.2 spammy=20180323, 2018-03-23 X-Spam-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-HELO: gnu.wildebeest.org Received: from wildebeest.demon.nl (HELO gnu.wildebeest.org) (212.238.236.112) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 30 Mar 2018 15:57:29 +0000 Received: from tarox.wildebeest.org (tarox.wildebeest.org [172.31.17.39]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id CB29031D69EC; Fri, 30 Mar 2018 17:57:26 +0200 (CEST) Received: by tarox.wildebeest.org (Postfix, from userid 1000) id C411740013BF; Fri, 30 Mar 2018 17:57:26 +0200 (CEST) From: Mark Wielaard To: elfutils-devel@sourceware.org Cc: Mark Wielaard Subject: [PATCH] libdw: Add support for reading DW_FORM_strx[1234] in .debug_str_offsets. Date: Fri, 30 Mar 2018 15:57:00 -0000 Message-Id: <1522425423-7839-1-git-send-email-mark@klomp.org> X-Mailer: git-send-email 1.8.3.1 X-Spam-Flag: NO X-IsSubscribed: yes X-SW-Source: 2018-q1/txt/msg00123.txt.bz2 Recognize the new .debug_str_offsets section. The CU will now hold a new str_off_base offset in that section for that CU. dwarf_form_string will decode DW_FORM_strx[1234] and return strings using that str_off_base from the .debug_addr. Signed-off-by: Mark Wielaard --- libdw/ChangeLog | 13 +++++ libdw/dwarf_begin_elf.c | 5 +- libdw/dwarf_error.c | 1 + libdw/dwarf_formstring.c | 124 +++++++++++++++++++++++++++++++++++++++++++---- libdw/dwarf_formudata.c | 8 +++ libdw/libdwP.h | 9 ++++ src/ChangeLog | 4 ++ src/readelf.c | 5 ++ 8 files changed, 158 insertions(+), 11 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 8423cb3..a5bb6c4 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,16 @@ +2018-03-23 Mark Wielaard + + * dwarf_begin_elf.c (dwarf_scnnames): Add IDX_debug_str_offsets, + increase size. + * dwarf_error.c (errmsgs): Add DWARF_E_NO_STR_OFFSETS. + * dwarf_formstring.c (dwarf_formstring): Handle DW_FORM_strx[1234]. + (__libdw_cu_str_off_base): New function. + * dwarf_formudata.c (dwarf_formudata): Handle IDX_debug_str_offsets + as stroffsetsptr. + * libdwP.h: Add IDX_debug_str_offsets and DWARF_E_NO_STR_OFFSETS. + (struct Dwarf_CU): Add str_off_base field. + (__libdw_cu_str_off_base): New function declaration. + 2018-03-22 Mark Wielaard * dwarf_begin_elf.c (dwarf_scnnames): Add IDX_debug_addr. diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c index 1ffa6c9..19a5fbb 100644 --- a/libdw/dwarf_begin_elf.c +++ b/libdw/dwarf_begin_elf.c @@ -46,8 +46,8 @@ #include "libdwP.h" -/* Section names. */ -static const char dwarf_scnnames[IDX_last][18] = +/* Section names. (Note .debug_str_offsets is the largest 19 chars.) */ +static const char dwarf_scnnames[IDX_last][19] = { [IDX_debug_info] = ".debug_info", [IDX_debug_types] = ".debug_types", @@ -59,6 +59,7 @@ static const char dwarf_scnnames[IDX_last][18] = [IDX_debug_loc] = ".debug_loc", [IDX_debug_pubnames] = ".debug_pubnames", [IDX_debug_str] = ".debug_str", + [IDX_debug_str_offsets] = ".debug_str_offsets", [IDX_debug_macinfo] = ".debug_macinfo", [IDX_debug_macro] = ".debug_macro", [IDX_debug_ranges] = ".debug_ranges", diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c index 212f32e..cbf573f 100644 --- a/libdw/dwarf_error.c +++ b/libdw/dwarf_error.c @@ -73,6 +73,7 @@ static const char *errmsgs[] = [DWARF_E_NO_ENTRY] = N_("no entries found"), [DWARF_E_INVALID_DWARF] = N_("invalid DWARF"), [DWARF_E_NO_STRING] = N_("no string data"), + [DWARF_E_NO_STR_OFFSETS] = N_(".debug_str_offsets section missing"), [DWARF_E_NO_ADDR] = N_("no address value"), [DWARF_E_NO_CONSTANT] = N_("no constant value"), [DWARF_E_NO_REFERENCE] = N_("no reference value"), diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c index 4eae0ed..39766ad 100644 --- a/libdw/dwarf_formstring.c +++ b/libdw/dwarf_formstring.c @@ -1,7 +1,6 @@ /* Return string associated with given attribute. Copyright (C) 2003-2010, 2013, 2018 Red Hat, Inc. This file is part of elfutils. - Written by Ulrich Drepper , 2003. This file is free software; you can redistribute it and/or modify it under the terms of either @@ -47,7 +46,8 @@ dwarf_formstring (Dwarf_Attribute *attrp) /* A simple inlined string. */ return (const char *) attrp->valp; - Dwarf *dbg = attrp->cu->dbg; + Dwarf_CU *cu = attrp->cu; + Dwarf *dbg = cu->dbg; Dwarf *dbg_ret = (attrp->form == DW_FORM_GNU_strp_alt ? INTUSE(dwarf_getalt) (dbg) : dbg); @@ -57,20 +57,126 @@ dwarf_formstring (Dwarf_Attribute *attrp) return NULL; } - - if (unlikely (attrp->form != DW_FORM_strp - && attrp->form != DW_FORM_GNU_strp_alt) - || dbg_ret->sectiondata[IDX_debug_str] == NULL) + if (dbg_ret->sectiondata[IDX_debug_str] == NULL) { __libdw_seterrno (DWARF_E_NO_STRING); return NULL; } uint64_t off; - if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (attrp->cu), attrp->valp, - attrp->cu->offset_size, &off, IDX_debug_str, 1)) - return NULL; + if (attrp->form == DW_FORM_strp + || attrp->form == DW_FORM_GNU_strp_alt) + { + if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (cu), + attrp->valp, cu->offset_size, &off, + IDX_debug_str, 1)) + return NULL; + } + else + { + Dwarf_Word idx; + const unsigned char *datap = attrp->valp; + const unsigned char *endp = cu->endp; + switch (attrp->form) + { + case DW_FORM_strx: + if (datap >= endp) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + get_uleb128 (idx, datap, endp); + break; + + case DW_FORM_strx1: + if (datap >= endp - 1) + goto invalid; + idx = *datap; + break; + + case DW_FORM_strx2: + if (datap >= endp - 2) + goto invalid; + idx = read_2ubyte_unaligned (dbg, datap); + break; + + case DW_FORM_strx3: + if (datap >= endp - 3) + goto invalid; + idx = read_3ubyte_unaligned (dbg, datap); + break; + + case DW_FORM_strx4: + if (datap >= endp - 4) + goto invalid; + idx = read_4ubyte_unaligned (dbg, datap); + break; + + default: + __libdw_seterrno (DWARF_E_NO_STRING); + return NULL; + } + + /* So we got an index in the .debug_str_offsets. Lets see if it + is valid and we can get the actual .debug_str offset. */ + Dwarf_Off str_off = __libdw_cu_str_off_base (cu); + if (str_off == (Dwarf_Off) -1) + return NULL; + + if (dbg->sectiondata[IDX_debug_str_offsets] == NULL) + { + __libdw_seterrno (DWARF_E_NO_STR_OFFSETS); + return NULL; + } + + /* The section should at least contain room for one offset. */ + int offset_size = cu->offset_size; + if (cu->offset_size > dbg->sectiondata[IDX_debug_str_offsets]->d_size) + { + invalid_offset: + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return NULL; + } + + /* And the base offset should be at least inside the section. */ + if (str_off > (dbg->sectiondata[IDX_debug_str_offsets]->d_size + - offset_size)) + goto invalid_offset; + + size_t max_idx = (dbg->sectiondata[IDX_debug_str_offsets]->d_size + - offset_size - str_off) / offset_size; + if (idx > max_idx) + goto invalid_offset; + + datap = (dbg->sectiondata[IDX_debug_str_offsets]->d_buf + + str_off + (idx * offset_size)); + if (offset_size == 4) + off = read_4ubyte_unaligned (dbg, datap); + else + off = read_8ubyte_unaligned (dbg, datap); + + if (off > dbg->sectiondata[IDX_debug_str]->d_size) + goto invalid_offset; + } return (const char *) dbg_ret->sectiondata[IDX_debug_str]->d_buf + off; } INTDEF(dwarf_formstring) + +Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu) +{ + if (cu->str_off_base == (Dwarf_Off) -1) + { + Dwarf_Die cu_die = CUDIE(cu); + Dwarf_Attribute attr; + if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL) + { + Dwarf_Word off; + if (dwarf_formudata (&attr, &off) == 0) + cu->str_off_base = off; + } + } + + return cu->str_off_base; +} diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c index 5d5fc63..0aaea24 100644 --- a/libdw/dwarf_formudata.c +++ b/libdw/dwarf_formudata.c @@ -190,6 +190,14 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) return -1; break; + case DW_AT_str_offsets_base: + /* stroffsetsptr */ + if (__libdw_formptr (attr, IDX_debug_str_offsets, + DWARF_E_NO_STR_OFFSETS, NULL, + return_uval) == NULL) + return -1; + break; + default: /* sec_offset can only be used by one of the above attrs. */ if (attr->form == DW_FORM_sec_offset) diff --git a/libdw/libdwP.h b/libdw/libdwP.h index ba50c35..9413705 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -80,6 +80,7 @@ enum IDX_debug_loc, IDX_debug_pubnames, IDX_debug_str, + IDX_debug_str_offsets, IDX_debug_macinfo, IDX_debug_macro, IDX_debug_ranges, @@ -109,6 +110,7 @@ enum DWARF_E_NO_ENTRY, DWARF_E_INVALID_DWARF, DWARF_E_NO_STRING, + DWARF_E_NO_STR_OFFSETS, DWARF_E_NO_ADDR, DWARF_E_NO_CONSTANT, DWARF_E_NO_REFERENCE, @@ -330,6 +332,10 @@ struct Dwarf_CU Don't access directly, call __libdw_cu_addr_base. */ Dwarf_Off addr_base; + /* The offset into the .debug_str_offsets section where index zero begins. + Don't access directly, call __libdw_cu_str_off_base. */ + Dwarf_Off str_off_base; + /* Memory boundaries of this CU. */ void *startp; void *endp; @@ -874,6 +880,9 @@ const char *__libdw_getcompdir (Dwarf_Die *cudie); /* Get the address base for the CU, fetches it when not yet set. */ Dwarf_Off __libdw_cu_addr_base (Dwarf_CU *cu); +/* Get the string offsets base for the CU, fetches it when not yet set. */ +Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu); + /* Given a file descriptor, dir and file returns a full path. If the file is absolute (starts with a /) a copy of file is returned. If the file isn't absolute, but dir is absolute, then a path that is diff --git a/src/ChangeLog b/src/ChangeLog index 7b8084f..37c9cb3 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2018-03-23 Mark Wielaard + + * readelf.c (attr_callback): Handle DW_FORM_strx[1234]. + 2018-03-22 Mark Wielaard * readelf.c (attr_callback): Handle DW_FORM_addrx[1234]. diff --git a/src/readelf.c b/src/readelf.c index c1d6ac1..933eab1 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -6097,6 +6097,11 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) case DW_FORM_indirect: case DW_FORM_strp: + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: case DW_FORM_string: case DW_FORM_GNU_strp_alt: if (cbargs->silent) -- 1.8.3.1