[PATCH] libdw: Return an error in dwarf_getlocation_attr for missing .debug_addr.
When constructing a "fake" Dwarf_Attribute for DW_OP_GNU_const_index, DW_OP_constx, DW_OP_GNU_addr_index or DW_OP_addrx, we would create a fake attribute pointing to the actual data in the .debug_addr section. We would even do that if there was no .debug_addr section assuming dwarf_formaddr or dwarf_formudata would generate an error. But when there is no .debug_addr there is also no fake_addr_cu, so the dwarf_form* functions cannot check the value is correct (and crash). Fix by returning an error early from dwarf_getlocation_attr indicating bad DWARF data. Found by the afl fuzzer running on the varlocs testcase. Signed-off-by: Mark Wielaard --- libdw/ChangeLog| 6 ++ libdw/dwarf_getlocation_attr.c | 14 ++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 9d0b484..79fcf1e 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,9 @@ +2018-06-08 Mark Wielaard + + * dwarf_getlocation_attr.c (addr_valp): Set error and return NULL + when there is no .debug_addr section. + (dwarf_getlocation_attr): If addr_valp returns NULL, then return -1. + 2018-06-07 Mark Wielaard * libdw_findcu.c (__libdw_intern_next_unit): Report DWARF_E_VERSION, diff --git a/libdw/dwarf_getlocation_attr.c b/libdw/dwarf_getlocation_attr.c index 875fc5d..99bcc82 100644 --- a/libdw/dwarf_getlocation_attr.c +++ b/libdw/dwarf_getlocation_attr.c @@ -1,5 +1,5 @@ /* Return DWARF attribute associated with a location expression op. - Copyright (C) 2013, 2014, 2017 Red Hat, Inc. + Copyright (C) 2013, 2014, 2017, 2018 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -58,11 +58,13 @@ static unsigned char * addr_valp (Dwarf_CU *cu, Dwarf_Word index) { Elf_Data *debug_addr = cu->dbg->sectiondata[IDX_debug_addr]; - Dwarf_Word offset = __libdw_cu_addr_base (cu) + (index * cu->address_size); if (debug_addr == NULL) -/* This is really an error, will trigger with dwarf_formaddr. */ -return (unsigned char *) (uintptr_t) offset; +{ + __libdw_seterrno (DWARF_E_NO_DEBUG_ADDR); + return NULL; +} + Dwarf_Word offset = __libdw_cu_addr_base (cu) + (index * cu->address_size); return (unsigned char *) debug_addr->d_buf + offset; } @@ -105,6 +107,8 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu else result->form = DW_FORM_data8; result->valp = addr_valp (attr->cu, op->number); + if (result->valp == NULL) + return -1; result->cu = attr->cu->dbg->fake_addr_cu; break; @@ -113,6 +117,8 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu result->code = DW_AT_low_pc; result->form = DW_FORM_addr; result->valp = addr_valp (attr->cu, op->number); + if (result->valp == NULL) + return -1; result->cu = attr->cu->dbg->fake_addr_cu; break; -- 1.8.3.1
Re: [PATCH] libdwfl: Make __libdwfl_addrsym a static function in dwfl_module_addrsym.c
On Tue, 2018-06-05 at 00:04 +0200, Mark Wielaard wrote: > __libdwfl_addrsym is only used in the dwfl_module_addrsym.c source. > There is no need to mark this as a (shared) internal function. Pushed to master.
Re: [PATCH] readelf: Make room for DW_MACRO_hi_user opcode if used.
On Tue, 2018-06-05 at 21:06 +0200, Mark Wielaard wrote: > The vendor array should have room for all vendor opcode, including > DW_MACRO_hi_user if used. Pushed to master.
Re: [PATCH] libdw: Make sure id_path can contain max number of build id bytes.
On Tue, 2018-06-05 at 21:33 +0200, Mark Wielaard wrote: > The MAX_BUILD_ID_BYTES is fairly large (64), while normally build-ids > are only 20 bytes long. But if we would encounter a jumbo build-id we > should have enough room to construct the full build-id path. > > We used to substract 2 bytes from the max, because 2 chars are used > as subdir. But that should be 1 (2 hex chars is just one 8 bit byte). Pushed to master.
Re: [PATCH] readelf: Set begin properly for DW_LLE_GNU_start_end_entry on addrx failure.
On Tue, 2018-06-05 at 23:06 +0200, Mark Wielaard wrote: > When printing the GNU DebugFission location entries we want to print the > start idx as begin, if we cannot find the address index. > A copy/paste error set up end instead of begin in that case causing us > to print garbage (in the unlikely event the .debug_addr table wasn't > found for this entry). Pushed to master.
Re: [PATCH] readelf: Don't leak lengths array when detecting an invalid hash chain.
On Tue, 2018-06-05 at 21:55 +0200, Mark Wielaard wrote: > In both handle_sysv_hash and handle_sysv_hash64 we check the has chain > isn't too long. If it is we would report an error and leak the lengths > array. Just clean up the array even in the error case. Pushed to master.
Re: [PATCH] libdw: Make sure dirarray is always properly freed in dwarf_getsrclines.
On Tue, 2018-06-05 at 22:33 +0200, Mark Wielaard wrote: > If there were more than 256 directories in the table and there was > illegal DWARF before we read them all, then we might not free the > dirarray (or the wrong one). Fix by defining the dirarray early > (before the first data sanity check) and making sure it is not > (still) equal to dirstack before freeing. Pushed to master.
Re: [PATCH] libdw: Don't leak arange if we cannot figure out which CU it belongs to.
On Tue, 2018-06-05 at 22:44 +0200, Mark Wielaard wrote: > In the unlikely case that __libdw_findcu fails to find the associated > CU we would leak one arange because it wasn't linked into the arangelist > list yet. Make sure to free it immediately. Pushed to master.
Re: [PATCH] libdw: Explicitly check we could decode diridx in dwarf_getsrclines.
On Tue, 2018-06-05 at 23:36 +0200, Mark Wielaard wrote: > It is highly unlikely dwarf_formudata fails because we setup the attribute > ourselves, but better to explicitly mark diridx as bad if it does. Pushed to master.
Re: [PATCH] readelf: Always initialize .debug_addr unit_length, even without a header.
On Tue, 2018-06-05 at 23:23 +0200, Mark Wielaard wrote: > We would print a "fake" .debug_addr header, but didn't always setup the > unit_length (in case there was a mix of GNU DebugFission and DWARF5 tables). > Make sure to always set the unit_length (we do always calculate the next > unit offset already). Pushed to master.
[PATCH] readelf, libdw: Handle too many directories or files in the line table better.
The afl fuzzer found that the way we handle "too many" directories or files in the (DWARF5 style) line table badly. In the case of eu-readelf we would print an endless stream of "bad directory" or "bad file". Just stop printing when the end of data is reached. In the case of dwarf_getsrclines we would allocate a giant amount of memory, even if there was no data to actually read in. Sanity check that the directory and file counts seem reasonable compared to the amount of data left (assume we need at least 1 byte of data per form describing the dirs or files). Signed-off-by: Mark Wielaard --- libdw/ChangeLog | 4 libdw/dwarf_getsrclines.c | 10 ++ src/ChangeLog | 5 + src/readelf.c | 4 4 files changed, 23 insertions(+) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 79fcf1e..ddd8296 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,5 +1,9 @@ 2018-06-08 Mark Wielaard + * dwarf_getsrclines.c (read_srclines): Sanity check ndirs and nfiles. + +2018-06-08 Mark Wielaard + * dwarf_getlocation_attr.c (addr_valp): Set error and return NULL when there is no .debug_addr section. (dwarf_getlocation_attr): If addr_valp returns NULL, then return -1. diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c index 07baebc..bb512ec 100644 --- a/libdw/dwarf_getsrclines.c +++ b/libdw/dwarf_getsrclines.c @@ -356,6 +356,11 @@ read_srclines (Dwarf *dbg, if (nforms == 0 && ndirs != 0) goto invalid_data; + + /* Assume there is at least 1 byte needed per form to describe +the directory. Filters out insanely large ndirs. */ + if (nforms != 0 && ndirs > (size_t) (lineendp - linep) / nforms) + goto invalid_data; } /* Arrange the list in array form. */ @@ -561,6 +566,11 @@ read_srclines (Dwarf *dbg, if (nforms == 0 && nfiles != 0) goto invalid_data; + /* Assume there is at least 1 byte needed per form to describe +the file. Filters out insanely large nfiles. */ + if (nforms != 0 && nfiles > (size_t) (lineendp - linep) / nforms) + goto invalid_data; + Dwarf_Attribute attr; attr.cu = &fake_cu; for (unsigned int n = 0; n < nfiles; n++) diff --git a/src/ChangeLog b/src/ChangeLog index 778238e..ca1917a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2018-06-08 Mark Wielaard + + * readelf.c (print_debug_line_section): Stop printing directories + and files when we are at the end of the unit data. + 2018-06-07 Mark Wielaard * readelf.c (format_result): Removed. diff --git a/src/readelf.c b/src/readelf.c index f9514a1..af78f17 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -8294,6 +8294,8 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, printf (", "); } printf ("\n"); + if (linep >= lineendp) + goto invalid_unit; } } else @@ -8370,6 +8372,8 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, printf (", "); } printf ("\n"); + if (linep >= lineendp) + goto invalid_unit; } } else -- 1.8.3.1
[PATCH] tests: Fix cfi_debug_bias assert in varlocs.
It is only a consistency issue if we actually have an cfi_debug and the cfi_debug_bias is not zero (because they come from the same file as the other debug data). Signed-off-by: Mark Wielaard --- tests/ChangeLog | 5 + tests/varlocs.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/ChangeLog b/tests/ChangeLog index a2adfee..25ed41e 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,8 @@ +2018-06-08 Mark Wielaard + + * varlocs.c (main): Only assert when cfi_debug_bias != 0 if there + actually is a cfi_debug. + 2018-06-07 Mark Wielaard * run-readelf-loc.sh: Fix expected output for startx_length. diff --git a/tests/varlocs.c b/tests/varlocs.c index 2ddd3d8..99c3887 100644 --- a/tests/varlocs.c +++ b/tests/varlocs.c @@ -1121,7 +1121,8 @@ main (int argc, char *argv[]) cfi_debug = dwfl_module_dwarf_cfi (mod, &cfi_debug_bias); cfi_eh = dwfl_module_eh_cfi (mod, &cfi_eh_bias); - assert (cfi_debug_bias == 0); // No bias needed, same file. + // No bias needed, same file. + assert (cfi_debug == NULL || cfi_debug_bias == 0); // We are a bit forgiving for object files. There might be // relocations we don't handle that are needed in some -- 1.8.3.1
[PATCH] libdw: Detect bad DWARF in store_implicit_value.
The afl fuzzer running against the varlocs test detected we didn't report the value block of a DW_OP_implicit_value consistently when the DWARF was bad. Although this doesn't cause a crash it might result in consumers using dwarf_getlocation_implicit_value seeing an inconsistent block length value. To fix this detect and report bad DWARF data earlier. Signed-off-by: Mark Wielaard --- libdw/ChangeLog | 7 +++ libdw/dwarf_getlocation.c | 25 +++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index ddd8296..23e11b9 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,5 +1,12 @@ 2018-06-08 Mark Wielaard + * dwarf_getlocation.c (store_implicit_value): Return error when + seeing bad DWARF or when tsearch runs out of memory. + (__libdw_intern_expression): Report error when store_implicit_value + reported an error. + +2018-06-08 Mark Wielaard + * dwarf_getsrclines.c (read_srclines): Sanity check ndirs and nfiles. 2018-06-08 Mark Wielaard diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c index d293e75..7f294fe 100644 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@ -120,19 +120,23 @@ loc_compare (const void *p1, const void *p2) } /* For each DW_OP_implicit_value, we store a special entry in the cache. - This points us directly to the block data for later fetching. */ -static void + This points us directly to the block data for later fetching. + Returns zero on success, -1 on bad DWARF or 1 if tsearch failed. */ +static int store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op) { struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s, sizeof (struct loc_block_s), 1); const unsigned char *data = (const unsigned char *) (uintptr_t) op->number2; - // Ignored, equal to op->number. And data length already checked. - (void) __libdw_get_uleb128 (&data, data + len_leb128 (Dwarf_Word)); + uint64_t len = __libdw_get_uleb128 (&data, data + len_leb128 (Dwarf_Word)); + if (unlikely (len != op->number)) +return -1; block->addr = op; block->data = (unsigned char *) data; block->length = op->number; - (void) tsearch (block, cache, loc_compare); + if (unlikely (tsearch (block, cache, loc_compare) == NULL)) +return 1; + return 0; } int @@ -589,7 +593,16 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order, result[n].offset = loclist->offset; if (result[n].atom == DW_OP_implicit_value) - store_implicit_value (dbg, cache, &result[n]); + { + int store = store_implicit_value (dbg, cache, &result[n]); + if (unlikely (store != 0)) + { + if (store < 0) + goto invalid; + else + goto nomem; + } + } struct loclist *loc = loclist; loclist = loclist->next; -- 1.8.3.1
Re: [PATCH] tests: Use error, not assert, when trying to print a non-base type DIE.
On Wed, 2018-06-06 at 23:43 +0200, Mark Wielaard wrote: > When using the varlocs test with a fuzzer using assert for internal > sanity checks is great to find issues. But when encountering bad data > using an assert is wrong. Just use error to show we handle the data > correctly (by reporting it is bad, instead of crashing). Pushed to master.
Re: [PATCH] libdw: Report error in dwarf_getlocation_die for bogus opcode offset.
On Thu, 2018-06-07 at 00:01 +0200, Mark Wielaard wrote: > Found by afl fuzzer on varlocs test. varlocs sanity checks that the > given offset in the opcode corresponds to the cuoffset of the returned > DIE. In case the opcode offset was bogus this might fail because we > might wrap around and return a random DIE instead of reporting an error. Pushed to master.
[PATCH] libdw: dwarf_get_units should handle existing failure to open Dwarf.
The other dwarf unit/cu iterators handle a NULL Dwarf handle as an existing error and return NULL. Don't crash. Signed-off-by: Mark Wielaard --- libdw/ChangeLog | 5 + libdw/dwarf_get_units.c | 4 2 files changed, 9 insertions(+) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 23e11b9..21cb03c 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,5 +1,10 @@ 2018-06-08 Mark Wielaard + * dwarf_get_units.c (dwarf_get_units): Handle existing error, no + dwarf. + +2018-06-08 Mark Wielaard + * dwarf_getlocation.c (store_implicit_value): Return error when seeing bad DWARF or when tsearch runs out of memory. (__libdw_intern_expression): Report error when store_implicit_value diff --git a/libdw/dwarf_get_units.c b/libdw/dwarf_get_units.c index aece17e..6215bf4 100644 --- a/libdw/dwarf_get_units.c +++ b/libdw/dwarf_get_units.c @@ -40,6 +40,10 @@ dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu, Dwarf_Half *version, uint8_t *unit_type, Dwarf_Die *cudie, Dwarf_Die *subdie) { + /* Handle existing error. */ + if (dwarf == NULL) +return -1; + Dwarf_Off off; bool v4type; if (cu == NULL) -- 1.8.3.1
[PATCH] libdw: Check validity of dwarf_getabbrev arguments.
When the given Dwarf_Die was invalid we might crash and when the offset was totally bogus we might succeed with a random abbrev. Signed-off-by: Mark Wielaard --- libdw/ChangeLog | 4 libdw/dwarf_getabbrev.c | 20 +--- tests/ChangeLog | 5 + tests/get-units-invalid.c | 6 ++ tests/show-abbrev.c | 8 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 21cb03c..1195cf6 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,5 +1,9 @@ 2018-06-08 Mark Wielaard + * dwarf_getabbrev.c (dwarf_getabbrev): Check die and offset. + +2018-06-08 Mark Wielaard + * dwarf_get_units.c (dwarf_get_units): Handle existing error, no dwarf. diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c index 1e113db..988d12c 100644 --- a/libdw/dwarf_getabbrev.c +++ b/libdw/dwarf_getabbrev.c @@ -158,7 +158,21 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset, Dwarf_Abbrev * dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, size_t *lengthp) { - return __libdw_getabbrev (die->cu->dbg, die->cu, - die->cu->orig_abbrev_offset + offset, lengthp, - NULL); + if (die == NULL || die->cu == NULL) +return NULL; + + Dwarf_CU *cu = die->cu; + Dwarf *dbg = cu->dbg; + Dwarf_Off abbrev_offset = cu->orig_abbrev_offset; + Elf_Data *data = dbg->sectiondata[IDX_debug_abbrev]; + if (data == NULL) +return NULL; + + if (offset >= data->d_size - abbrev_offset) +{ + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return NULL; +} + + return __libdw_getabbrev (dbg, cu, abbrev_offset + offset, lengthp, NULL); } diff --git a/tests/ChangeLog b/tests/ChangeLog index 25ed41e..3b69a87 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,5 +1,10 @@ 2018-06-08 Mark Wielaard + * get-units-invalid.c (main): Check invalid dwarf_getabbrev call. + * show-abbrev.c (main): Check illegal dwarf_getabbrev offset call. + +2018-06-08 Mark Wielaard + * varlocs.c (main): Only assert when cfi_debug_bias != 0 if there actually is a cfi_debug. diff --git a/tests/get-units-invalid.c b/tests/get-units-invalid.c index ba0f818..155e12d 100644 --- a/tests/get-units-invalid.c +++ b/tests/get-units-invalid.c @@ -98,6 +98,12 @@ main (int argc, char *argv[]) dwarf_diename (&subdie)); return -1; } + if (dwarf_getabbrev (&subdie, 0, NULL) != NULL) + { + printf ("Should NOT have an abbrev: %s\n", + dwarf_diename (&subdie)); + return -1; + } } else if (unit_type == DW_UT_type) printf ("subdie: %s\n", dwarf_diename (&subdie)); diff --git a/tests/show-abbrev.c b/tests/show-abbrev.c index b0af029..002ae25 100644 --- a/tests/show-abbrev.c +++ b/tests/show-abbrev.c @@ -51,6 +51,14 @@ main (int argc, char *argv[]) /* Something went wrong. */ break; + /* Test something obviously wrong. */ + Dwarf_Abbrev *a = dwarf_getabbrev (&die, (Dwarf_Off) -1, NULL); + if (a != NULL) + { + printf ("dwarf_getabbrev -1 succeeded?\n"); + break; + } + Dwarf_Off offset = 0; while (1) -- 1.8.3.1
[PATCH] tests: Don't assert on bad DW_OP_GNU_parameter_ref target in varlocs.
If the target of a DW_OP_GNU_parameter_ref isn't a DW_TAG_formal_parameter that is bad data (which varlocs should error on). But it isn't an internal consistency check (for which varlocs should assert). Signed-off-by: Mark Wielaard --- tests/ChangeLog | 5 + tests/varlocs.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/ChangeLog b/tests/ChangeLog index 3b69a87..e5df211 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,5 +1,10 @@ 2018-06-08 Mark Wielaard + * varlocs.c (print_expr): Error on bad DW_OP_GNU_parameter_ref + target, do not assert. + +2018-06-08 Mark Wielaard + * get-units-invalid.c (main): Check invalid dwarf_getabbrev call. * show-abbrev.c (main): Check illegal dwarf_getabbrev offset call. diff --git a/tests/varlocs.c b/tests/varlocs.c index 99c3887..f4a711c 100644 --- a/tests/varlocs.c +++ b/tests/varlocs.c @@ -546,7 +546,8 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr) // XXX actually lookup DW_TAG_GNU_call_site_parameter printf ("%s[%" PRIx64 "]", opname, dwarf_dieoffset (¶m)); assert (expr->number == dwarf_cuoffset (¶m)); - assert (dwarf_tag (¶m) == DW_TAG_formal_parameter); + if (dwarf_tag (¶m) != DW_TAG_formal_parameter) + error (EXIT_FAILURE, 0, "Not a formal parameter"); } break; -- 1.8.3.1
[PATCH] readelf: Calculate max_entries instead of needed bytes (and overflowing).
The afl fuzzer found that we would overflow the needed bytes when calculating how many index entries would fit in the .debug_loclists and .debug_rnglists tables. To fix this just calculate the max number of entries. If the offset entry count is larger than that, do emit an error, but print up to max_entries of offsets (so the user can more clearly see what is wrong with their table). Signed-off-by: Mark Wielaard --- src/ChangeLog | 7 +++ src/readelf.c | 12 ++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index ca1917a..8ebb5fb 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,12 @@ 2018-06-08 Mark Wielaard + * readelf.c (print_debug_rnglists_section): Calculate max_entries + instead of needed bytes to prevent overflowing. Always print + max_entries (but not more). + (print_debug_loclists_section): Likewise. + +2018-06-08 Mark Wielaard + * readelf.c (print_debug_line_section): Stop printing directories and files when we are at the end of the unit data. diff --git a/src/readelf.c b/src/readelf.c index af78f17..bbaaf96 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -5656,12 +5656,12 @@ print_debug_rnglists_section (Dwfl_Module *dwflmod, const unsigned char *offset_array_start = readp; if (offset_entry_count > 0) { - uint64_t needed = offset_entry_count * offset_size; - if (unit_length - 8 < needed) + uint64_t max_entries = (unit_length - 8) / offset_size; + if (offset_entry_count > max_entries) { error (0, 0, gettext ("too many offset entries for unit length")); - goto next_table; + offset_entry_count = max_entries; } printf (gettext (" Offsets starting at 0x%" PRIx64 ":\n"), @@ -8864,12 +8864,12 @@ print_debug_loclists_section (Dwfl_Module *dwflmod, const unsigned char *offset_array_start = readp; if (offset_entry_count > 0) { - uint64_t needed = offset_entry_count * offset_size; - if (unit_length - 8 < needed) + uint64_t max_entries = (unit_length - 8) / offset_size; + if (offset_entry_count > max_entries) { error (0, 0, gettext ("too many offset entries for unit length")); - goto next_table; + offset_entry_count = max_entries; } printf (gettext (" Offsets starting at 0x%" PRIx64 ":\n"), -- 1.8.3.1