From 06614111d1be94b43ea8dd83805184d4e177bcea Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 1 Dec 2014 16:43:46 +0000 Subject: [PATCH] More fixes for memory access violations exposed by fuzzed binaries. PR binutils/17512 * dwarf.h (struct dwarf_section): Add user_data field. * dwarf.c (frame_need_space): Check for an over large register number. (display_debug_frames): Check the return value from frame_need_space. Check for a CFA expression that is so long the start address wraps around. (debug_displays): Initialise the user_data field. * objdump.c (load_specific_debug_section): Save the BFD section pointer in the user_data field of the dwarf_section structure. (free_debug_section): Update BFD section data when freeing section contents. * readelf.c (load_specific_debug_section): Initialise the user_data field. * archive.c (do_slurp_coff_armap): Add range checks to prevent running off the end of the string table. * compress.c (bfd_get_full_section_contents): Return a NULL pointer for zero sized sections. Do not attempt to copy a buffer onto itself. * elf-attrs.c (_bfd_elf_parse_attributes): Check for an empty header. Add range checks to avoid running off the end of the section. * elf.c (bfd_elf_get_str_section): Seek before allocating so that if the seek fails, no memory is allocated. (bfd_elf_string_from_elf_section): Do not allocate a string from a non string section. It only leads to trouble later on. (_bfd_elf_print_private_bfd_data): Check for there being too little external dynamic data. (bfd_section_from_shdr): Replace assertion with a failure mode. (bfd_section_from_shdr): When walking a loaded group section use the internal structure size, not the external size. Check for the group section being empty. * elf32-i386.c (elf_i386_rtype_to_howto): Replace assertion with a failure mode. * elfcode.h (elf_slurp_reloc_table): Likewise. * reloc.c (bfd_perform_relocation): Avoid seg-fault if the howto parameter is NULL. --- bfd/ChangeLog | 27 +++++++++++ bfd/archive.c | 11 ++++- bfd/compress.c | 13 +++-- bfd/elf-attrs.c | 16 ++++-- bfd/elf.c | 36 +++++++++++--- bfd/elf32-i386.c | 4 +- bfd/elfcode.h | 4 +- bfd/reloc.c | 4 ++ binutils/ChangeLog | 17 +++++++ binutils/dwarf.c | 118 ++++++++++++++++++++++++++++----------------- binutils/dwarf.h | 2 + binutils/objdump.c | 17 +++++++ binutils/readelf.c | 1 + 13 files changed, 207 insertions(+), 63 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 8bcbc1184e3..0489b79b066 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,30 @@ +2014-12-01 Nick Clifton + + PR binutils/17512 + * archive.c (do_slurp_coff_armap): Add range checks to prevent + running off the end of the string table. + * compress.c (bfd_get_full_section_contents): Return a NULL + pointer for zero sized sections. Do not attempt to copy a buffer + onto itself. + * elf-attrs.c (_bfd_elf_parse_attributes): Check for an empty + header. Add range checks to avoid running off the end of the + section. + * elf.c (bfd_elf_get_str_section): Seek before allocating so that + if the seek fails, no memory is allocated. + (bfd_elf_string_from_elf_section): Do not allocate a string from a + non string section. It only leads to trouble later on. + (_bfd_elf_print_private_bfd_data): Check for there being too + little external dynamic data. + (bfd_section_from_shdr): Replace assertion with a failure mode. + (bfd_section_from_shdr): When walking a loaded group section use + the internal structure size, not the external size. Check for the + group section being empty. + * elf32-i386.c (elf_i386_rtype_to_howto): Replace assertion with a + failure mode. + * elfcode.h (elf_slurp_reloc_table): Likewise. + * reloc.c (bfd_perform_relocation): Avoid seg-fault if the howto + parameter is NULL. + 2014-11-30 Alan Modra PR 16452, 16457 diff --git a/bfd/archive.c b/bfd/archive.c index df37996d74b..0ab4f6e103c 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -1038,12 +1038,19 @@ do_slurp_coff_armap (bfd *abfd) } /* OK, build the carsyms. */ - for (i = 0; i < nsymz; i++) + for (i = 0; i < nsymz && stringsize > 0; i++) { + bfd_size_type len; + rawptr = raw_armap + i; carsyms->file_offset = swap ((bfd_byte *) rawptr); carsyms->name = stringbase; - stringbase += strlen (stringbase) + 1; + /* PR 17512: file: 4a1d50c1. */ + len = strnlen (stringbase, stringsize); + if (len < stringsize) + len ++; + stringbase += len; + stringsize -= len; carsyms++; } *stringbase = 0; diff --git a/bfd/compress.c b/bfd/compress.c index 20eef952826..3fcbd783ee4 100644 --- a/bfd/compress.c +++ b/bfd/compress.c @@ -152,7 +152,8 @@ DESCRIPTION return @var{*ptr} with memory malloc'd by this function. Return @code{TRUE} if the full section contents is retrieved - successfully. + successfully. If the section has no contents then this function + returns @code{TRUE} but @var{*ptr} is set to NULL. */ bfd_boolean @@ -172,7 +173,10 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) else sz = sec->size; if (sz == 0) - return TRUE; + { + *ptr = NULL; + return TRUE; + } switch (sec->compress_status) { @@ -183,6 +187,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) if (p == NULL) return FALSE; } + if (!bfd_get_section_contents (abfd, sec, p, 0, sz)) { if (*ptr != p) @@ -246,7 +251,9 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) return FALSE; *ptr = p; } - memcpy (p, sec->contents, sz); + /* PR 17512; file: 5bc29788. */ + if (p != sec->contents) + memcpy (p, sec->contents, sz); return TRUE; default: diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c index 6bc2944c7bf..25f7e2672d7 100644 --- a/bfd/elf-attrs.c +++ b/bfd/elf-attrs.c @@ -430,9 +430,13 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) { bfd_byte *contents; bfd_byte *p; + bfd_byte *p_end; bfd_vma len; const char *std_sec; + /* PR 17512: file: 2844a11d. */ + if (hdr->sh_size == 0) + return; contents = (bfd_byte *) bfd_malloc (hdr->sh_size); if (!contents) return; @@ -443,11 +447,14 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) return; } p = contents; + p_end = p + hdr->sh_size; std_sec = get_elf_backend_data (abfd)->obj_attrs_vendor; + if (*(p++) == 'A') { len = hdr->sh_size - 1; - while (len > 0) + + while (len > 0 && p < p_end - 4) { unsigned namelen; bfd_vma section_len; @@ -477,7 +484,7 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) } p += namelen; - while (section_len > 0) + while (section_len > 0 && p < p_end) { int tag; unsigned int n; @@ -487,7 +494,10 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) tag = read_unsigned_leb128 (abfd, p, &n); p += n; - subsection_len = bfd_get_32 (abfd, p); + if (p < p_end - 4) + subsection_len = bfd_get_32 (abfd, p); + else + subsection_len = 0; p += 4; if (subsection_len == 0) break; diff --git a/bfd/elf.c b/bfd/elf.c index 07cb8044181..405ec332b37 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -297,13 +297,14 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) /* Allocate and clear an extra byte at the end, to prevent crashes in case the string table is not terminated. */ if (shstrtabsize + 1 <= 1 - || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL - || bfd_seek (abfd, offset, SEEK_SET) != 0) + || bfd_seek (abfd, offset, SEEK_SET) != 0 + || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL) shstrtab = NULL; else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_file_truncated); + bfd_release (abfd, shstrtab); shstrtab = NULL; /* Once we've failed to read it, make sure we don't keep trying. Otherwise, we'll keep allocating space for @@ -332,9 +333,19 @@ bfd_elf_string_from_elf_section (bfd *abfd, hdr = elf_elfsections (abfd)[shindex]; - if (hdr->contents == NULL - && bfd_elf_get_str_section (abfd, shindex) == NULL) - return NULL; + if (hdr->contents == NULL) + { + if (hdr->sh_type != SHT_STRTAB && hdr->sh_type < SHT_LOOS) + { + /* PR 17512: file: f057ec89. */ + _bfd_error_handler (_("%B: attempt to load strings from a non-string section (number %d)"), + abfd, shindex); + return NULL; + } + + if (bfd_elf_get_str_section (abfd, shindex) == NULL) + return NULL; + } if (strindex >= hdr->sh_size) { @@ -636,6 +647,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) pointers. */ src = shdr->contents + shdr->sh_size; dest = (Elf_Internal_Group *) (shdr->contents + amt); + while (1) { unsigned int idx; @@ -1253,6 +1265,9 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; extdyn = dynbuf; + /* PR 17512: file: 6f427532. */ + if (s->size < extdynsize) + goto error_return; extdynend = extdyn + s->size; /* PR 17512: file: id:000006,sig:06,src:000000,op:flip4,pos:5664. Fix range check. */ @@ -1607,7 +1622,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (++ nesting > 3) { /* PR17512: A corrupt ELF binary might contain a recursive group of - sections, each the string indicies pointing to the next in the + sections, with each the string indicies pointing to the next in the loop. Detect this here, by refusing to load a section that we are already in the process of loading. We only trigger this test if we have nested at least three sections deep as normal ELF binaries @@ -1974,7 +1989,9 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) else p_hdr = &esdt->rel.hdr; - BFD_ASSERT (*p_hdr == NULL); + /* PR 17512: file: 0b4f81b7. */ + if (*p_hdr != NULL) + goto fail; amt = sizeof (*hdr2); hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); if (hdr2 == NULL) @@ -2031,15 +2048,18 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (hdr->contents != NULL) { Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents; - unsigned int n_elt = hdr->sh_size / GRP_ENTRY_SIZE; + unsigned int n_elt = hdr->sh_size / sizeof (* idx); asection *s; + if (n_elt == 0) + goto fail; if (idx->flags & GRP_COMDAT) hdr->bfd_section->flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; /* We try to keep the same section order as it comes in. */ idx += n_elt; + while (--n_elt != 0) { --idx; diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 5c35d6509d1..dcf37b14a86 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -379,7 +379,9 @@ elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type) abfd, (int) r_type); indx = R_386_NONE; } - BFD_ASSERT (elf_howto_table [indx].type == r_type); + /* PR 17512: file: 0f67f69d. */ + if (elf_howto_table [indx].type != r_type) + return NULL; return &elf_howto_table[indx]; } diff --git a/bfd/elfcode.h b/bfd/elfcode.h index ec53c3bbd8f..d34e18ed080 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -1501,7 +1501,9 @@ elf_slurp_reloc_table (bfd *abfd, rel_hdr2 = d->rela.hdr; reloc_count2 = rel_hdr2 ? NUM_SHDR_ENTRIES (rel_hdr2) : 0; - BFD_ASSERT (asect->reloc_count == reloc_count + reloc_count2); + /* PR 17512: file: 0b4f81b7. */ + if (asect->reloc_count != reloc_count + reloc_count2) + return FALSE; BFD_ASSERT ((rel_hdr && asect->rel_filepos == rel_hdr->sh_offset) || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset)); diff --git a/bfd/reloc.c b/bfd/reloc.c index dedfb6a4f98..89e46f39d39 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -592,6 +592,10 @@ bfd_perform_relocation (bfd *abfd, return bfd_reloc_ok; } + /* PR 17512: file: 0f67f69d. */ + if (howto == NULL) + return bfd_reloc_undefined; + /* If we are not producing relocatable output, return an error if the symbol is not defined. An undefined weak symbol is considered to have a value of zero (SVR4 ABI, p. 4-27). */ diff --git a/binutils/ChangeLog b/binutils/ChangeLog index ecb7c8bf8e9..597e52a28ee 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,20 @@ +2014-12-01 Nick Clifton + + PR binutils/17512 + * dwarf.h (struct dwarf_section): Add user_data field. + * dwarf.c (frame_need_space): Check for an over large register + number. + (display_debug_frames): Check the return value from + frame_need_space. Check for a CFA expression that is so long the + start address wraps around. + (debug_displays): Initialise the user_data field. + * objdump.c (load_specific_debug_section): Save the BFD section + pointer in the user_data field of the dwarf_section structure. + (free_debug_section): Update BFD section data when freeing section + contents. + * readelf.c (load_specific_debug_section): Initialise the + user_data field. + 2014-12-01 Nick Clifton PR binutils/17531 diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 5f953d51187..d744929c02d 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -5157,6 +5157,16 @@ frame_need_space (Frame_Chunk *fc, unsigned int reg) if (fc->ncols == 0) return -1; + /* PR 17512: file: 2844a11d. */ + if (fc->ncols > 1024) + { + error (_("Unfeasibly large register number: %u\n"), reg); + fc->ncols = 0; + /* FIXME: 1024 is an arbitrary limit. Increase it if + we ever encounter a valid binary that exceeds it. */ + return -1; + } + fc->col_type = (short int *) xcrealloc (fc->col_type, fc->ncols, sizeof (short int)); fc->col_offset = (int *) xcrealloc (fc->col_offset, fc->ncols, sizeof (int)); @@ -5590,7 +5600,8 @@ display_debug_frames (struct dwarf_section *section, mreg = max_regs > 0 ? max_regs - 1 : 0; if (mreg < fc->ra) mreg = fc->ra; - frame_need_space (fc, mreg); + if (frame_need_space (fc, mreg) < 0) + break; if (fc->fde_encoding) encoded_ptr_size = size_of_encoded_value (fc->fde_encoding); @@ -5696,7 +5707,11 @@ display_debug_frames (struct dwarf_section *section, mreg = max_regs > 0 ? max_regs - 1 : 0; if (mreg < cie->ra) mreg = cie->ra; - frame_need_space (cie, mreg); + if (frame_need_space (cie, mreg) < 0) + { + warn (_("Invalid max register\n")); + break; + } if (cie->fde_encoding) encoded_ptr_size = size_of_encoded_value (cie->fde_encoding); @@ -5716,7 +5731,11 @@ display_debug_frames (struct dwarf_section *section, fc->ncols = 0; fc->col_type = (short int *) xmalloc (sizeof (short int)); fc->col_offset = (int *) xmalloc (sizeof (int)); - frame_need_space (fc, max_regs > 0 ? max_regs - 1 : 0); + if (frame_need_space (fc, max_regs > 0 ? max_regs - 1 : 0) < 0) + { + warn (_("Invalid max register\n")); + break; + } cie = fc; fc->augmentation = ""; fc->fde_encoding = 0; @@ -5739,7 +5758,11 @@ display_debug_frames (struct dwarf_section *section, fc->cfa_reg = cie->cfa_reg; fc->cfa_offset = cie->cfa_offset; fc->ra = cie->ra; - frame_need_space (fc, max_regs > 0 ? max_regs - 1: 0); + if (frame_need_space (fc, max_regs > 0 ? max_regs - 1: 0) < 0) + { + warn (_("Invalid max register\n")); + break; + } fc->fde_encoding = cie->fde_encoding; } @@ -5857,7 +5880,6 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_restore_extended: reg = LEB (); - frame_need_space (fc, reg); if (frame_need_space (fc, reg) >= 0) fc->col_type[reg] = DW_CFA_undefined; break; @@ -6176,7 +6198,12 @@ display_debug_frames (struct dwarf_section *section, fc->cfa_reg = rs->cfa_reg; fc->ra = rs->ra; fc->cfa_exp = rs->cfa_exp; - frame_need_space (fc, rs->ncols - 1); + if (frame_need_space (fc, rs->ncols - 1) < 0) + { + warn (_("Invalid column number in saved frame state")); + fc->ncols = 0; + break; + } memcpy (fc->col_type, rs->col_type, rs->ncols * sizeof (* rs->col_type)); memcpy (fc->col_offset, rs->col_offset, rs->ncols * sizeof (* rs->col_offset)); @@ -6218,7 +6245,7 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_def_cfa_expression: ul = LEB (); - if (start >= block_end || start + ul > block_end) + if (start >= block_end || start + ul > block_end || start + ul < start) { printf (_(" DW_CFA_def_cfa_expression: \n"), ul); break; @@ -6240,7 +6267,8 @@ display_debug_frames (struct dwarf_section *section, if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; /* PR 17512: file: 069-133014-0.006. */ - if (start >= block_end || start + ul > block_end) + /* PR 17512: file: 98c02eb4. */ + if (start >= block_end || start + ul > block_end || start + ul < start) { printf (_(" DW_CFA_expression: \n"), ul); break; @@ -6263,7 +6291,7 @@ display_debug_frames (struct dwarf_section *section, ul = LEB (); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; - if (start >= block_end || start + ul > block_end) + if (start >= block_end || start + ul > block_end || start + ul < start) { printf (" DW_CFA_val_expression: \n", ul); break; @@ -7189,76 +7217,76 @@ dwarf_select_sections_all (void) struct dwarf_section_display debug_displays[] = { - { { ".debug_abbrev", ".zdebug_abbrev", NULL, NULL, 0, 0, 0 }, + { { ".debug_abbrev", ".zdebug_abbrev", NULL, NULL, 0, 0, 0, NULL }, display_debug_abbrev, &do_debug_abbrevs, 0 }, - { { ".debug_aranges", ".zdebug_aranges", NULL, NULL, 0, 0, 0 }, + { { ".debug_aranges", ".zdebug_aranges", NULL, NULL, 0, 0, 0, NULL }, display_debug_aranges, &do_debug_aranges, 1 }, - { { ".debug_frame", ".zdebug_frame", NULL, NULL, 0, 0, 0 }, + { { ".debug_frame", ".zdebug_frame", NULL, NULL, 0, 0, 0, NULL }, display_debug_frames, &do_debug_frames, 1 }, - { { ".debug_info", ".zdebug_info", NULL, NULL, 0, 0, abbrev }, + { { ".debug_info", ".zdebug_info", NULL, NULL, 0, 0, abbrev, NULL }, display_debug_info, &do_debug_info, 1 }, - { { ".debug_line", ".zdebug_line", NULL, NULL, 0, 0, 0 }, + { { ".debug_line", ".zdebug_line", NULL, NULL, 0, 0, 0, NULL }, display_debug_lines, &do_debug_lines, 1 }, - { { ".debug_pubnames", ".zdebug_pubnames", NULL, NULL, 0, 0, 0 }, + { { ".debug_pubnames", ".zdebug_pubnames", NULL, NULL, 0, 0, 0, NULL }, display_debug_pubnames, &do_debug_pubnames, 0 }, - { { ".debug_gnu_pubnames", ".zdebug_gnu_pubnames", NULL, NULL, 0, 0, 0 }, + { { ".debug_gnu_pubnames", ".zdebug_gnu_pubnames", NULL, NULL, 0, 0, 0, NULL }, display_debug_gnu_pubnames, &do_debug_pubnames, 0 }, - { { ".eh_frame", "", NULL, NULL, 0, 0, 0 }, + { { ".eh_frame", "", NULL, NULL, 0, 0, 0, NULL }, display_debug_frames, &do_debug_frames, 1 }, - { { ".debug_macinfo", ".zdebug_macinfo", NULL, NULL, 0, 0, 0 }, + { { ".debug_macinfo", ".zdebug_macinfo", NULL, NULL, 0, 0, 0, NULL }, display_debug_macinfo, &do_debug_macinfo, 0 }, - { { ".debug_macro", ".zdebug_macro", NULL, NULL, 0, 0, 0 }, + { { ".debug_macro", ".zdebug_macro", NULL, NULL, 0, 0, 0, NULL }, display_debug_macro, &do_debug_macinfo, 1 }, - { { ".debug_str", ".zdebug_str", NULL, NULL, 0, 0, 0 }, + { { ".debug_str", ".zdebug_str", NULL, NULL, 0, 0, 0, NULL }, display_debug_str, &do_debug_str, 0 }, - { { ".debug_loc", ".zdebug_loc", NULL, NULL, 0, 0, 0 }, + { { ".debug_loc", ".zdebug_loc", NULL, NULL, 0, 0, 0, NULL }, display_debug_loc, &do_debug_loc, 1 }, - { { ".debug_pubtypes", ".zdebug_pubtypes", NULL, NULL, 0, 0, 0 }, + { { ".debug_pubtypes", ".zdebug_pubtypes", NULL, NULL, 0, 0, 0, NULL }, display_debug_pubnames, &do_debug_pubtypes, 0 }, - { { ".debug_gnu_pubtypes", ".zdebug_gnu_pubtypes", NULL, NULL, 0, 0, 0 }, + { { ".debug_gnu_pubtypes", ".zdebug_gnu_pubtypes", NULL, NULL, 0, 0, 0, NULL }, display_debug_gnu_pubnames, &do_debug_pubtypes, 0 }, - { { ".debug_ranges", ".zdebug_ranges", NULL, NULL, 0, 0, 0 }, + { { ".debug_ranges", ".zdebug_ranges", NULL, NULL, 0, 0, 0, NULL }, display_debug_ranges, &do_debug_ranges, 1 }, - { { ".debug_static_func", ".zdebug_static_func", NULL, NULL, 0, 0, 0 }, + { { ".debug_static_func", ".zdebug_static_func", NULL, NULL, 0, 0, 0, NULL }, display_debug_not_supported, NULL, 0 }, - { { ".debug_static_vars", ".zdebug_static_vars", NULL, NULL, 0, 0, 0 }, + { { ".debug_static_vars", ".zdebug_static_vars", NULL, NULL, 0, 0, 0, NULL }, display_debug_not_supported, NULL, 0 }, - { { ".debug_types", ".zdebug_types", NULL, NULL, 0, 0, abbrev }, + { { ".debug_types", ".zdebug_types", NULL, NULL, 0, 0, abbrev, NULL }, display_debug_types, &do_debug_info, 1 }, - { { ".debug_weaknames", ".zdebug_weaknames", NULL, NULL, 0, 0, 0 }, + { { ".debug_weaknames", ".zdebug_weaknames", NULL, NULL, 0, 0, 0, NULL }, display_debug_not_supported, NULL, 0 }, - { { ".gdb_index", "", NULL, NULL, 0, 0, 0 }, + { { ".gdb_index", "", NULL, NULL, 0, 0, 0, NULL }, display_gdb_index, &do_gdb_index, 0 }, - { { ".trace_info", "", NULL, NULL, 0, 0, trace_abbrev }, + { { ".trace_info", "", NULL, NULL, 0, 0, trace_abbrev, NULL }, display_trace_info, &do_trace_info, 1 }, - { { ".trace_abbrev", "", NULL, NULL, 0, 0, 0 }, + { { ".trace_abbrev", "", NULL, NULL, 0, 0, 0, NULL }, display_debug_abbrev, &do_trace_abbrevs, 0 }, - { { ".trace_aranges", "", NULL, NULL, 0, 0, 0 }, + { { ".trace_aranges", "", NULL, NULL, 0, 0, 0, NULL }, display_debug_aranges, &do_trace_aranges, 0 }, - { { ".debug_info.dwo", ".zdebug_info.dwo", NULL, NULL, 0, 0, abbrev_dwo }, + { { ".debug_info.dwo", ".zdebug_info.dwo", NULL, NULL, 0, 0, abbrev_dwo, NULL }, display_debug_info, &do_debug_info, 1 }, - { { ".debug_abbrev.dwo", ".zdebug_abbrev.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_abbrev.dwo", ".zdebug_abbrev.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_abbrev, &do_debug_abbrevs, 0 }, - { { ".debug_types.dwo", ".zdebug_types.dwo", NULL, NULL, 0, 0, abbrev_dwo }, + { { ".debug_types.dwo", ".zdebug_types.dwo", NULL, NULL, 0, 0, abbrev_dwo, NULL }, display_debug_types, &do_debug_info, 1 }, - { { ".debug_line.dwo", ".zdebug_line.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_line.dwo", ".zdebug_line.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_lines, &do_debug_lines, 1 }, - { { ".debug_loc.dwo", ".zdebug_loc.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_loc.dwo", ".zdebug_loc.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_loc, &do_debug_loc, 1 }, - { { ".debug_macro.dwo", ".zdebug_macro.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_macro.dwo", ".zdebug_macro.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_macro, &do_debug_macinfo, 1 }, - { { ".debug_macinfo.dwo", ".zdebug_macinfo.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_macinfo.dwo", ".zdebug_macinfo.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_macinfo, &do_debug_macinfo, 0 }, - { { ".debug_str.dwo", ".zdebug_str.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_str.dwo", ".zdebug_str.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_str, &do_debug_str, 1 }, - { { ".debug_str_offsets", ".zdebug_str_offsets", NULL, NULL, 0, 0, 0 }, + { { ".debug_str_offsets", ".zdebug_str_offsets", NULL, NULL, 0, 0, 0, NULL }, display_debug_str_offsets, NULL, 0 }, - { { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo", NULL, NULL, 0, 0, 0 }, + { { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo", NULL, NULL, 0, 0, 0, NULL }, display_debug_str_offsets, NULL, 0 }, - { { ".debug_addr", ".zdebug_addr", NULL, NULL, 0, 0, 0 }, + { { ".debug_addr", ".zdebug_addr", NULL, NULL, 0, 0, 0, NULL }, display_debug_addr, &do_debug_addr, 1 }, - { { ".debug_cu_index", "", NULL, NULL, 0, 0, 0 }, + { { ".debug_cu_index", "", NULL, NULL, 0, 0, 0, NULL }, display_cu_index, &do_debug_cu_index, 0 }, - { { ".debug_tu_index", "", NULL, NULL, 0, 0, 0 }, + { { ".debug_tu_index", "", NULL, NULL, 0, 0, 0, NULL }, display_cu_index, &do_debug_cu_index, 0 }, }; diff --git a/binutils/dwarf.h b/binutils/dwarf.h index 124d9d6d358..bd62892c4f5 100644 --- a/binutils/dwarf.h +++ b/binutils/dwarf.h @@ -164,6 +164,8 @@ struct dwarf_section dwarf_vma address; dwarf_size_type size; enum dwarf_section_display_enum abbrev_sec; + /* A spare field for random use. */ + void *user_data; }; /* A structure containing the name of a debug section diff --git a/binutils/objdump.c b/binutils/objdump.c index fdfa60250c2..b13bf00e699 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -2280,6 +2280,7 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, section->address = bfd_get_section_vma (abfd, sec); section->size = bfd_get_section_size (sec); section->start = NULL; + section->user_data = sec; ret = bfd_get_full_section_contents (abfd, sec, §ion->start); if (! ret) @@ -2346,6 +2347,22 @@ free_debug_section (enum dwarf_section_display_enum debug) if (section->start == NULL) return; + /* PR 17512: file: 0f67f69d. */ + if (section->user_data != NULL) + { + asection * sec = (asection *) section->user_data; + + /* If we are freeing contents that are also pointed to by the BFD + library's section structure then make sure to update those pointers + too. Otherwise, the next time we try to load data for this section + we can end up using a stale pointer. */ + if (section->start == sec->contents) + { + sec->contents = NULL; + sec->flags &= ~ SEC_IN_MEMORY; + } + } + free ((char *) section->start); section->start = NULL; section->address = 0; diff --git a/binutils/readelf.c b/binutils/readelf.c index 4e16bd62bc9..200475232a8 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -11713,6 +11713,7 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, snprintf (buf, sizeof (buf), _("%s section data"), section->name); section->address = sec->sh_addr; + section->user_data = NULL; section->start = (unsigned char *) get_data (NULL, (FILE *) file, sec->sh_offset, 1, sec->sh_size, buf); -- 2.30.2