X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Freadelf.c;h=fea372fd4bb449b98595a412d56bd2db724b5005;hb=c58212eaf957ef39484ed71316074fd8366e9c4a;hp=e8ce2793404b783772d8f7fbfd0556189ed1d3de;hpb=5d921cbd81554867007e903b634acc6bc8281f9f;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/readelf.c b/binutils/readelf.c index e8ce279340..fea372fd4b 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -1,5 +1,5 @@ /* readelf.c -- display contents of an ELF format file - Copyright (C) 1998-2014 Free Software Foundation, Inc. + Copyright (C) 1998-2015 Free Software Foundation, Inc. Originally developed by Eric Youngdale Modifications by Nick Clifton @@ -43,9 +43,7 @@ #include "sysdep.h" #include #include -#ifdef HAVE_ZLIB_H #include -#endif #ifdef HAVE_WCHAR_H #include #endif @@ -106,6 +104,7 @@ #include "elf/epiphany.h" #include "elf/fr30.h" #include "elf/frv.h" +#include "elf/ft32.h" #include "elf/h8.h" #include "elf/hppa.h" #include "elf/i386.h" @@ -149,6 +148,7 @@ #include "elf/tilepro.h" #include "elf/v850.h" #include "elf/vax.h" +#include "elf/visium.h" #include "elf/x86-64.h" #include "elf/xc16x.h" #include "elf/xgate.h" @@ -165,7 +165,7 @@ #endif char * program_name = "readelf"; -static long archive_file_offset; +static unsigned long archive_file_offset; static unsigned long archive_file_size; static bfd_size_type current_file_size; static unsigned long dynamic_addr; @@ -272,6 +272,20 @@ typedef enum print_mode } print_mode; +/* Versioned symbol info. */ +enum versioned_symbol_info +{ + symbol_undefined, + symbol_hidden, + symbol_public +}; + +static const char *get_symbol_version_string + (FILE *file, int is_dynsym, const char *strtab, + unsigned long int strtab_size, unsigned int si, + Elf_Internal_Sym *psym, enum versioned_symbol_info *sym_info, + unsigned short *vna_other); + #define UNKNOWN -1 #define SECTION_NAME(X) \ @@ -299,36 +313,62 @@ print_mode; } \ while (0) -/* Retrieve NMEMB structures, each SIZE bytes long from FILE starting at OFFSET. +/* Retrieve NMEMB structures, each SIZE bytes long from FILE starting at OFFSET + + the offset of the current archive member, if we are examining an archive. Put the retrieved data into VAR, if it is not NULL. Otherwise allocate a buffer using malloc and fill that. In either case return the pointer to the start of the retrieved data or NULL if something went wrong. If something does go wrong - emit an error message using REASON as part of the context. */ + and REASON is not NULL then emit an error message using REASON as part of the + context. */ static void * -get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb, - const char * reason) +get_data (void * var, FILE * file, unsigned long offset, bfd_size_type size, + bfd_size_type nmemb, const char * reason) { void * mvar; + bfd_size_type amt = size * nmemb; if (size == 0 || nmemb == 0) return NULL; - if (fseek (file, archive_file_offset + offset, SEEK_SET)) + /* If the size_t type is smaller than the bfd_size_type, eg because + you are building a 32-bit tool on a 64-bit host, then make sure + that when the sizes are cast to (size_t) no information is lost. */ + if (sizeof (size_t) < sizeof (bfd_size_type) + && ( (bfd_size_type) ((size_t) size) != size + || (bfd_size_type) ((size_t) nmemb) != nmemb)) { if (reason) - error (_("Unable to seek to 0x%lx for %s\n"), - (unsigned long) archive_file_offset + offset, reason); + error (_("Size truncation prevents reading 0x%llx elements of size 0x%llx for %s\n"), + (unsigned long long) nmemb, (unsigned long long) size, reason); + return NULL; + } + + /* Check for size overflow. */ + if (amt < nmemb) + { + if (reason) + error (_("Size overflow prevents reading 0x%llx elements of size 0x%llx for %s\n"), + (unsigned long long) nmemb, (unsigned long long) size, reason); return NULL; } /* Be kind to memory chekers (eg valgrind, address sanitizer) by not attempting to allocate memory when the read is bound to fail. */ - if (offset + archive_file_offset + size * nmemb > current_file_size) + if (amt > current_file_size + || offset + archive_file_offset + amt > current_file_size) + { + if (reason) + error (_("Reading 0x%llx bytes extends past end of file for %s\n"), + (unsigned long long) amt, reason); + return NULL; + } + + if (fseek (file, archive_file_offset + offset, SEEK_SET)) { if (reason) - error (_("Reading 0x%lx bytes extends past end of file for %s\n"), - (unsigned long) (size * nmemb), reason); + error (_("Unable to seek to 0x%lx for %s\n"), + (unsigned long) archive_file_offset + offset, reason); return NULL; } @@ -336,26 +376,26 @@ get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb, if (mvar == NULL) { /* Check for overflow. */ - if (nmemb < (~(size_t) 0 - 1) / size) + if (nmemb < (~(bfd_size_type) 0 - 1) / size) /* + 1 so that we can '\0' terminate invalid string table sections. */ - mvar = malloc (size * nmemb + 1); + mvar = malloc ((size_t) amt + 1); if (mvar == NULL) { if (reason) - error (_("Out of memory allocating 0x%lx bytes for %s\n"), - (unsigned long)(size * nmemb), reason); + error (_("Out of memory allocating 0x%llx bytes for %s\n"), + (unsigned long long) amt, reason); return NULL; } - ((char *) mvar)[size * nmemb] = '\0'; + ((char *) mvar)[amt] = '\0'; } - if (fread (mvar, size, nmemb, file) != nmemb) + if (fread (mvar, (size_t) size, (size_t) nmemb, file) != nmemb) { if (reason) - error (_("Unable to read in 0x%lx bytes of %s\n"), - (unsigned long)(size * nmemb), reason); + error (_("Unable to read in 0x%llx bytes of %s\n"), + (unsigned long long) amt, reason); if (mvar != var) free (mvar); return NULL; @@ -525,7 +565,7 @@ printable_section_name (Elf_Internal_Shdr * sec) { if (remaining < 2) break; - + * buf ++ = '^'; * buf ++ = c + 0x40; remaining -= 2; @@ -690,6 +730,7 @@ guess_is_rela (unsigned int e_machine) case EM_D30V: case EM_CYGNUS_D30V: case EM_FR30: + case EM_FT32: case EM_CYGNUS_FR30: case EM_CYGNUS_FRV: case EM_H8S: @@ -736,6 +777,7 @@ guess_is_rela (unsigned int e_machine) case EM_V850: case EM_CYGNUS_V850: case EM_VAX: + case EM_VISIUM: case EM_X86_64: case EM_L1OM: case EM_K1OM: @@ -1015,7 +1057,8 @@ dump_relocations (FILE * file, unsigned long nsyms, char * strtab, unsigned long strtablen, - int is_rela) + int is_rela, + int is_dynsym) { unsigned int i; Elf_Internal_Rela * rels; @@ -1213,6 +1256,10 @@ dump_relocations (FILE * file, rtype = elf_frv_reloc_type (type); break; + case EM_FT32: + rtype = elf_ft32_reloc_type (type); + break; + case EM_MCORE: rtype = elf_mcore_reloc_type (type); break; @@ -1325,6 +1372,10 @@ dump_relocations (FILE * file, rtype = elf_vax_reloc_type (type); break; + case EM_VISIUM: + rtype = elf_visium_reloc_type (type); + break; + case EM_ADAPTEVA_EPIPHANY: rtype = elf_epiphany_reloc_type (type); break; @@ -1448,9 +1499,20 @@ dump_relocations (FILE * file, else { Elf_Internal_Sym * psym; + const char * version_string; + enum versioned_symbol_info sym_info; + unsigned short vna_other; psym = symtab + symtab_index; + version_string + = get_symbol_version_string (file, is_dynsym, + strtab, strtablen, + symtab_index, + psym, + &sym_info, + &vna_other); + printf (" "); if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC) @@ -1477,6 +1539,9 @@ dump_relocations (FILE * file, name = strtab + psym->st_name; len = print_symbol (width, name); + if (version_string) + printf (sym_info == symbol_public ? "@@%s" : "@%s", + version_string); printf ("()%-*s", len <= width ? (width + 1) - len : 1, " "); } else @@ -1533,13 +1598,21 @@ dump_relocations (FILE * file, else if (psym->st_name >= strtablen) printf (_(""), psym->st_name); else - print_symbol (22, strtab + psym->st_name); + { + print_symbol (22, strtab + psym->st_name); + if (version_string) + printf (sym_info == symbol_public ? "@@%s" : "@%s", + version_string); + } if (is_rela) { bfd_signed_vma off = rels[i].r_addend; - if (off < 0) + /* PR 17531: file: 2e63226f. */ + if (off == ((bfd_signed_vma) 1) << ((sizeof (bfd_signed_vma) * 8) - 1)) + printf (" + %" BFD_VMA_FMT "x", off); + else if (off < 0) printf (" - %" BFD_VMA_FMT "x", - off); else printf (" + %" BFD_VMA_FMT "x", off); @@ -1551,7 +1624,10 @@ dump_relocations (FILE * file, bfd_signed_vma off = rels[i].r_addend; printf ("%*c", is_32bit_elf ? 12 : 20, ' '); - if (off < 0) + /* PR 17531: file: 2e63226f. */ + if (off == ((bfd_signed_vma) 1) << ((sizeof (bfd_signed_vma) * 8) - 1)) + printf ("%" BFD_VMA_FMT "x", off); + else if (off < 0) printf ("-%" BFD_VMA_FMT "x", - off); else printf ("%" BFD_VMA_FMT "x", off); @@ -2028,6 +2104,7 @@ get_machine_name (unsigned e_machine) case EM_PPC: return "PowerPC"; case EM_PPC64: return "PowerPC64"; case EM_FR20: return "Fujitsu FR20"; + case EM_FT32: return "FTDI FT32"; case EM_RH32: return "TRW RH32"; case EM_MCORE: return "MCORE"; case EM_ARM: return "ARM"; @@ -2085,6 +2162,7 @@ get_machine_name (unsigned e_machine) case EM_SVX: return "Silicon Graphics SVx"; case EM_ST19: return "STMicroelectronics ST19 8-bit microcontroller"; case EM_VAX: return "Digital VAX"; + case EM_VISIUM: return "CDS VISIUMcore processor"; case EM_AVR_OLD: case EM_AVR: return "Atmel AVR 8-bit microcontroller"; case EM_CRIS: return "Axis Communications 32-bit embedded processor"; @@ -2200,12 +2278,6 @@ decode_ARM_machine_flags (unsigned e_flags, char buf[]) e_flags &= ~ EF_ARM_RELEXEC; } - if (e_flags & EF_ARM_HASENTRY) - { - strcat (buf, ", has entry point"); - e_flags &= ~ EF_ARM_HASENTRY; - } - /* Now handle EABI specific flags. */ switch (eabi) { @@ -2399,6 +2471,77 @@ decode_ARM_machine_flags (unsigned e_flags, char buf[]) strcat (buf,_(", ")); } +static void +decode_AVR_machine_flags (unsigned e_flags, char buf[], size_t size) +{ + --size; /* Leave space for null terminator. */ + + switch (e_flags & EF_AVR_MACH) + { + case E_AVR_MACH_AVR1: + strncat (buf, ", avr:1", size); + break; + case E_AVR_MACH_AVR2: + strncat (buf, ", avr:2", size); + break; + case E_AVR_MACH_AVR25: + strncat (buf, ", avr:25", size); + break; + case E_AVR_MACH_AVR3: + strncat (buf, ", avr:3", size); + break; + case E_AVR_MACH_AVR31: + strncat (buf, ", avr:31", size); + break; + case E_AVR_MACH_AVR35: + strncat (buf, ", avr:35", size); + break; + case E_AVR_MACH_AVR4: + strncat (buf, ", avr:4", size); + break; + case E_AVR_MACH_AVR5: + strncat (buf, ", avr:5", size); + break; + case E_AVR_MACH_AVR51: + strncat (buf, ", avr:51", size); + break; + case E_AVR_MACH_AVR6: + strncat (buf, ", avr:6", size); + break; + case E_AVR_MACH_AVRTINY: + strncat (buf, ", avr:100", size); + break; + case E_AVR_MACH_XMEGA1: + strncat (buf, ", avr:101", size); + break; + case E_AVR_MACH_XMEGA2: + strncat (buf, ", avr:102", size); + break; + case E_AVR_MACH_XMEGA3: + strncat (buf, ", avr:103", size); + break; + case E_AVR_MACH_XMEGA4: + strncat (buf, ", avr:104", size); + break; + case E_AVR_MACH_XMEGA5: + strncat (buf, ", avr:105", size); + break; + case E_AVR_MACH_XMEGA6: + strncat (buf, ", avr:106", size); + break; + case E_AVR_MACH_XMEGA7: + strncat (buf, ", avr:107", size); + break; + default: + strncat (buf, ", avr:", size); + break; + } + + size -= strlen (buf); + if (e_flags & EF_AVR_LINKRELAX_PREPARED) + strncat (buf, ", link-relax", size); +} + static void decode_NDS32_machine_flags (unsigned e_flags, char buf[], size_t size) { @@ -2620,6 +2763,10 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) decode_ARM_machine_flags (e_flags, buf); break; + case EM_AVR: + decode_AVR_machine_flags (e_flags, buf, sizeof buf); + break; + case EM_BLACKFIN: if (e_flags & EF_BFIN_PIC) strcat (buf, ", PIC"); @@ -2797,12 +2944,8 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) { case EF_RH850_FPU_DOUBLE: strcat (buf, ", double precision FPU"); break; case EF_RH850_FPU_SINGLE: strcat (buf, ", single precision FPU"); break; - case EF_RH850_SIMD: strcat (buf, ", SIMD"); break; - case EF_RH850_CACHE: strcat (buf, ", CACHE"); break; - case EF_RH850_MMU: strcat (buf, ", MMU"); break; case EF_RH850_REGMODE22: strcat (buf, ", regmode:22"); break; case EF_RH850_REGMODE32: strcat (buf, ", regmode:23"); break; - case EF_RH850_DATA_ALIGN8: strcat (buf, ", 8-byte alignment"); break; case EF_RH850_GP_FIX: strcat (buf, ", r4 fixed"); break; case EF_RH850_GP_NOFIX: strcat (buf, ", r4 free"); break; case EF_RH850_EP_FIX: strcat (buf, ", r30 fixed"); break; @@ -2984,7 +3127,7 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) if (e_flags & EF_SH_FDPIC) strcat (buf, ", fdpic"); break; - + case EM_OR1K: if (e_flags & EF_OR1K_NODELAY) strcat (buf, ", no delay"); @@ -3085,7 +3228,9 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) strcat (buf, ", abort"); break; default: - abort (); + warn (_("Unrecognised IA64 VMS Command Code: %x\n"), + e_flags & EF_IA_64_VMS_COMCOD); + strcat (buf, ", "); } } break; @@ -3099,9 +3244,23 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) strcat (buf, ", G-Float"); break; + case EM_VISIUM: + if (e_flags & EF_VISIUM_ARCH_MCM) + strcat (buf, ", mcm"); + else if (e_flags & EF_VISIUM_ARCH_MCM24) + strcat (buf, ", mcm24"); + if (e_flags & EF_VISIUM_ARCH_GR6) + strcat (buf, ", gr6"); + break; + case EM_RL78: - if (e_flags & E_FLAG_RL78_G10) - strcat (buf, ", G10"); + switch (e_flags & E_FLAG_RL78_CPU_MASK) + { + case E_FLAG_RL78_ANY_CPU: break; + case E_FLAG_RL78_G10: strcat (buf, ", G10"); break; + case E_FLAG_RL78_G13: strcat (buf, ", G13"); break; + case E_FLAG_RL78_G14: strcat (buf, ", G14"); break; + } if (e_flags & E_FLAG_RL78_64BIT_DOUBLES) strcat (buf, ", 64-bit doubles"); break; @@ -3195,6 +3354,7 @@ get_osabi_name (unsigned int osabi) case EM_MSP430: case EM_MSP430_OLD: + case EM_VISIUM: switch (osabi) { case ELFOSABI_STANDALONE: return _("Standalone App"); @@ -3591,6 +3751,20 @@ get_msp430x_section_type_name (unsigned int sh_type) } } +static const char * +get_v850_section_type_name (unsigned int sh_type) +{ + switch (sh_type) + { + case SHT_V850_SCOMMON: return "V850 Small Common"; + case SHT_V850_TCOMMON: return "V850 Tiny Common"; + case SHT_V850_ZCOMMON: return "V850 Zero Common"; + case SHT_RENESAS_IOP: return "RENESAS IOP"; + case SHT_RENESAS_INFO: return "RENESAS INFO"; + default: return NULL; + } +} + static const char * get_section_type_name (unsigned int sh_type) { @@ -3659,6 +3833,11 @@ get_section_type_name (unsigned int sh_type) case EM_MSP430: result = get_msp430x_section_type_name (sh_type); break; + case EM_V800: + case EM_V850: + case EM_CYGNUS_V850: + result = get_v850_section_type_name (sh_type); + break; default: result = NULL; break; @@ -3689,7 +3868,19 @@ get_section_type_name (unsigned int sh_type) sprintf (buff, "LOOS+%x", sh_type - SHT_LOOS); } else if ((sh_type >= SHT_LOUSER) && (sh_type <= SHT_HIUSER)) - sprintf (buff, "LOUSER+%x", sh_type - SHT_LOUSER); + { + switch (elf_header.e_machine) + { + case EM_V800: + case EM_V850: + case EM_CYGNUS_V850: + return get_v850_section_type_name (sh_type); + default: + break; + } + + sprintf (buff, "LOUSER+%x", sh_type - SHT_LOUSER); + } else /* This message is probably going to be displayed in a 15 character wide field, so put the hex value first. */ @@ -4044,11 +4235,6 @@ parse_args (int argc, char ** argv) && !do_section_groups && !do_archive_index && !do_dyn_syms) usage (stderr); - else if (argc < 3) - { - warn (_("Nothing to do.\n")); - usage (stderr); - } } static const char * @@ -4323,7 +4509,7 @@ process_program_headers (FILE * file) /* PR binutils/12467. */ if (elf_header.e_phoff != 0) warn (_("possibly corrupt ELF header - it has a non-zero program" - " header offset, but no program headers")); + " header offset, but no program headers\n")); else if (do_segments) printf (_("\nThere are no program headers in this file.\n")); return 0; @@ -4722,10 +4908,18 @@ get_32bit_elf_symbols (FILE * file, Elf_Internal_Sym * psym; unsigned int j; + if (section->sh_size == 0) + { + if (num_syms_return != NULL) + * num_syms_return = 0; + return NULL; + } + /* Run some sanity checks first. */ - if (section->sh_entsize == 0) + if (section->sh_entsize == 0 || section->sh_entsize > section->sh_size) { - error (_("sh_entsize is zero\n")); + error (_("Section %s has an invalid sh_entsize of 0x%lx\n"), + printable_section_name (section), (unsigned long) section->sh_entsize); goto exit_point; } @@ -4740,7 +4934,10 @@ get_32bit_elf_symbols (FILE * file, if (number * sizeof (Elf32_External_Sym) > section->sh_size + 1) { - error (_("Invalid sh_entsize\n")); + error (_("Size (0x%lx) of section %s is not a multiple of its sh_entsize (0x%lx)\n"), + (unsigned long) section->sh_size, + printable_section_name (section), + (unsigned long) section->sh_entsize); goto exit_point; } @@ -4760,6 +4957,15 @@ get_32bit_elf_symbols (FILE * file, _("symbol table section indicies")); if (shndx == NULL) goto exit_point; + /* PR17531: file: heap-buffer-overflow */ + else if (symtab_shndx_hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number) + { + error (_("Index section %s has an sh_size of 0x%lx - expected 0x%lx\n"), + printable_section_name (symtab_shndx_hdr), + (unsigned long) symtab_shndx_hdr->sh_size, + (unsigned long) section->sh_size); + goto exit_point; + } } isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym)); @@ -4810,17 +5016,27 @@ get_64bit_elf_symbols (FILE * file, Elf_Internal_Sym * psym; unsigned int j; + if (section->sh_size == 0) + { + if (num_syms_return != NULL) + * num_syms_return = 0; + return NULL; + } + /* Run some sanity checks first. */ - if (section->sh_entsize == 0) + if (section->sh_entsize == 0 || section->sh_entsize > section->sh_size) { - error (_("sh_entsize is zero\n")); + error (_("Section %s has an invalid sh_entsize of 0x%lx\n"), + printable_section_name (section), + (unsigned long) section->sh_entsize); goto exit_point; } if (section->sh_size > current_file_size) { error (_("Section %s has an invalid sh_size of 0x%lx\n"), - printable_section_name (section), (unsigned long) section->sh_size); + printable_section_name (section), + (unsigned long) section->sh_size); goto exit_point; } @@ -4828,7 +5044,10 @@ get_64bit_elf_symbols (FILE * file, if (number * sizeof (Elf64_External_Sym) > section->sh_size + 1) { - error (_("Invalid sh_entsize\n")); + error (_("Size (0x%lx) of section %s is not a multiple of its sh_entsize (0x%lx)\n"), + (unsigned long) section->sh_size, + printable_section_name (section), + (unsigned long) section->sh_entsize); goto exit_point; } @@ -4847,6 +5066,14 @@ get_64bit_elf_symbols (FILE * file, _("symbol table section indicies")); if (shndx == NULL) goto exit_point; + else if (symtab_shndx_hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number) + { + error (_("Index section %s has an sh_size of 0x%lx - expected 0x%lx\n"), + printable_section_name (symtab_shndx_hdr), + (unsigned long) symtab_shndx_hdr->sh_size, + (unsigned long) section->sh_size); + goto exit_point; + } } isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym)); @@ -4928,7 +5155,8 @@ get_elf_section_flags (bfd_vma sh_flags) /* Generic. */ /* 18 */ { STRING_COMMA_LEN ("EXCLUDE") }, /* SPARC specific. */ - /* 19 */ { STRING_COMMA_LEN ("ORDERED") } + /* 19 */ { STRING_COMMA_LEN ("ORDERED") }, + /* 20 */ { STRING_COMMA_LEN ("COMPRESSED") } }; if (do_section_details) @@ -4960,6 +5188,7 @@ get_elf_section_flags (bfd_vma sh_flags) case SHF_GROUP: sindex = 8; break; case SHF_TLS: sindex = 9; break; case SHF_EXCLUDE: sindex = 18; break; + case SHF_COMPRESSED: sindex = 20; break; default: sindex = -1; @@ -5007,7 +5236,10 @@ get_elf_section_flags (bfd_vma sh_flags) if (p != buff + field_size + 4) { if (size < (10 + 2)) - abort (); + { + warn (_("Internal error: not enough buffer room for section flag info")); + return _(""); + } size -= 2; *p++ = ','; *p++ = ' '; @@ -5038,6 +5270,7 @@ get_elf_section_flags (bfd_vma sh_flags) case SHF_GROUP: *p = 'G'; break; case SHF_TLS: *p = 'T'; break; case SHF_EXCLUDE: *p = 'E'; break; + case SHF_COMPRESSED: *p = 'C'; break; default: if ((elf_header.e_machine == EM_X86_64 @@ -5071,7 +5304,10 @@ get_elf_section_flags (bfd_vma sh_flags) if (p != buff + field_size + 4) { if (size < (2 + 1)) - abort (); + { + warn (_("Internal error: not enough buffer room for section flag info")); + return _(""); + } size -= 2; *p++ = ','; *p++ = ' '; @@ -5086,7 +5322,10 @@ get_elf_section_flags (bfd_vma sh_flags) if (p != buff + field_size + 4) { if (size < (2 + 1)) - abort (); + { + warn (_("Internal error: not enough buffer room for section flag info")); + return _(""); + } size -= 2; *p++ = ','; *p++ = ' '; @@ -5101,7 +5340,10 @@ get_elf_section_flags (bfd_vma sh_flags) if (p != buff + field_size + 4) { if (size < (2 + 1)) - abort (); + { + warn (_("Internal error: not enough buffer room for section flag info")); + return _(""); + } size -= 2; *p++ = ','; *p++ = ' '; @@ -5116,6 +5358,27 @@ get_elf_section_flags (bfd_vma sh_flags) return buff; } +static unsigned int +get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf) +{ + if (is_32bit_elf) + { + Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) buf; + chdr->ch_type = BYTE_GET (echdr->ch_type); + chdr->ch_size = BYTE_GET (echdr->ch_size); + chdr->ch_addralign = BYTE_GET (echdr->ch_addralign); + return sizeof (*echdr); + } + else + { + Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) buf; + chdr->ch_type = BYTE_GET (echdr->ch_type); + chdr->ch_size = BYTE_GET (echdr->ch_size); + chdr->ch_addralign = BYTE_GET (echdr->ch_addralign); + return sizeof (*echdr); + } +} + static int process_section_headers (FILE * file) { @@ -5560,7 +5823,29 @@ process_section_headers (FILE * file) } if (do_section_details) - printf (" %s\n", get_elf_section_flags (section->sh_flags)); + { + printf (" %s\n", get_elf_section_flags (section->sh_flags)); + if ((section->sh_flags & SHF_COMPRESSED) != 0) + { + /* Minimum section size is 12 bytes for 32-bit compression + header + 12 bytes for compressed data header. */ + unsigned char buf[24]; + assert (sizeof (buf) >= sizeof (Elf64_External_Chdr)); + if (get_data (&buf, (FILE *) file, section->sh_offset, 1, + sizeof (buf), _("compression header"))) + { + Elf_Internal_Chdr chdr; + get_compression_header (&chdr, buf); + if (chdr.ch_type == ELFCOMPRESS_ZLIB) + printf (" ZLIB, "); + else + printf (_(" [: 0x%x], "), + chdr.ch_type); + print_vma (chdr.ch_size, LONG_HEX); + printf (", %lu\n", (unsigned long) chdr.ch_addralign); + } + } + } } if (!do_section_details) @@ -5762,6 +6047,16 @@ process_section_groups (FILE * file) ? strtab + sym->st_name : _(""); } + /* PR 17531: file: loop. */ + if (section->sh_entsize > section->sh_size) + { + error (_("Section %s has sh_entsize (0x%lx) which is larger than its size (0x%lx)\n"), + printable_section_name (section), + (unsigned long) section->sh_entsize, + (unsigned long) section->sh_size); + break; + } + start = (unsigned char *) get_data (NULL, file, section->sh_offset, 1, section->sh_size, _("section data")); @@ -5792,8 +6087,15 @@ process_section_groups (FILE * file) if (entry >= elf_header.e_shnum) { - error (_("section [%5u] in group section [%5u] > maximum section [%5u]\n"), - entry, i, elf_header.e_shnum - 1); + static unsigned num_group_errors = 0; + + if (num_group_errors ++ < 10) + { + error (_("section [%5u] in group section [%5u] > maximum section [%5u]\n"), + entry, i, elf_header.e_shnum - 1); + if (num_group_errors == 10) + warn (_("Futher error messages about overlarge group section indicies suppressed\n")); + } continue; } @@ -5801,9 +6103,16 @@ process_section_groups (FILE * file) { if (entry) { - error (_("section [%5u] in group section [%5u] already in group section [%5u]\n"), - entry, i, - section_headers_groups [entry]->group_index); + static unsigned num_errs = 0; + + if (num_errs ++ < 10) + { + error (_("section [%5u] in group section [%5u] already in group section [%5u]\n"), + entry, i, + section_headers_groups [entry]->group_index); + if (num_errs == 10) + warn (_("Further error messages about already contained group sections suppressed\n")); + } continue; } else @@ -6097,7 +6406,8 @@ process_relocs (FILE * file) offset_from_vma (file, rel_offset, rel_size), rel_size, dynamic_symbols, num_dynamic_syms, - dynamic_strings, dynamic_strings_length, is_rela); + dynamic_strings, dynamic_strings_length, + is_rela, 1); } } @@ -6172,14 +6482,16 @@ process_relocs (FILE * file) } dump_relocations (file, rel_offset, rel_size, - symtab, nsyms, strtab, strtablen, is_rela); + symtab, nsyms, strtab, strtablen, + is_rela, + symsec->sh_type == SHT_DYNSYM); if (strtab) free (strtab); free (symtab); } else dump_relocations (file, rel_offset, rel_size, - NULL, 0, NULL, 0, is_rela); + NULL, 0, NULL, 0, is_rela, 0); found = 1; } @@ -6192,71 +6504,53 @@ process_relocs (FILE * file) return 1; } -/* Process the unwind section. */ - -#include "unwind-ia64.h" - /* An absolute address consists of a section and an offset. If the section is NULL, the offset itself is the address, otherwise, the address equals to LOAD_ADDRESS(section) + offset. */ struct absaddr - { - unsigned short section; - bfd_vma offset; - }; +{ + unsigned short section; + bfd_vma offset; +}; #define ABSADDR(a) \ ((a).section \ ? section_headers [(a).section].sh_addr + (a).offset \ : (a).offset) -struct ia64_unw_table_entry - { - struct absaddr start; - struct absaddr end; - struct absaddr info; - }; - -struct ia64_unw_aux_info - { - - struct ia64_unw_table_entry *table; /* Unwind table. */ - unsigned long table_len; /* Length of unwind table. */ - unsigned char * info; /* Unwind info. */ - unsigned long info_size; /* Size of unwind info. */ - bfd_vma info_addr; /* starting address of unwind info. */ - bfd_vma seg_base; /* Starting address of segment. */ - Elf_Internal_Sym * symtab; /* The symbol table. */ - unsigned long nsyms; /* Number of symbols. */ - char * strtab; /* The string table. */ - unsigned long strtab_size; /* Size of string table. */ - }; +/* Find the nearest symbol at or below ADDR. Returns the symbol + name, if found, and the offset from the symbol to ADDR. */ static void find_symbol_for_address (Elf_Internal_Sym * symtab, - unsigned long nsyms, - const char * strtab, - unsigned long strtab_size, - struct absaddr addr, - const char ** symname, - bfd_vma * offset) + unsigned long nsyms, + const char * strtab, + unsigned long strtab_size, + struct absaddr addr, + const char ** symname, + bfd_vma * offset) { bfd_vma dist = 0x100000; Elf_Internal_Sym * sym; + Elf_Internal_Sym * beg; + Elf_Internal_Sym * end; Elf_Internal_Sym * best = NULL; - unsigned long i; REMOVE_ARCH_BITS (addr.offset); + beg = symtab; + end = symtab + nsyms; - for (i = 0, sym = symtab; i < nsyms; ++i, ++sym) + while (beg < end) { - bfd_vma value = sym->st_value; + bfd_vma value; + + sym = beg + (end - beg) / 2; + value = sym->st_value; REMOVE_ARCH_BITS (value); - if (ELF_ST_TYPE (sym->st_info) == STT_FUNC - && sym->st_name != 0 + if (sym->st_name != 0 && (addr.section == SHN_UNDEF || addr.section == sym->st_shndx) && addr.offset >= value && addr.offset - value < dist) @@ -6266,6 +6560,11 @@ find_symbol_for_address (Elf_Internal_Sym * symtab, if (!dist) break; } + + if (addr.offset < value) + end = sym; + else + beg = sym + 1; } if (best) @@ -6280,21 +6579,66 @@ find_symbol_for_address (Elf_Internal_Sym * symtab, *offset = addr.offset; } +static int +symcmp (const void *p, const void *q) +{ + Elf_Internal_Sym *sp = (Elf_Internal_Sym *) p; + Elf_Internal_Sym *sq = (Elf_Internal_Sym *) q; + + return sp->st_value > sq->st_value ? 1 : (sp->st_value < sq->st_value ? -1 : 0); +} + +/* Process the unwind section. */ + +#include "unwind-ia64.h" + +struct ia64_unw_table_entry +{ + struct absaddr start; + struct absaddr end; + struct absaddr info; +}; + +struct ia64_unw_aux_info +{ + struct ia64_unw_table_entry *table; /* Unwind table. */ + unsigned long table_len; /* Length of unwind table. */ + unsigned char * info; /* Unwind info. */ + unsigned long info_size; /* Size of unwind info. */ + bfd_vma info_addr; /* Starting address of unwind info. */ + bfd_vma seg_base; /* Starting address of segment. */ + Elf_Internal_Sym * symtab; /* The symbol table. */ + unsigned long nsyms; /* Number of symbols. */ + Elf_Internal_Sym * funtab; /* Sorted table of STT_FUNC symbols. */ + unsigned long nfuns; /* Number of entries in funtab. */ + char * strtab; /* The string table. */ + unsigned long strtab_size; /* Size of string table. */ +}; + static void dump_ia64_unwind (struct ia64_unw_aux_info * aux) { struct ia64_unw_table_entry * tp; + unsigned long j, nfuns; int in_body; + aux->funtab = xmalloc (aux->nsyms * sizeof (Elf_Internal_Sym)); + for (nfuns = 0, j = 0; j < aux->nsyms; j++) + if (aux->symtab[j].st_value && ELF_ST_TYPE (aux->symtab[j].st_info) == STT_FUNC) + aux->funtab[nfuns++] = aux->symtab[j]; + aux->nfuns = nfuns; + qsort (aux->funtab, aux->nfuns, sizeof (Elf_Internal_Sym), symcmp); + for (tp = aux->table; tp < aux->table + aux->table_len; ++tp) { bfd_vma stamp; bfd_vma offset; const unsigned char * dp; const unsigned char * head; + const unsigned char * end; const char * procname; - find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab, + find_symbol_for_address (aux->funtab, aux->nfuns, aux->strtab, aux->strtab_size, tp->start, &procname, &offset); fputs ("\n<", stdout); @@ -6314,6 +6658,18 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux) printf ("], info at +0x%lx\n", (unsigned long) (tp->info.offset - aux->seg_base)); + /* PR 17531: file: 86232b32. */ + if (aux->info == NULL) + continue; + + /* PR 17531: file: 0997b4d1. */ + if ((ABSADDR (tp->info) - aux->info_addr) >= aux->info_size) + { + warn (_("Invalid offset %lx in table entry %ld\n"), + (long) tp->info.offset, (long) (tp - aux->table)); + continue; + } + head = aux->info + (ABSADDR (tp->info) - aux->info_addr); stamp = byte_get ((unsigned char *) head, sizeof (stamp)); @@ -6331,12 +6687,18 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux) } in_body = 0; - for (dp = head + 8; dp < head + 8 + eh_addr_size * UNW_LENGTH (stamp);) + end = head + 8 + eh_addr_size * UNW_LENGTH (stamp); + /* PR 17531: file: 16ceda89. */ + if (end > aux->info + aux->info_size) + end = aux->info + aux->info_size; + for (dp = head + 8; dp < end;) dp = unw_decode (dp, in_body, & in_body); } + + free (aux->funtab); } -static int +static bfd_boolean slurp_ia64_unwind_table (FILE * file, struct ia64_unw_aux_info * aux, Elf_Internal_Shdr * sec) @@ -6352,13 +6714,15 @@ slurp_ia64_unwind_table (FILE * file, Elf_Internal_Sym * sym; const char * relname; + aux->table_len = 0; + /* First, find the starting address of the segment that includes this section: */ if (elf_header.e_phnum) { if (! get_program_headers (file)) - return 0; + return FALSE; for (seg = program_headers; seg < program_headers + elf_header.e_phnum; @@ -6381,12 +6745,14 @@ slurp_ia64_unwind_table (FILE * file, table = (unsigned char *) get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table")); if (!table) - return 0; + return FALSE; + aux->table_len = size / (3 * eh_addr_size); aux->table = (struct ia64_unw_table_entry *) - xcmalloc (size / (3 * eh_addr_size), sizeof (aux->table[0])); + xcmalloc (aux->table_len, sizeof (aux->table[0])); tep = aux->table; - for (tp = table; tp < table + size; ++tep) + + for (tp = table; tp <= table + size - (3 * eh_addr_size); ++tep) { tep->start.section = SHN_UNDEF; tep->end.section = SHN_UNDEF; @@ -6412,22 +6778,41 @@ slurp_ia64_unwind_table (FILE * file, if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size, & rela, & nrelas)) - return 0; + { + free (aux->table); + aux->table = NULL; + aux->table_len = 0; + return FALSE; + } for (rp = rela; rp < rela + nrelas; ++rp) { relname = elf_ia64_reloc_type (get_reloc_type (rp->r_info)); sym = aux->symtab + get_reloc_symindex (rp->r_info); + /* PR 17531: file: 9fa67536. */ + if (relname == NULL) + { + warn (_("Skipping unknown relocation type: %u\n"), get_reloc_type (rp->r_info)); + continue; + } + if (! const_strneq (relname, "R_IA64_SEGREL")) { - warn (_("Skipping unexpected relocation type %s\n"), relname); + warn (_("Skipping unexpected relocation type: %s\n"), relname); continue; } i = rp->r_offset / (3 * eh_addr_size); - switch (rp->r_offset/eh_addr_size % 3) + /* PR 17531: file: 5bc8d9bf. */ + if (i >= aux->table_len) + { + warn (_("Skipping reloc with overlarge offset: %lx\n"), i); + continue; + } + + switch (rp->r_offset / eh_addr_size % 3) { case 0: aux->table[i].start.section = sym->st_shndx; @@ -6449,8 +6834,7 @@ slurp_ia64_unwind_table (FILE * file, free (rela); } - aux->table_len = size / (3 * eh_addr_size); - return 1; + return TRUE; } static void @@ -6587,9 +6971,8 @@ ia64_process_unwind (FILE * file) (unsigned long) unwsec->sh_offset, (unsigned long) (unwsec->sh_size / (3 * eh_addr_size))); - (void) slurp_ia64_unwind_table (file, & aux, unwsec); - - if (aux.table_len > 0) + if (slurp_ia64_unwind_table (file, & aux, unwsec) + && aux.table_len > 0) dump_ia64_unwind (& aux); if (aux.table) @@ -6611,7 +6994,7 @@ struct hppa_unw_table_entry { struct absaddr start; struct absaddr end; - unsigned int Cannot_unwind:1; /* 0 */ + unsigned int Cannot_unwind:1; /* 0 */ unsigned int Millicode:1; /* 1 */ unsigned int Millicode_save_sr0:1; /* 2 */ unsigned int Region_description:2; /* 3..4 */ @@ -6620,52 +7003,62 @@ struct hppa_unw_table_entry unsigned int Entry_FR:4; /* number saved */ /* 7..10 */ unsigned int Entry_GR:5; /* number saved */ /* 11..15 */ unsigned int Args_stored:1; /* 16 */ - unsigned int Variable_Frame:1; /* 17 */ - unsigned int Separate_Package_Body:1; /* 18 */ + unsigned int Variable_Frame:1; /* 17 */ + unsigned int Separate_Package_Body:1; /* 18 */ unsigned int Frame_Extension_Millicode:1; /* 19 */ - unsigned int Stack_Overflow_Check:1; /* 20 */ - unsigned int Two_Instruction_SP_Increment:1; /* 21 */ + unsigned int Stack_Overflow_Check:1; /* 20 */ + unsigned int Two_Instruction_SP_Increment:1;/* 21 */ unsigned int Ada_Region:1; /* 22 */ unsigned int cxx_info:1; /* 23 */ - unsigned int cxx_try_catch:1; /* 24 */ - unsigned int sched_entry_seq:1; /* 25 */ + unsigned int cxx_try_catch:1; /* 24 */ + unsigned int sched_entry_seq:1; /* 25 */ unsigned int reserved2:1; /* 26 */ - unsigned int Save_SP:1; /* 27 */ - unsigned int Save_RP:1; /* 28 */ + unsigned int Save_SP:1; /* 27 */ + unsigned int Save_RP:1; /* 28 */ unsigned int Save_MRP_in_frame:1; /* 29 */ unsigned int extn_ptr_defined:1; /* 30 */ - unsigned int Cleanup_defined:1; /* 31 */ + unsigned int Cleanup_defined:1; /* 31 */ - unsigned int MPE_XL_interrupt_marker:1; /* 0 */ - unsigned int HP_UX_interrupt_marker:1; /* 1 */ + unsigned int MPE_XL_interrupt_marker:1; /* 0 */ + unsigned int HP_UX_interrupt_marker:1; /* 1 */ unsigned int Large_frame:1; /* 2 */ - unsigned int Pseudo_SP_Set:1; /* 3 */ + unsigned int Pseudo_SP_Set:1; /* 3 */ unsigned int reserved4:1; /* 4 */ unsigned int Total_frame_size:27; /* 5..31 */ }; struct hppa_unw_aux_info - { - struct hppa_unw_table_entry *table; /* Unwind table. */ - unsigned long table_len; /* Length of unwind table. */ - bfd_vma seg_base; /* Starting address of segment. */ - Elf_Internal_Sym * symtab; /* The symbol table. */ - unsigned long nsyms; /* Number of symbols. */ - char * strtab; /* The string table. */ - unsigned long strtab_size; /* Size of string table. */ - }; +{ + struct hppa_unw_table_entry * table; /* Unwind table. */ + unsigned long table_len; /* Length of unwind table. */ + bfd_vma seg_base; /* Starting address of segment. */ + Elf_Internal_Sym * symtab; /* The symbol table. */ + unsigned long nsyms; /* Number of symbols. */ + Elf_Internal_Sym * funtab; /* Sorted table of STT_FUNC symbols. */ + unsigned long nfuns; /* Number of entries in funtab. */ + char * strtab; /* The string table. */ + unsigned long strtab_size; /* Size of string table. */ +}; static void dump_hppa_unwind (struct hppa_unw_aux_info * aux) { struct hppa_unw_table_entry * tp; + unsigned long j, nfuns; + + aux->funtab = xmalloc (aux->nsyms * sizeof (Elf_Internal_Sym)); + for (nfuns = 0, j = 0; j < aux->nsyms; j++) + if (aux->symtab[j].st_value && ELF_ST_TYPE (aux->symtab[j].st_info) == STT_FUNC) + aux->funtab[nfuns++] = aux->symtab[j]; + aux->nfuns = nfuns; + qsort (aux->funtab, aux->nfuns, sizeof (Elf_Internal_Sym), symcmp); for (tp = aux->table; tp < aux->table + aux->table_len; ++tp) { bfd_vma offset; const char * procname; - find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab, + find_symbol_for_address (aux->funtab, aux->nfuns, aux->strtab, aux->strtab_size, tp->start, &procname, &offset); @@ -6719,6 +7112,8 @@ dump_hppa_unwind (struct hppa_unw_aux_info * aux) } printf ("\n"); + + free (aux->funtab); } static int @@ -6955,6 +7350,8 @@ struct arm_unw_aux_info FILE * file; /* The file containing the unwind sections. */ Elf_Internal_Sym * symtab; /* The file's symbol table. */ unsigned long nsyms; /* Number of symbols. */ + Elf_Internal_Sym * funtab; /* Sorted table of STT_FUNC symbols. */ + unsigned long nfuns; /* Number of these symbols. */ char * strtab; /* The file's string table. */ unsigned long strtab_size; /* Size of string table. */ }; @@ -6969,7 +7366,7 @@ arm_print_vma_and_name (struct arm_unw_aux_info *aux, if (addr.section == SHN_UNDEF) addr.offset = fn; - find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab, + find_symbol_for_address (aux->funtab, aux->nfuns, aux->strtab, aux->strtab_size, addr, &procname, &sym_offset); @@ -7264,11 +7661,13 @@ decode_tic6x_unwind_regmask (unsigned int mask) printf ("0x%02x ", OP) static void -decode_arm_unwind_bytecode (struct arm_unw_aux_info *aux, - unsigned int word, unsigned int remaining, - unsigned int more_words, - bfd_vma data_offset, Elf_Internal_Shdr *data_sec, - struct arm_section *data_arm_sec) +decode_arm_unwind_bytecode (struct arm_unw_aux_info * aux, + unsigned int word, + unsigned int remaining, + unsigned int more_words, + bfd_vma data_offset, + Elf_Internal_Shdr * data_sec, + struct arm_section * data_arm_sec) { struct absaddr addr; @@ -7475,11 +7874,13 @@ decode_arm_unwind_bytecode (struct arm_unw_aux_info *aux, } static void -decode_tic6x_unwind_bytecode (struct arm_unw_aux_info *aux, - unsigned int word, unsigned int remaining, - unsigned int more_words, - bfd_vma data_offset, Elf_Internal_Shdr *data_sec, - struct arm_section *data_arm_sec) +decode_tic6x_unwind_bytecode (struct arm_unw_aux_info * aux, + unsigned int word, + unsigned int remaining, + unsigned int more_words, + bfd_vma data_offset, + Elf_Internal_Shdr * data_sec, + struct arm_section * data_arm_sec) { struct absaddr addr; @@ -7597,7 +7998,7 @@ decode_tic6x_unwind_bytecode (struct arm_unw_aux_info *aux, warn (_("Corrupt stack pointer adjustment detected\n")); return; } - + offset = read_uleb128 (buf, &len, buf + i + 1); assert (len == i + 1); offset = offset * 8 + 0x408; @@ -7792,11 +8193,19 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec) { struct arm_section exidx_arm_sec, extab_arm_sec; unsigned int i, exidx_len; + unsigned long j, nfuns; memset (&exidx_arm_sec, 0, sizeof (exidx_arm_sec)); memset (&extab_arm_sec, 0, sizeof (extab_arm_sec)); exidx_len = exidx_sec->sh_size / 8; + aux->funtab = xmalloc (aux->nsyms * sizeof (Elf_Internal_Sym)); + for (nfuns = 0, j = 0; j < aux->nsyms; j++) + if (aux->symtab[j].st_value && ELF_ST_TYPE (aux->symtab[j].st_info) == STT_FUNC) + aux->funtab[nfuns++] = aux->symtab[j]; + aux->nfuns = nfuns; + qsort (aux->funtab, aux->nfuns, sizeof (Elf_Internal_Sym), symcmp); + for (i = 0; i < exidx_len; i++) { unsigned int exidx_fn, exidx_entry; @@ -7810,6 +8219,7 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec) || ! get_unwind_section_word (aux, & exidx_arm_sec, exidx_sec, 8 * i + 4, & exidx_entry, & entry_addr, NULL)) { + free (aux->funtab); arm_free_section (& exidx_arm_sec); arm_free_section (& extab_arm_sec); return; @@ -7873,6 +8283,7 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec) printf ("\n"); + free (aux->funtab); arm_free_section (&exidx_arm_sec); arm_free_section (&extab_arm_sec); } @@ -8032,12 +8443,16 @@ dynamic_section_mips_val (Elf_Internal_Dyn * entry) { char timebuf[20]; struct tm * tmp; - time_t atime = entry->d_un.d_val; + tmp = gmtime (&atime); - snprintf (timebuf, sizeof (timebuf), "%04u-%02u-%02uT%02u:%02u:%02u", - tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + /* PR 17531: file: 6accc532. */ + if (tmp == NULL) + snprintf (timebuf, sizeof (timebuf), _("")); + else + snprintf (timebuf, sizeof (timebuf), "%04u-%02u-%02uT%02u:%02u:%02u", + tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); printf (_("Time Stamp: %s"), timebuf); } break; @@ -9208,7 +9623,6 @@ process_version_sections (FILE * file) /* Check for overflow. */ if (ent.vn_aux > (size_t) (endbuf - vstart)) break; - vstart += ent.vn_aux; for (j = 0, isum = idx + ent.vn_aux; j < ent.vn_cnt; ++j) @@ -9237,9 +9651,14 @@ process_version_sections (FILE * file) get_ver_flags (aux.vna_flags), aux.vna_other); /* Check for overflow. */ - if (aux.vna_next > (size_t) (endbuf - vstart)) - break; - + if (aux.vna_next > (size_t) (endbuf - vstart) + || (aux.vna_next == 0 && j < ent.vn_cnt - 1)) + { + warn (_("Invalid vna_next field of %lx\n"), + aux.vna_next); + j = ent.vn_cnt; + break; + } isum += aux.vna_next; vstart += aux.vna_next; } @@ -9458,7 +9877,7 @@ process_version_sections (FILE * file) _("version def")) == NULL) { ivd.vd_next = 0; - /* PR 17531: file: 046-1082287-0.004. */ + /* PR 17531: file: 046-1082287-0.004. */ ivd.vd_ndx = (data[cnt + j] & VERSYM_VERSION) + 1; break; } @@ -9616,7 +10035,9 @@ get_symbol_visibility (unsigned int visibility) case STV_INTERNAL: return "INTERNAL"; case STV_HIDDEN: return "HIDDEN"; case STV_PROTECTED: return "PROTECTED"; - default: abort (); + default: + error (_("Unrecognized visibility value: %u"), visibility); + return _(""); } } @@ -9671,7 +10092,10 @@ get_ia64_symbol_other (unsigned int other) strcat (res, " RSV"); break; default: - abort (); + warn (_("Unrecognized IA64 VMS ST Function type: %d\n"), + VMS_ST_FUNC_TYPE (other)); + strcat (res, " "); + break; } break; default: @@ -9692,7 +10116,10 @@ get_ia64_symbol_other (unsigned int other) strcat (res, " LNK"); break; default: - abort (); + warn (_("Unrecognized IA64 VMS ST Linkage: %d\n"), + VMS_ST_LINKAGE (other)); + strcat (res, " "); + break; } if (res[0] != 0) @@ -9792,41 +10219,52 @@ get_symbol_index_type (unsigned int type) } static bfd_vma * -get_dynamic_data (FILE * file, size_t number, unsigned int ent_size) +get_dynamic_data (FILE * file, bfd_size_type number, unsigned int ent_size) { unsigned char * e_data; bfd_vma * i_data; + /* If the size_t type is smaller than the bfd_size_type, eg because + you are building a 32-bit tool on a 64-bit host, then make sure + that when (number) is cast to (size_t) no information is lost. */ + if (sizeof (size_t) < sizeof (bfd_size_type) + && (bfd_size_type) ((size_t) number) != number) + { + error (_("Size truncation prevents reading %llu elements of size %u\n"), + (unsigned long long) number, ent_size); + return NULL; + } + /* Be kind to memory chekers (eg valgrind, address sanitizer) by not attempting to allocate memory when the read is bound to fail. */ if (ent_size * number > current_file_size) { - error (_("Invalid number of dynamic entries: %lu\n"), - (unsigned long) number); + error (_("Invalid number of dynamic entries: %llu\n"), + (unsigned long long) number); return NULL; } - e_data = (unsigned char *) cmalloc (number, ent_size); + e_data = (unsigned char *) cmalloc ((size_t) number, ent_size); if (e_data == NULL) { - error (_("Out of memory reading %lu dynamic entries\n"), - (unsigned long) number); + error (_("Out of memory reading %llu dynamic entries\n"), + (unsigned long long) number); return NULL; } - if (fread (e_data, ent_size, number, file) != number) + if (fread (e_data, ent_size, (size_t) number, file) != number) { - error (_("Unable to read in %lu bytes of dynamic data\n"), - (unsigned long) (number * ent_size)); + error (_("Unable to read in %llu bytes of dynamic data\n"), + (unsigned long long) (number * ent_size)); free (e_data); return NULL; } - i_data = (bfd_vma *) cmalloc (number, sizeof (*i_data)); + i_data = (bfd_vma *) cmalloc ((size_t) number, sizeof (*i_data)); if (i_data == NULL) { - error (_("Out of memory allocating space for %lu dynamic entries\n"), - (unsigned long) number); + error (_("Out of memory allocating space for %llu dynamic entries\n"), + (unsigned long long) number); free (e_data); return NULL; } @@ -9879,23 +10317,199 @@ print_dynamic_symbol (bfd_vma si, unsigned long hn) putchar ('\n'); } -/* Dump the symbol table. */ -static int -process_symbol_table (FILE * file) +static const char * +get_symbol_version_string (FILE *file, int is_dynsym, + const char *strtab, + unsigned long int strtab_size, + unsigned int si, Elf_Internal_Sym *psym, + enum versioned_symbol_info *sym_info, + unsigned short *vna_other) { - Elf_Internal_Shdr * section; - bfd_size_type nbuckets = 0; - bfd_size_type nchains = 0; - bfd_vma * buckets = NULL; - bfd_vma * chains = NULL; - bfd_vma ngnubuckets = 0; - bfd_vma * gnubuckets = NULL; - bfd_vma * gnuchains = NULL; - bfd_vma gnusymidx = 0; - bfd_size_type ngnuchains = 0; + const char *version_string = NULL; - if (!do_syms && !do_dyn_syms && !do_histogram) - return 1; + if (is_dynsym + && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0) + { + unsigned char data[2]; + unsigned short vers_data; + unsigned long offset; + int is_nobits; + int check_def; + + offset = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)], + sizeof data + si * sizeof (vers_data)); + + if (get_data (&data, file, offset + si * sizeof (vers_data), + sizeof (data), 1, _("version data")) == NULL) + return NULL; + + vers_data = byte_get (data, 2); + + is_nobits = (section_headers != NULL + && psym->st_shndx < elf_header.e_shnum + && section_headers[psym->st_shndx].sh_type + == SHT_NOBITS); + + check_def = (psym->st_shndx != SHN_UNDEF); + + if ((vers_data & VERSYM_HIDDEN) || vers_data > 1) + { + if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)] + && (is_nobits || ! check_def)) + { + Elf_External_Verneed evn; + Elf_Internal_Verneed ivn; + Elf_Internal_Vernaux ivna; + + /* We must test both. */ + offset = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], + sizeof evn); + + do + { + unsigned long vna_off; + + if (get_data (&evn, file, offset, sizeof (evn), 1, + _("version need")) == NULL) + { + ivna.vna_next = 0; + ivna.vna_other = 0; + ivna.vna_name = 0; + break; + } + + ivn.vn_aux = BYTE_GET (evn.vn_aux); + ivn.vn_next = BYTE_GET (evn.vn_next); + + vna_off = offset + ivn.vn_aux; + + do + { + Elf_External_Vernaux evna; + + if (get_data (&evna, file, vna_off, + sizeof (evna), 1, + _("version need aux (3)")) == NULL) + { + ivna.vna_next = 0; + ivna.vna_other = 0; + ivna.vna_name = 0; + } + else + { + ivna.vna_other = BYTE_GET (evna.vna_other); + ivna.vna_next = BYTE_GET (evna.vna_next); + ivna.vna_name = BYTE_GET (evna.vna_name); + } + + vna_off += ivna.vna_next; + } + while (ivna.vna_other != vers_data + && ivna.vna_next != 0); + + if (ivna.vna_other == vers_data) + break; + + offset += ivn.vn_next; + } + while (ivn.vn_next != 0); + + if (ivna.vna_other == vers_data) + { + *sym_info = symbol_undefined; + *vna_other = ivna.vna_other; + version_string = (ivna.vna_name < strtab_size + ? strtab + ivna.vna_name + : _("")); + check_def = 0; + } + else if (! is_nobits) + error (_("bad dynamic symbol\n")); + else + check_def = 1; + } + + if (check_def) + { + if (vers_data != 0x8001 + && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) + { + Elf_Internal_Verdef ivd; + Elf_Internal_Verdaux ivda; + Elf_External_Verdaux evda; + unsigned long off; + + off = offset_from_vma + (file, + version_info[DT_VERSIONTAGIDX (DT_VERDEF)], + sizeof (Elf_External_Verdef)); + + do + { + Elf_External_Verdef evd; + + if (get_data (&evd, file, off, sizeof (evd), + 1, _("version def")) == NULL) + { + ivd.vd_ndx = 0; + ivd.vd_aux = 0; + ivd.vd_next = 0; + } + else + { + ivd.vd_ndx = BYTE_GET (evd.vd_ndx); + ivd.vd_aux = BYTE_GET (evd.vd_aux); + ivd.vd_next = BYTE_GET (evd.vd_next); + } + + off += ivd.vd_next; + } + while (ivd.vd_ndx != (vers_data & VERSYM_VERSION) + && ivd.vd_next != 0); + + off -= ivd.vd_next; + off += ivd.vd_aux; + + if (get_data (&evda, file, off, sizeof (evda), + 1, _("version def aux")) == NULL) + return version_string; + + ivda.vda_name = BYTE_GET (evda.vda_name); + + if (psym->st_name != ivda.vda_name) + { + *sym_info = ((vers_data & VERSYM_HIDDEN) != 0 + ? symbol_hidden : symbol_public); + version_string = (ivda.vda_name < strtab_size + ? strtab + ivda.vda_name + : _("")); + } + } + } + } + } + return version_string; +} + +/* Dump the symbol table. */ +static int +process_symbol_table (FILE * file) +{ + Elf_Internal_Shdr * section; + bfd_size_type nbuckets = 0; + bfd_size_type nchains = 0; + bfd_vma * buckets = NULL; + bfd_vma * chains = NULL; + bfd_vma ngnubuckets = 0; + bfd_vma * gnubuckets = NULL; + bfd_vma * gnuchains = NULL; + bfd_vma gnusymidx = 0; + bfd_size_type ngnuchains = 0; + + if (!do_syms && !do_dyn_syms && !do_histogram) + return 1; if (dynamic_info[DT_HASH] && (do_histogram @@ -10179,6 +10793,10 @@ process_symbol_table (FILE * file) for (si = 0, psym = symtab; si < num_syms; si++, psym++) { + const char *version_string; + enum versioned_symbol_info sym_info; + unsigned short vna_other; + printf ("%6d: ", si); print_vma (psym->st_value, LONG_HEX); putchar (' '); @@ -10195,163 +10813,18 @@ process_symbol_table (FILE * file) print_symbol (25, psym->st_name < strtab_size ? strtab + psym->st_name : _("")); - if (section->sh_type == SHT_DYNSYM - && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0) + version_string + = get_symbol_version_string (file, + section->sh_type == SHT_DYNSYM, + strtab, strtab_size, si, + psym, &sym_info, &vna_other); + if (version_string) { - unsigned char data[2]; - unsigned short vers_data; - unsigned long offset; - int is_nobits; - int check_def; - - offset = offset_from_vma - (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)], - sizeof data + si * sizeof (vers_data)); - - if (get_data (&data, file, offset + si * sizeof (vers_data), - sizeof (data), 1, _("version data")) == NULL) - break; - - vers_data = byte_get (data, 2); - - is_nobits = (psym->st_shndx < elf_header.e_shnum - && section_headers[psym->st_shndx].sh_type - == SHT_NOBITS); - - check_def = (psym->st_shndx != SHN_UNDEF); - - if ((vers_data & VERSYM_HIDDEN) || vers_data > 1) - { - if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)] - && (is_nobits || ! check_def)) - { - Elf_External_Verneed evn; - Elf_Internal_Verneed ivn; - Elf_Internal_Vernaux ivna; - - /* We must test both. */ - offset = offset_from_vma - (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], - sizeof evn); - - do - { - unsigned long vna_off; - - if (get_data (&evn, file, offset, sizeof (evn), 1, - _("version need")) == NULL) - { - ivna.vna_next = 0; - ivna.vna_other = 0; - ivna.vna_name = 0; - break; - } - - ivn.vn_aux = BYTE_GET (evn.vn_aux); - ivn.vn_next = BYTE_GET (evn.vn_next); - - vna_off = offset + ivn.vn_aux; - - do - { - Elf_External_Vernaux evna; - - if (get_data (&evna, file, vna_off, - sizeof (evna), 1, - _("version need aux (3)")) == NULL) - { - ivna.vna_next = 0; - ivna.vna_other = 0; - ivna.vna_name = 0; - } - else - { - ivna.vna_other = BYTE_GET (evna.vna_other); - ivna.vna_next = BYTE_GET (evna.vna_next); - ivna.vna_name = BYTE_GET (evna.vna_name); - } - - vna_off += ivna.vna_next; - } - while (ivna.vna_other != vers_data - && ivna.vna_next != 0); - - if (ivna.vna_other == vers_data) - break; - - offset += ivn.vn_next; - } - while (ivn.vn_next != 0); - - if (ivna.vna_other == vers_data) - { - printf ("@%s (%d)", - ivna.vna_name < strtab_size - ? strtab + ivna.vna_name : _(""), - ivna.vna_other); - check_def = 0; - } - else if (! is_nobits) - error (_("bad dynamic symbol\n")); - else - check_def = 1; - } - - if (check_def) - { - if (vers_data != 0x8001 - && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) - { - Elf_Internal_Verdef ivd; - Elf_Internal_Verdaux ivda; - Elf_External_Verdaux evda; - unsigned long off; - - off = offset_from_vma - (file, - version_info[DT_VERSIONTAGIDX (DT_VERDEF)], - sizeof (Elf_External_Verdef)); - - do - { - Elf_External_Verdef evd; - - if (get_data (&evd, file, off, sizeof (evd), - 1, _("version def")) == NULL) - { - ivd.vd_ndx = 0; - ivd.vd_aux = 0; - ivd.vd_next = 0; - } - else - { - ivd.vd_ndx = BYTE_GET (evd.vd_ndx); - ivd.vd_aux = BYTE_GET (evd.vd_aux); - ivd.vd_next = BYTE_GET (evd.vd_next); - } - - off += ivd.vd_next; - } - while (ivd.vd_ndx != (vers_data & VERSYM_VERSION) - && ivd.vd_next != 0); - - off -= ivd.vd_next; - off += ivd.vd_aux; - - if (get_data (&evda, file, off, sizeof (evda), - 1, _("version def aux")) == NULL) - break; - - ivda.vda_name = BYTE_GET (evda.vda_name); - - if (psym->st_name != ivda.vda_name) - printf ((vers_data & VERSYM_HIDDEN) - ? "@%s" : "@@%s", - ivda.vda_name < strtab_size - ? strtab + ivda.vda_name : _("")); - } - } - } + if (sym_info == symbol_undefined) + printf ("@%s (%d)", version_string, vna_other); + else + printf (sym_info == symbol_hidden ? "@%s" : "@@%s", + version_string); } putchar ('\n'); @@ -10375,6 +10848,7 @@ process_symbol_table (FILE * file) unsigned long maxlength = 0; unsigned long nzero_counts = 0; unsigned long nsyms = 0; + unsigned long chained; printf (_("\nHistogram for bucket list length (total of %lu buckets):\n"), (unsigned long) nbuckets); @@ -10389,21 +10863,23 @@ process_symbol_table (FILE * file) printf (_(" Length Number %% of total Coverage\n")); for (hn = 0; hn < nbuckets; ++hn) { - for (si = buckets[hn]; si > 0 && si < nchains; si = chains[si]) + for (si = buckets[hn], chained = 0; + si > 0 && si < nchains && si < nbuckets && chained <= nchains; + si = chains[si], ++chained) { ++nsyms; if (maxlength < ++lengths[hn]) ++maxlength; - - /* PR binutils/17531: A corrupt binary could contain broken - histogram data. Do not go into an infinite loop trying - to process it. */ - if (chains[si] == si) - { - error (_("histogram chain links to itself\n")); - break; - } } + + /* PR binutils/17531: A corrupt binary could contain broken + histogram data. Do not go into an infinite loop trying + to process it. */ + if (chained > nchains) + { + error (_("histogram chain is corrupt\n")); + break; + } } counts = (unsigned long *) calloc (maxlength + 1, sizeof (*counts)); @@ -10746,6 +11222,8 @@ is_32bit_abs_reloc (unsigned int reloc_type) case EM_CYGNUS_FR30: case EM_FR30: return reloc_type == 3; /* R_FR30_32. */ + case EM_FT32: + return reloc_type == 1; /* R_FT32_32. */ case EM_H8S: case EM_H8_300: case EM_H8_300H: @@ -10840,6 +11318,8 @@ is_32bit_abs_reloc (unsigned int reloc_type) return reloc_type == 0x33; /* R_V810_WORD. */ case EM_VAX: return reloc_type == 1; /* R_VAX_32. */ + case EM_VISIUM: + return reloc_type == 3; /* R_VISIUM_32. */ case EM_X86_64: case EM_L1OM: case EM_K1OM: @@ -10855,9 +11335,16 @@ is_32bit_abs_reloc (unsigned int reloc_type) case EM_XTENSA: return reloc_type == 1; /* R_XTENSA_32. */ default: - error (_("Missing knowledge of 32-bit reloc types used in DWARF sections of machine number %d\n"), - elf_header.e_machine); - abort (); + { + static unsigned int prev_warn = 0; + + /* Avoid repeating the same warning multiple times. */ + if (prev_warn != elf_header.e_machine) + error (_("Missing knowledge of 32-bit reloc types used in DWARF sections of machine number %d\n"), + elf_header.e_machine); + prev_warn = elf_header.e_machine; + return FALSE; + } } } @@ -10907,6 +11394,8 @@ is_32bit_pcrel_reloc (unsigned int reloc_type) return reloc_type == 6; /* R_TILEGX_32_PCREL. */ case EM_TILEPRO: return reloc_type == 4; /* R_TILEPRO_32_PCREL. */ + case EM_VISIUM: + return reloc_type == 6; /* R_VISIUM_32_PCREL */ case EM_X86_64: case EM_L1OM: case EM_K1OM: @@ -11064,6 +11553,8 @@ is_16bit_abs_reloc (unsigned int reloc_type) case EM_CYGNUS_MN10300: case EM_MN10300: return reloc_type == 2; /* R_MN10300_16. */ + case EM_VISIUM: + return reloc_type == 2; /* R_VISIUM_16. */ case EM_XGATE: return reloc_type == 3; /* R_XGATE_16. */ default: @@ -11100,6 +11591,7 @@ is_none_reloc (unsigned int reloc_type) case EM_L1OM: /* R_X86_64_NONE. */ case EM_K1OM: /* R_X86_64_NONE. */ case EM_MN10300: /* R_MN10300_NONE. */ + case EM_FT32: /* R_FT32_NONE. */ case EM_MOXIE: /* R_MOXIE_NONE. */ case EM_M32R: /* R_M32R_NONE. */ case EM_TI_C6000:/* R_C6000_NONE. */ @@ -11216,8 +11708,11 @@ apply_relocations (void * file, reloc_size = 2; else { - warn (_("unable to apply unsupported reloc type %d to section %s\n"), - reloc_type, printable_section_name (section)); + static unsigned int prev_reloc = 0; + if (reloc_type != prev_reloc) + warn (_("unable to apply unsupported reloc type %d to section %s\n"), + reloc_type, printable_section_name (section)); + prev_reloc = reloc_type; continue; } @@ -11505,12 +12000,9 @@ dump_section_as_bytes (Elf_Internal_Shdr * section, /* Uncompresses a section that was compressed using zlib, in place. */ static int -uncompress_section_contents (unsigned char **buffer ATTRIBUTE_UNUSED, - dwarf_size_type *size ATTRIBUTE_UNUSED) +uncompress_section_contents (unsigned char **buffer, + dwarf_size_type *size) { -#ifndef HAVE_ZLIB_H - return FALSE; -#else dwarf_size_type compressed_size = *size; unsigned char * compressed_buffer = *buffer; dwarf_size_type uncompressed_size; @@ -11561,7 +12053,6 @@ uncompress_section_contents (unsigned char **buffer ATTRIBUTE_UNUSED, || strm.avail_out != 0) goto fail; - free (compressed_buffer); *buffer = uncompressed_buffer; *size = uncompressed_size; return 1; @@ -11571,7 +12062,6 @@ uncompress_section_contents (unsigned char **buffer ATTRIBUTE_UNUSED, /* Indicate decompression failure. */ *buffer = NULL; return 0; -#endif /* HAVE_ZLIB_H */ } static int @@ -11587,6 +12077,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); @@ -11594,9 +12085,30 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, section->size = 0; else { - section->size = sec->sh_size; - if (uncompress_section_contents (§ion->start, §ion->size)) - sec->sh_size = section->size; + unsigned char *start = section->start; + dwarf_size_type size = sec->sh_size; + + if ((sec->sh_flags & SHF_COMPRESSED) != 0) + { + Elf_Internal_Chdr chdr; + unsigned int compression_header_size + = get_compression_header (&chdr, start); + if (chdr.ch_type != ELFCOMPRESS_ZLIB + || chdr.ch_addralign != sec->sh_addralign) + return 0; + start += compression_header_size; + size -= compression_header_size; + } + + if (uncompress_section_contents (&start, &size)) + { + /* Free the compressed buffer, update the section buffer + and the section size if uncompress is successful. */ + free (section->start); + section->start = start; + sec->sh_size = size; + } + section->size = size; } if (section->start == NULL) @@ -11918,9 +12430,9 @@ static const char * arm_attr_tag_ABI_FP_number_model[] = static const char * arm_attr_tag_ABI_enum_size[] = {"Unused", "small", "int", "forced to int"}; static const char * arm_attr_tag_ABI_HardFP_use[] = - {"As Tag_FP_arch", "SP only", "DP only", "SP and DP"}; + {"As Tag_FP_arch", "SP only", "Reserved", "Deprecated"}; static const char * arm_attr_tag_ABI_VFP_args[] = - {"AAPCS", "VFP registers", "custom"}; + {"AAPCS", "VFP registers", "custom", "compatible"}; static const char * arm_attr_tag_ABI_WMMX_args[] = {"AAPCS", "WMMX registers", "custom"}; static const char * arm_attr_tag_ABI_optimization_goals[] = @@ -12123,7 +12635,8 @@ display_arm_attribute (unsigned char * p, break; default: - abort (); + printf (_("\n"), tag); + break; } return p; @@ -13084,10 +13597,12 @@ process_msp430x_specific (FILE * file) /* DATA points to the contents of a MIPS GOT that starts at VMA PLTGOT. Print the Address, Access and Initial fields of an entry at VMA ADDR - and return the VMA of the next entry. */ + and return the VMA of the next entry, or -1 if there was a problem. + Does not read from DATA_END or beyond. */ static bfd_vma -print_mips_got_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr) +print_mips_got_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr, + unsigned char * data_end) { printf (" "); print_vma (addr, LONG_HEX); @@ -13102,9 +13617,19 @@ print_mips_got_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr) else { bfd_vma entry; + unsigned char * from = data + addr - pltgot; - entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8); - print_vma (entry, LONG_HEX); + if (from + (is_32bit_elf ? 4 : 8) > data_end) + { + warn (_("MIPS GOT entry extends beyond the end of available data\n")); + printf ("%*s", is_32bit_elf ? 8 : 16, _("")); + return (bfd_vma) -1; + } + else + { + entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8); + print_vma (entry, LONG_HEX); + } } return addr + (is_32bit_elf ? 4 : 8); } @@ -13469,7 +13994,7 @@ process_mips_specific (FILE * file) /* Find the section header so that we get the size. */ sect = find_section_by_type (SHT_MIPS_OPTIONS); - /* PR 17533 file: 012-277276-0.004. */ + /* PR 17533 file: 012-277276-0.004. */ if (sect == NULL) { error (_("No MIPS_OPTIONS header found\n")); @@ -13491,7 +14016,7 @@ process_mips_specific (FILE * file) offset = cnt = 0; option = iopt; - while (offset < sect->sh_size) + while (offset <= sect->sh_size - sizeof (* eopt)) { Elf_External_Options * eoption; @@ -13502,8 +14027,15 @@ process_mips_specific (FILE * file) option->section = BYTE_GET (eoption->section); option->info = BYTE_GET (eoption->info); + /* PR 17531: file: ffa0fa3b. */ + if (option->size < sizeof (* eopt) + || offset + option->size > sect->sh_size) + { + error (_("Invalid size (%u) for MIPS option\n"), option->size); + return 0; + } offset += option->size; - + ++option; ++cnt; } @@ -13512,6 +14044,7 @@ process_mips_specific (FILE * file) printable_section_name (sect), cnt); option = iopt; + offset = 0; while (cnt-- > 0) { @@ -13648,13 +14181,18 @@ process_mips_specific (FILE * file) len = sizeof (* eopt); while (len < option->size) - if (((char *) option)[len] >= ' ' - && ((char *) option)[len] < 0x7f) - printf ("%c", ((char *) option)[len++]); - else - printf ("\\%03o", ((char *) option)[len++]); + { + char datum = * ((char *) eopt + offset + len); + if (ISPRINT (datum)) + printf ("%c", datum); + else + printf ("\\%03o", datum); + len ++; + } fputs ("\n", stdout); + + offset += option->size; ++option; } @@ -13744,6 +14282,7 @@ process_mips_specific (FILE * file) bfd_vma ent, local_end, global_end; size_t i, offset; unsigned char * data; + unsigned char * data_end; int addr_size; ent = pltgot; @@ -13754,18 +14293,25 @@ process_mips_specific (FILE * file) if (symtabno < gotsym) { error (_("The GOT symbol offset (%lu) is greater than the symbol table size (%lu)\n"), - (long) gotsym, (long) symtabno); + (unsigned long) gotsym, (unsigned long) symtabno); return 0; } - + global_end = local_end + (symtabno - gotsym) * addr_size; - assert (global_end >= local_end); + /* PR 17531: file: 54c91a34. */ + if (global_end < local_end) + { + error (_("Too many GOT symbols: %lu\n"), (unsigned long) symtabno); + return 0; + } + offset = offset_from_vma (file, pltgot, global_end - pltgot); data = (unsigned char *) get_data (NULL, file, offset, global_end - pltgot, 1, _("Global Offset Table data")); if (data == NULL) return 0; + data_end = data + (global_end - pltgot); printf (_("\nPrimary GOT:\n")); printf (_(" Canonical gp value: ")); @@ -13776,14 +14322,18 @@ process_mips_specific (FILE * file) printf (_(" %*s %10s %*s Purpose\n"), addr_size * 2, _("Address"), _("Access"), addr_size * 2, _("Initial")); - ent = print_mips_got_entry (data, pltgot, ent); + ent = print_mips_got_entry (data, pltgot, ent, data_end); printf (_(" Lazy resolver\n")); + if (ent == (bfd_vma) -1) + goto got_print_fail; if (data && (byte_get (data + ent - pltgot, addr_size) >> (addr_size * 8 - 1)) != 0) { - ent = print_mips_got_entry (data, pltgot, ent); + ent = print_mips_got_entry (data, pltgot, ent, data_end); printf (_(" Module pointer (GNU extension)\n")); + if (ent == (bfd_vma) -1) + goto got_print_fail; } printf ("\n"); @@ -13795,8 +14345,10 @@ process_mips_specific (FILE * file) addr_size * 2, _("Initial")); while (ent < local_end) { - ent = print_mips_got_entry (data, pltgot, ent); + ent = print_mips_got_entry (data, pltgot, ent, data_end); printf ("\n"); + if (ent == (bfd_vma) -1) + goto got_print_fail; } printf ("\n"); } @@ -13819,7 +14371,7 @@ process_mips_specific (FILE * file) for (i = gotsym; i < symtabno; i++) { - ent = print_mips_got_entry (data, pltgot, ent); + ent = print_mips_got_entry (data, pltgot, ent, data_end); printf (" "); if (dynamic_symbols == NULL) @@ -13843,10 +14395,13 @@ process_mips_specific (FILE * file) (unsigned long) i); printf ("\n"); + if (ent == (bfd_vma) -1) + break; } printf ("\n"); } + got_print_fail: if (data) free (data); } @@ -14103,6 +14658,10 @@ get_note_type (unsigned e_type) return _("NT_S390_SYSTEM_CALL (s390 system call restart data)"); case NT_S390_TDB: return _("NT_S390_TDB (s390 transaction diagnostic block)"); + case NT_S390_VXRS_LOW: + return _("NT_S390_VXRS_LOW (s390 vector registers 0-15 upper half)"); + case NT_S390_VXRS_HIGH: + return _("NT_S390_VXRS_HIGH (s390 vector registers 16-31)"); case NT_ARM_VFP: return _("NT_ARM_VFP (arm VFP registers)"); case NT_ARM_TLS: @@ -14329,6 +14888,85 @@ print_gnu_note (Elf_Internal_Note *pnote) return 1; } +static const char * +get_v850_elf_note_type (enum v850_notes n_type) +{ + static char buff[64]; + + switch (n_type) + { + case V850_NOTE_ALIGNMENT: return _("Alignment of 8-byte objects"); + case V850_NOTE_DATA_SIZE: return _("Sizeof double and long double"); + case V850_NOTE_FPU_INFO: return _("Type of FPU support needed"); + case V850_NOTE_SIMD_INFO: return _("Use of SIMD instructions"); + case V850_NOTE_CACHE_INFO: return _("Use of cache"); + case V850_NOTE_MMU_INFO: return _("Use of MMU"); + default: + snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), n_type); + return buff; + } +} + +static int +print_v850_note (Elf_Internal_Note * pnote) +{ + unsigned int val; + + if (pnote->descsz != 4) + return 0; + val = byte_get ((unsigned char *) pnote->descdata, pnote->descsz); + + if (val == 0) + { + printf (_("not set\n")); + return 1; + } + + switch (pnote->type) + { + case V850_NOTE_ALIGNMENT: + switch (val) + { + case EF_RH850_DATA_ALIGN4: printf (_("4-byte\n")); return 1; + case EF_RH850_DATA_ALIGN8: printf (_("8-byte\n")); return 1; + } + break; + + case V850_NOTE_DATA_SIZE: + switch (val) + { + case EF_RH850_DOUBLE32: printf (_("4-bytes\n")); return 1; + case EF_RH850_DOUBLE64: printf (_("8-bytes\n")); return 1; + } + break; + + case V850_NOTE_FPU_INFO: + switch (val) + { + case EF_RH850_FPU20: printf (_("FPU-2.0\n")); return 1; + case EF_RH850_FPU30: printf (_("FPU-3.0\n")); return 1; + } + break; + + case V850_NOTE_MMU_INFO: + case V850_NOTE_CACHE_INFO: + case V850_NOTE_SIMD_INFO: + if (val == EF_RH850_SIMD) + { + printf (_("yes\n")); + return 1; + } + break; + + default: + /* An 'unknown note type' message will already have been displayed. */ + break; + } + + printf (_("unknown value: %x\n"), val); + return 0; +} + static const char * get_netbsd_elfcore_note_type (unsigned e_type) { @@ -14511,7 +15149,7 @@ print_ia64_vms_note (Elf_Internal_Note * pnote) case NT_VMS_FPMODE: printf (_(" Floating Point mode: ")); printf ("0x%016" BFD_VMA_FMT "x\n", - (bfd_vma)byte_get ((unsigned char *)pnote->descdata, 8)); + (bfd_vma) byte_get ((unsigned char *)pnote->descdata, 8)); break; case NT_VMS_LINKTIME: printf (_(" Link time: ")); @@ -14534,9 +15172,9 @@ print_ia64_vms_note (Elf_Internal_Note * pnote) ((bfd_int64_t) byte_get ((unsigned char *)pnote->descdata + 8, 8)); printf (_("\n Link flags : ")); printf ("0x%016" BFD_VMA_FMT "x\n", - (bfd_vma)byte_get ((unsigned char *)pnote->descdata + 16, 8)); + (bfd_vma) byte_get ((unsigned char *)pnote->descdata + 16, 8)); printf (_(" Header flags: 0x%08x\n"), - (unsigned)byte_get ((unsigned char *)pnote->descdata + 24, 4)); + (unsigned) byte_get ((unsigned char *)pnote->descdata + 24, 4)); printf (_(" Image id : %s\n"), pnote->descdata + 32); break; #endif @@ -14621,6 +15259,7 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) { Elf_External_Note * pnotes; Elf_External_Note * external; + char * end; int res = 1; if (length <= 0) @@ -14637,13 +15276,14 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) (unsigned long) offset, (unsigned long) length); printf (_(" %-20s %10s\tDescription\n"), _("Owner"), _("Data size")); - while ((char *) external < (char *) pnotes + length) + end = (char *) pnotes + length; + while ((char *) external < end) { Elf_Internal_Note inote; size_t min_notesz; char *next; char * temp = NULL; - size_t data_remaining = ((char *) pnotes + length) - (char *) external; + size_t data_remaining = end - (char *) external; if (!is_ia64_vms ()) { @@ -14661,6 +15301,14 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) inote.namedata = external->name; inote.descsz = BYTE_GET (external->descsz); inote.descdata = inote.namedata + align_power (inote.namesz, 2); + /* PR 17531: file: 3443835e. */ + if (inote.descdata < (char *) pnotes || inote.descdata > end) + { + warn (_("Corrupt note: name size is too big: %lx\n"), inote.namesz); + inote.descdata = inote.namedata; + inote.namesz = 0; + } + inote.descpos = offset + (inote.descdata - (char *) pnotes); next = inote.descdata + align_power (inote.descsz, 2); } @@ -14762,6 +15410,87 @@ process_corefile_note_segments (FILE * file) return res; } +static int +process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length) +{ + Elf_External_Note * pnotes; + Elf_External_Note * external; + char * end; + int res = 1; + + if (length <= 0) + return 0; + + pnotes = (Elf_External_Note *) get_data (NULL, file, offset, 1, length, + _("v850 notes")); + if (pnotes == NULL) + return 0; + + external = pnotes; + end = (char*) pnotes + length; + + printf (_("\nDisplaying contents of Renesas V850 notes section at offset 0x%lx with length 0x%lx:\n"), + (unsigned long) offset, (unsigned long) length); + + while ((char *) external + sizeof (Elf_External_Note) < end) + { + Elf_External_Note * next; + Elf_Internal_Note inote; + + inote.type = BYTE_GET (external->type); + inote.namesz = BYTE_GET (external->namesz); + inote.namedata = external->name; + inote.descsz = BYTE_GET (external->descsz); + inote.descdata = inote.namedata + align_power (inote.namesz, 2); + inote.descpos = offset + (inote.descdata - (char *) pnotes); + + if (inote.descdata < (char *) pnotes || inote.descdata >= end) + { + warn (_("Corrupt note: name size is too big: %lx\n"), inote.namesz); + inote.descdata = inote.namedata; + inote.namesz = 0; + } + + next = (Elf_External_Note *) (inote.descdata + align_power (inote.descsz, 2)); + + if ( ((char *) next > end) + || ((char *) next < (char *) pnotes)) + { + warn (_("corrupt descsz found in note at offset 0x%lx\n"), + (unsigned long) ((char *) external - (char *) pnotes)); + warn (_(" type: 0x%lx, namesize: 0x%lx, descsize: 0x%lx\n"), + inote.type, inote.namesz, inote.descsz); + break; + } + + external = next; + + /* Prevent out-of-bounds indexing. */ + if ( inote.namedata + inote.namesz > end + || inote.namedata + inote.namesz < inote.namedata) + { + warn (_("corrupt namesz found in note at offset 0x%lx\n"), + (unsigned long) ((char *) external - (char *) pnotes)); + warn (_(" type: 0x%lx, namesize: 0x%lx, descsize: 0x%lx\n"), + inote.type, inote.namesz, inote.descsz); + break; + } + + printf (" %s: ", get_v850_elf_note_type (inote.type)); + + if (! print_v850_note (& inote)) + { + res = 0; + printf ("\n", + inote.namesz, inote.descsz); + } + } + + free (pnotes); + + return res; +} + static int process_note_sections (FILE * file) { @@ -14773,13 +15502,26 @@ process_note_sections (FILE * file) for (i = 0, section = section_headers; i < elf_header.e_shnum && section != NULL; i++, section++) - if (section->sh_type == SHT_NOTE) - { - res &= process_corefile_note_segment (file, - (bfd_vma) section->sh_offset, - (bfd_vma) section->sh_size); - n++; - } + { + if (section->sh_type == SHT_NOTE) + { + res &= process_corefile_note_segment (file, + (bfd_vma) section->sh_offset, + (bfd_vma) section->sh_size); + n++; + } + + if (( elf_header.e_machine == EM_V800 + || elf_header.e_machine == EM_V850 + || elf_header.e_machine == EM_CYGNUS_V850) + && section->sh_type == SHT_RENESAS_INFO) + { + res &= process_v850_notes (file, + (bfd_vma) section->sh_offset, + (bfd_vma) section->sh_size); + n++; + } + } if (n == 0) /* Try processing NOTE segments instead. */ @@ -15135,11 +15877,11 @@ process_archive (char * file_name, FILE * file, bfd_boolean is_thin_archive) error (_("%s: unable to dump the index as none was found\n"), file_name); else { - unsigned int i, l; + unsigned long i, l; unsigned long current_pos; - printf (_("Index of archive %s: (%ld entries, 0x%lx bytes in the symbol table)\n"), - file_name, (long) arch.index_num, arch.sym_size); + printf (_("Index of archive %s: (%lu entries, 0x%lx bytes in the symbol table)\n"), + file_name, (unsigned long) arch.index_num, arch.sym_size); current_pos = ftell (file); for (i = l = 0; i < arch.index_num; i++) @@ -15170,8 +15912,9 @@ process_archive (char * file_name, FILE * file, bfd_boolean is_thin_archive) file_name); break; } - printf ("\t%s\n", arch.sym_table + l); - l += strlen (arch.sym_table + l) + 1; + /* PR 17531: file: 0b6630b2. */ + printf ("\t%.*s\n", (int) (arch.sym_size - l), arch.sym_table + l); + l += strnlen (arch.sym_table + l, arch.sym_size - l) + 1; } if (arch.uses_64bit_indicies) @@ -15448,6 +16191,11 @@ main (int argc, char ** argv) if (optind < (argc - 1)) show_name = 1; + else if (optind >= argc) + { + warn (_("Nothing to do.\n")); + usage (stderr); + } err = 0; while (optind < argc)