From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gnu.wildebeest.org (wildebeest.demon.nl [212.238.236.112]) by sourceware.org (Postfix) with ESMTPS id 7B85A3861039 for ; Mon, 28 Sep 2020 08:08:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 7B85A3861039 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=klomp.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mark@klomp.org 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 037AA3000A21; Mon, 28 Sep 2020 10:08:21 +0200 (CEST) Received: by tarox.wildebeest.org (Postfix, from userid 1000) id 85860400B8BD; Mon, 28 Sep 2020 10:08:21 +0200 (CEST) From: Mark Wielaard To: dwz@sourceware.org Cc: Mark Wielaard Subject: [PATCH] Support updating DWARF5 .debug_loclists. Date: Mon, 28 Sep 2020 10:07:59 +0200 Message-Id: <20200928080759.8619-1-mark@klomp.org> X-Mailer: git-send-email 2.18.4 X-Spam-Status: No, score=-10.9 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.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: dwz@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Dwz mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Sep 2020 08:08:26 -0000 This patch updates dwz to handle .debug_loclists as it updates .debug_locs. Both sections can be present at the same time (if there are both DWARF5 CUs and older DWARF CUs). So we need to keep both a loc_htab and loclists_htab. * dwz.c (read_loclist_low_mem_phase1): Add cu as argument. Track which section we are reading based on cu->cu_version. Read DWARF5 loclists entries setting ptr and len up to the start and length of the location lists to read. (add_locexpr_dummy_dies): Pass cu to read_loclist_low_mem_phase1. (loclists_htab): New static htab variable. (read_loclist): Update like read_loclist_low_mem_phase1 and create and update loclists_htab for DEBUG_LOCLISTS. (checksum_die): Pass cu to read_loclists. (adjust_loclists): New function like adjust_loclist for DEBUG_LOCLISTS. (write_loclists): New function like write_locs. (cleanup): Delete loclists_htab. (dwz): Call write_loclists. At this time binutils readelf doesn't display .debug_loclists with view pairs correctly. To test the updates are correct when GCC emits view pairs as GNU extension you'll need elfutils eu-readelf with the following patch: https://sourceware.org/pipermail/elfutils-devel/2020q3/002900.html --- dwz.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 302 insertions(+), 54 deletions(-) diff --git a/dwz.c b/dwz.c index e772954..588ee50 100644 --- a/dwz.c +++ b/dwz.c @@ -2374,50 +2374,114 @@ read_exprloc_low_mem_phase1 (DSO *dso, dw_die_ref die, unsigned char *ptr, /* Add dummy DIEs for loclist at OFFSET. */ static int -read_loclist_low_mem_phase1 (DSO *dso, dw_die_ref die, GElf_Addr offset) +read_loclist_low_mem_phase1 (DSO *dso, dw_cu_ref cu, dw_die_ref die, + GElf_Addr offset) { unsigned char *ptr, *endsec; GElf_Addr low, high; - size_t len; + size_t len = 0; + int sec; - ptr = debug_sections[DEBUG_LOC].data; + sec = cu->cu_version < 5 ? DEBUG_LOC : DEBUG_LOCLISTS; + ptr = debug_sections[sec].data; if (ptr == NULL) { - error (0, 0, "%s: loclistptr attribute, yet no .debug_loc section", - dso->filename); + error (0, 0, "%s: loclistptr attribute, yet no %s section", + dso->filename, debug_sections[sec].name); return 1; } - if (offset >= debug_sections[DEBUG_LOC].size) + if (offset >= debug_sections[sec].size) { error (0, 0, - "%s: loclistptr offset %Ld outside of .debug_loc section", - dso->filename, (long long) offset); + "%s: loclistptr offset %Ld outside of %s section", + dso->filename, (long long) offset, debug_sections[sec].name); return 1; } - endsec = ptr + debug_sections[DEBUG_LOC].size; + endsec = ptr + debug_sections[sec].size; ptr += offset; while (ptr < endsec) { - low = read_size (ptr, ptr_size); - high = read_size (ptr + ptr_size, ptr_size); - ptr += 2 * ptr_size; - if (low == 0 && high == 0) - break; + if (cu->cu_version < 5) + { + low = read_size (ptr, ptr_size); + high = read_size (ptr + ptr_size, ptr_size); + ptr += 2 * ptr_size; + if (low == 0 && high == 0) + break; - if (low == ~ (GElf_Addr) 0 || (ptr_size == 4 && low == 0xffffffff)) - continue; + if (low == ~ (GElf_Addr) 0 || (ptr_size == 4 && low == 0xffffffff)) + continue; + + len = read_16 (ptr); + } + else + { + uint8_t lle = *ptr++; + switch (lle) + { + case DW_LLE_end_of_list: + return 0; + + case DW_LLE_base_addressx: + skip_leb128 (ptr); + continue; + + case DW_LLE_startx_endx: + skip_leb128 (ptr); + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + case DW_LLE_startx_length: + skip_leb128 (ptr); + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + case DW_LLE_offset_pair: + skip_leb128 (ptr); + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + case DW_LLE_default_location: + len = read_uleb128 (ptr); + break; + + case DW_LLE_base_address: + ptr += ptr_size; + continue; + + case DW_LLE_start_end: + ptr += 2 * ptr_size; + len = read_uleb128 (ptr); + break; + + case DW_LLE_start_length: + ptr += ptr_size; + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + default: + error (0, 0, + "%s: unhandled location list entry 0x%x in %s section", + dso->filename, lle, debug_sections[sec].name); + return 1; + } + } - len = read_16 (ptr); if (unlikely (!(ptr + len <= endsec))) { error (0, 0, - "%s: locexpr length 0x%Lx exceeds .debug_loc section", - dso->filename, (long long) len); + "%s: locexpr length 0x%Lx exceeds %s section", + dso->filename, (long long) len, debug_sections[sec].name); return 1; } - if (read_exprloc_low_mem_phase1 (dso, die, ptr, len)) - return 1; + if (len > 0) + if (read_exprloc_low_mem_phase1 (dso, die, ptr, len)) + return 1; ptr += len; } @@ -2492,13 +2556,13 @@ add_locexpr_dummy_dies (DSO *dso, dw_cu_ref cu, dw_die_ref die, if ((cu->cu_version < 4 && form == DW_FORM_data4) || form == DW_FORM_sec_offset) { - if (read_loclist_low_mem_phase1 (dso, die, do_read_32 (ptr))) + if (read_loclist_low_mem_phase1 (dso, cu, die, do_read_32 (ptr))) return 1; break; } else if (cu->cu_version < 4 && form == DW_FORM_data8) { - if (read_loclist_low_mem_phase1 (dso, die, do_read_64 (ptr))) + if (read_loclist_low_mem_phase1 (dso, cu, die, do_read_64 (ptr))) return 1; break; } @@ -2526,10 +2590,12 @@ struct debug_loc_adjust }; ALIGN_STRUCT (debug_loc_adjust) -/* Hash table and obstack for recording .debug_loc adjustment ranges. */ +/* Hash table and obstack for recording .debug_loc and .debug_loclists + adjustment ranges. */ static htab_t loc_htab; +static htab_t loclists_htab; -/* Hash function for loc_htab. */ +/* Hash function for loc[lists]_htab. */ static hashval_t loc_hash (const void *p) { @@ -2538,7 +2604,7 @@ loc_hash (const void *p) return a->end_offset; } -/* Equality function for loc_htab. */ +/* Equality function for loc[lists]_htab. */ static int loc_eq (const void *p, const void *q) { @@ -2552,47 +2618,109 @@ loc_eq (const void *p, const void *q) DIE. Call read_exprloc on each of the DWARF expressions contained in it. */ static int -read_loclist (DSO *dso, dw_die_ref die, GElf_Addr offset) +read_loclist (DSO *dso, dw_cu_ref cu, dw_die_ref die, GElf_Addr offset) { unsigned char *ptr, *endsec; GElf_Addr low, high; size_t len; + int sec; bool need_adjust = false; die->die_ck_state = CK_BAD; - ptr = debug_sections[DEBUG_LOC].data; + sec = cu->cu_version < 5 ? DEBUG_LOC : DEBUG_LOCLISTS; + ptr = debug_sections[sec].data; if (ptr == NULL) { - error (0, 0, "%s: loclistptr attribute, yet no .debug_loc section", - dso->filename); + error (0, 0, "%s: loclistptr attribute, yet no %s section", + dso->filename, debug_sections[sec].name); return 1; } - if (offset >= debug_sections[DEBUG_LOC].size) + if (offset >= debug_sections[sec].size) { error (0, 0, - "%s: loclistptr offset %Ld outside of .debug_loc section", - dso->filename, (long long) offset); + "%s: loclistptr offset %Ld outside of %s section", + dso->filename, (long long) offset, debug_sections[sec].name); return 1; } - endsec = ptr + debug_sections[DEBUG_LOC].size; + endsec = ptr + debug_sections[sec].size; ptr += offset; while (ptr < endsec) { - low = read_size (ptr, ptr_size); - high = read_size (ptr + ptr_size, ptr_size); - ptr += 2 * ptr_size; - if (low == 0 && high == 0) - break; + if (cu->cu_version < 5) + { + low = read_size (ptr, ptr_size); + high = read_size (ptr + ptr_size, ptr_size); + ptr += 2 * ptr_size; + if (low == 0 && high == 0) + break; - if (low == ~ (GElf_Addr) 0 || (ptr_size == 4 && low == 0xffffffff)) - continue; + if (low == ~ (GElf_Addr) 0 || (ptr_size == 4 && low == 0xffffffff)) + continue; + + len = read_16 (ptr); + } + else + { + uint8_t lle = *ptr++; + switch (lle) + { + case DW_LLE_end_of_list: + return 0; + + case DW_LLE_base_addressx: + skip_leb128 (ptr); + continue; + + case DW_LLE_startx_endx: + skip_leb128 (ptr); + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + case DW_LLE_startx_length: + skip_leb128 (ptr); + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + case DW_LLE_offset_pair: + skip_leb128 (ptr); + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + case DW_LLE_default_location: + len = read_uleb128 (ptr); + break; + + case DW_LLE_base_address: + ptr += ptr_size; + continue; + + case DW_LLE_start_end: + ptr += 2 * ptr_size; + len = read_uleb128 (ptr); + break; + + case DW_LLE_start_length: + ptr += ptr_size; + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + default: + error (0, 0, + "%s: unhandled location list entry 0x%x in %s section", + dso->filename, lle, debug_sections[sec].name); + return 1; + } + } - len = read_16 (ptr); if (unlikely (!(ptr + len <= endsec))) { error (0, 0, - "%s: locexpr length 0x%Lx exceeds .debug_loc section", - dso->filename, (long long) len); + "%s: locexpr length 0x%Lx exceeds %s section", + dso->filename, (long long) len, debug_sections[sec].name); return 1; } @@ -2608,15 +2736,30 @@ read_loclist (DSO *dso, dw_die_ref die, GElf_Addr offset) void **slot; adj.start_offset = offset; - adj.end_offset = ptr - debug_sections[DEBUG_LOC].data; - adj.cu = die_cu (die); - if (loc_htab == NULL) + adj.end_offset = ptr - debug_sections[sec].data; + adj.cu = cu; + if (sec == DEBUG_LOC) { - loc_htab = htab_try_create (50, loc_hash, loc_eq, NULL); if (loc_htab == NULL) - dwz_oom (); + { + loc_htab = htab_try_create (50, loc_hash, loc_eq, NULL); + if (loc_htab == NULL) + dwz_oom (); + } + slot = htab_find_slot_with_hash (loc_htab, &adj, adj.end_offset, + INSERT); + } + else + { + if (loclists_htab == NULL) + { + loclists_htab = htab_try_create (50, loc_hash, loc_eq, NULL); + if (loclists_htab == NULL) + dwz_oom (); + } + slot = htab_find_slot_with_hash (loclists_htab, &adj, adj.end_offset, + INSERT); } - slot = htab_find_slot_with_hash (loc_htab, &adj, adj.end_offset, INSERT); if (slot == NULL) dwz_oom (); if (*slot == NULL) @@ -2627,8 +2770,8 @@ read_loclist (DSO *dso, dw_die_ref die, GElf_Addr offset) } else if (((struct debug_loc_adjust *)*slot)->cu != adj.cu) { - error (0, 0, "%s: can't adjust .debug_loc section because multiple " - "CUs refer to it", dso->filename); + error (0, 0, "%s: can't adjust %s section because multiple " + "CUs refer to it", dso->filename, debug_sections[sec].name); return 1; } else if (((struct debug_loc_adjust *)*slot)->start_offset > offset) @@ -2848,14 +2991,14 @@ checksum_die (DSO *dso, dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die) if ((cu->cu_version < 4 && form == DW_FORM_data4) || form == DW_FORM_sec_offset) { - if (read_loclist (dso, die, read_32 (ptr))) + if (read_loclist (dso, cu, die, read_32 (ptr))) return 1; ptr = old_ptr; break; } else if (cu->cu_version < 4 && form == DW_FORM_data8) { - if (read_loclist (dso, die, read_64 (ptr))) + if (read_loclist (dso, cu, die, read_64 (ptr))) return 1; ptr = old_ptr; break; @@ -12128,6 +12271,85 @@ adjust_loclist (void **slot, void *data) return 1; } +/* Adjust .debug_loclists range determined by *SLOT, called through + htab_traverse. */ +static int +adjust_loclists (void **slot, void *data) +{ + struct debug_loc_adjust *adj = (struct debug_loc_adjust *) *slot; + unsigned char *ptr, *endsec; + size_t len = 0; + + (void)data; + + ptr = debug_sections[DEBUG_LOCLISTS].new_data + adj->start_offset; + endsec = ptr + debug_sections[DEBUG_LOCLISTS].size; + + while (ptr < endsec) + { + uint8_t lle = *ptr++; + switch (lle) + { + case DW_LLE_end_of_list: + return 1; + + case DW_LLE_base_addressx: + skip_leb128 (ptr); + continue; + + case DW_LLE_startx_endx: + skip_leb128 (ptr); + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + case DW_LLE_startx_length: + skip_leb128 (ptr); + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + case DW_LLE_offset_pair: + skip_leb128 (ptr); + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + case DW_LLE_default_location: + len = read_uleb128 (ptr); + break; + + case DW_LLE_base_address: + ptr += ptr_size; + continue; + + case DW_LLE_start_end: + ptr += 2 * ptr_size; + len = read_uleb128 (ptr); + break; + + case DW_LLE_start_length: + ptr += ptr_size; + skip_leb128 (ptr); + len = read_uleb128 (ptr); + break; + + default: + error (0, 0, "unhandled location list entry 0x%x", lle); + return 1; + } + + assert (ptr + len <= endsec); + + adjust_exprloc (adj->cu, adj->cu->cu_die, adj->cu, adj->cu->cu_die, + ptr, len); + + ptr += len; + } + + return 1; +} + /* Create new .debug_loc section in malloced memory if .debug_loc needs to be adjusted. */ static void @@ -12144,6 +12366,23 @@ write_loc (void) htab_traverse (loc_htab, adjust_loclist, NULL); } +/* Create new .debug_loclists section in malloced memory if .debug_loclists + needs to be adjusted. */ +static void +write_loclists (void) +{ + unsigned char *loc; + if (loclists_htab == NULL) + return; + loc = malloc (debug_sections[DEBUG_LOCLISTS].size); + if (loc == NULL) + dwz_oom (); + memcpy (loc, debug_sections[DEBUG_LOCLISTS].data, + debug_sections[DEBUG_LOCLISTS].size); + debug_sections[DEBUG_LOCLISTS].new_data = loc; + htab_traverse (loclists_htab, adjust_loclists, NULL); +} + /* Create new .debug_types section in malloced memory. */ static void write_types (void) @@ -13439,6 +13678,9 @@ cleanup (void) if (loc_htab != NULL) htab_delete (loc_htab); loc_htab = NULL; + if (loclists_htab != NULL) + htab_delete (loclists_htab); + loclists_htab = NULL; if (dup_htab != NULL) htab_delete (dup_htab); dup_htab = NULL; @@ -14440,6 +14682,12 @@ dwz (const char *file, const char *outfile, struct file_result *res, fprintf (stderr, "write_loc\n"); } write_loc (); + if (unlikely (progress_p)) + { + report_progress (); + fprintf (stderr, "write_loclists\n"); + } + write_loclists (); if (unlikely (progress_p)) { report_progress (); -- 2.18.4