From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 36715 invoked by alias); 7 Mar 2019 13:11:42 -0000 Mailing-List: contact dwz-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Post: List-Help: List-Subscribe: Sender: dwz-owner@sourceware.org Received: (qmail 36700 invoked by uid 89); 7 Mar 2019 13:11:41 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.100.2 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.8 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.1 spammy=HX-Languages-Length:4273, debug_info, **slot, google X-Spam-Status: No, score=-25.8 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on sourceware.org X-Spam-Level: X-HELO: mx1.suse.de X-Virus-Scanned: by amavisd-new at test-mx.suse.de Date: Tue, 01 Jan 2019 00:00:00 -0000 From: Tom de Vries To: dwz@sourceware.org, jakub@redhat.com Subject: [PATCH] Error out for invalid DW_FORM_ref_addr Message-ID: <20190307131218.GA6377@delia> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) X-SW-Source: 2019-q1/txt/msg00100.txt.bz2 Hi, When running dwz on a file that contains invalid DW_FORM_ref_addr attributes (which has been observed to be generated by a google go compiler) we run either into an assert: ... $ dwz f dwz: dwz.c:8792: write_die: Assertion `refd != NULL' failed. Aborted (core dumped) ... or a segmentation fault: ... $ dwz -l0 f Segmentation fault (core dumped) ... Fix this by verifying the DW_FORM_ref_addr attributes after parsing the .debug_info section. This gives a detailed error message in regular mode: ... $ dwz f dwz: Couldn't find DIE at DW_FORM_ref_addr offset 0x85e89c (referenced by \ DW_AT_abstract_origin in DIE at offset 0x85eacb) ... and a more basic error message in low-memory mode: ... $ dwz -l0 f dwz: Couldn't find DIE at DW_FORM_ref_addr offset 0x85e848 ... OK for trunk? Thanks, - Tom Error out for invalid DW_FORM_ref_addr 2019-02-05 Tom de Vries PR dwz/24169 * dwz.c (verify_ref_addr_die, verify_ref_addr_low_mem, verify_ref_addr): New function. (read_debug_info): Call verify_ref_addr. --- dwz.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/dwz.c b/dwz.c index e4e5d5c..7ec1347 100644 --- a/dwz.c +++ b/dwz.c @@ -4401,6 +4401,81 @@ collapse_children (dw_cu_ref cu, dw_die_ref die) } } +/* Verify DW_FORM_ref_addr in DIE. */ +static inline void +verify_ref_addr_die (dw_cu_ref cu, dw_die_ref die) +{ + dw_die_ref child; + for (child = die->die_child; child; child = child->die_sib) + verify_ref_addr_die (cu, child); + + if (die->die_offset == -1U) + return; + + struct abbrev_tag *t = die->die_abbrev; + unsigned int i; + unsigned char *section_ptr; + unsigned char *ptr; + if (unlikely (fi_multifile) && cu->cu_kind == CU_ALT) + section_ptr = alt_data[DEBUG_INFO]; + else if (cu->cu_kind == CU_TYPES) + section_ptr = debug_sections[DEBUG_TYPES].data; + else + section_ptr = debug_sections[DEBUG_INFO].data; + ptr = section_ptr + die->die_offset; + read_uleb128 (ptr); + for (i = 0; i < t->nattr; ++i) + { + struct abbrev_attr *attr = &t->attr[i]; + if (attr->form == DW_FORM_ref_addr) + { + uint64_t value; + dw_die_ref ref; + + value = read_size (ptr, cu->cu_version == 2 + ? ptr_size : 4); + + ref = off_htab_lookup (cu, value); + if (ref == NULL) + { + error (1, 0, + "Couldn't find DIE at DW_FORM_ref_addr offset 0x%lx" + " (referenced by %s in DIE at offset 0x%x)", + value, get_DW_AT_str (attr->attr), die->die_offset); + + } + } + ptr = skip_attr (cu, attr, ptr); + } +} + +/* Verify DW_FORM_ref_addr in low_mem mode. */ +static int +verify_ref_addr_low_mem (void **slot, void *data __attribute__((unused))) +{ + dw_die_ref die = (dw_die_ref) *slot; + if (die->die_tag == 0) + error (1, 0, "Couldn't find DIE at DW_FORM_ref_addr offset 0x%x", + die->die_offset); + + return 1; +} + +/* Verify DW_FORM_ref_addr. */ +static void +verify_ref_addr (void) +{ + if (unlikely (low_mem)) + htab_traverse (off_htab, verify_ref_addr_low_mem, NULL); + else + { + dw_cu_ref cu; + + for (cu = first_cu; cu; cu = cu->cu_next) + verify_ref_addr_die (cu, cu->cu_die); + } +} + /* First phase of the DWARF compression. Parse .debug_info section (for kind == DEBUG_INFO) or .debug_types section (for kind == DEBUG_TYPES) for each CU in it construct internal represetnation for the CU @@ -4428,6 +4503,7 @@ read_debug_info (DSO *dso, int kind) bool low_mem_phase1 = low_mem && kind == DEBUG_INFO; struct dw_cu cu_buf; struct dw_die die_buf; + bool seen_ref_addr = false; if (likely (!fi_multifile && kind != DEBUG_TYPES)) { @@ -4523,6 +4599,9 @@ read_debug_info (DSO *dso, int kind) { if (ptr == endcu) { + if (seen_ref_addr) + verify_ref_addr (); + dw_cu_ref cuf = cu_tail ? cu_tail->cu_next : first_cu; /* Inside of optimize_multifile, DIE hashes are computed only after all the CUs from a particular DSO or @@ -4748,6 +4827,7 @@ read_debug_info (DSO *dso, int kind) switch (form) { case DW_FORM_ref_addr: + seen_ref_addr = true; if (unlikely (low_mem_phase1)) { dw_die_ref ref; @@ -5019,6 +5099,9 @@ read_debug_info (DSO *dso, int kind) goto low_mem_phase2; } + if (seen_ref_addr && !(unlikely (op_multifile))) + verify_ref_addr (); + if (unlikely (low_mem)) ; else if (unlikely (meta_abbrev_htab != NULL))