/* readelf.c -- display contents of an ELF format file
- Copyright (C) 1998-2016 Free Software Foundation, Inc.
+ Copyright (C) 1998-2017 Free Software Foundation, Inc.
Originally developed by Eric Youngdale <eric@andante.jic.com>
Modifications by Nick Clifton <nickc@redhat.com>
#include "elf/metag.h"
#include "elf/microblaze.h"
#include "elf/mips.h"
+#include "elf/riscv.h"
#include "elf/mmix.h"
#include "elf/mn10200.h"
#include "elf/mn10300.h"
#include "elf/pj.h"
#include "elf/ppc.h"
#include "elf/ppc64.h"
+#include "elf/pru.h"
#include "elf/rl78.h"
#include "elf/rx.h"
#include "elf/s390.h"
{
case FULL_HEX:
nc = printf ("0x");
- /* Drop through. */
+ /* Fall through. */
case LONG_HEX:
#ifdef BFD64
case DEC_5:
if (vma <= 99999)
return printf ("%5" BFD_VMA_FMT "d", vma);
- /* Drop through. */
+ /* Fall through. */
case PREFIX_HEX:
nc = printf ("0x");
- /* Drop through. */
+ /* Fall through. */
case HEX:
return nc + printf ("%" BFD_VMA_FMT "x", vma);
return num_printed;
}
-/* Returns a pointer to a static buffer containing a printable version of
+/* Returns a pointer to a static buffer containing a printable version of
the given section's name. Like print_symbol, except that it does not try
to print multibyte characters, it just interprets them as hex values. */
if (set != NULL)
{
while ((i = *set++) > 0)
- if (streq (SECTION_NAME (section_headers + i), name))
- return section_headers + i;
+ {
+ /* See PR 21156 for a reproducer. */
+ if (i >= elf_header.e_shnum)
+ continue; /* FIXME: Should we issue an error message ? */
+
+ if (streq (SECTION_NAME (section_headers + i), name))
+ return section_headers + i;
+ }
}
return find_section (name);
case EM_OR1K:
case EM_PPC64:
case EM_PPC:
+ case EM_TI_PRU:
+ case EM_RISCV:
case EM_RL78:
case EM_RX:
case EM_S390:
rtype = elf_msp430x_reloc_type (type);
break;
}
+ /* Fall through. */
case EM_MSP430_OLD:
rtype = elf_msp430_reloc_type (type);
break;
rtype = elf_mips_reloc_type (type);
break;
+ case EM_RISCV:
+ rtype = elf_riscv_reloc_type (type);
+ break;
+
case EM_ALPHA:
rtype = elf_alpha_reloc_type (type);
break;
case EM_ALTERA_NIOS2:
rtype = elf_nios2_reloc_type (type);
break;
+
+ case EM_TI_PRU:
+ rtype = elf_pru_reloc_type (type);
+ break;
}
if (rtype == NULL)
case 0x7ffffffe: return "USED";
case 0x7fffffff: return "FILTER";
- default: return NULL;
+ default: return NULL;
}
}
case DT_PREINIT_ARRAY: return "PREINIT_ARRAY";
case DT_PREINIT_ARRAYSZ: return "PREINIT_ARRAYSZ";
+ case DT_SYMTAB_SHNDX: return "SYMTAB_SHNDX";
case DT_CHECKSUM: return "CHECKSUM";
case DT_PLTPADSZ: return "PLTPADSZ";
case EM_CR16:
case EM_MICROBLAZE:
case EM_MICROBLAZE_OLD: return "Xilinx MicroBlaze";
+ case EM_RISCV: return "RISC-V";
case EM_RL78: return "Renesas RL78";
case EM_RX: return "Renesas RX";
case EM_METAG: return "Imagination Technologies Meta processor architecture";
case EM_TILEGX: return "Tilera TILE-Gx multicore architecture family";
case EM_CUDA: return "NVIDIA CUDA architecture";
case EM_XGATE: return "Motorola XGATE embedded processor";
+ case EM_CLOUDSHIELD: return "CloudShield architecture family";
+ case EM_COREA_1ST: return "KIPO-KAIST Core-A 1st generation processor family";
+ case EM_COREA_2ND: return "KIPO-KAIST Core-A 2nd generation processor family";
+ case EM_OPEN8: return "Open8 8-bit RISC soft processor core";
+ case EM_VIDEOCORE5: return "Broadcom VideoCore V processor";
+ case EM_56800EX: return "Freescale 56800EX Digital Signal Controller (DSC)";
+ case EM_BA1: return "Beyond BA1 CPU architecture";
+ case EM_BA2: return "Beyond BA2 CPU architecture";
+ case EM_XCORE: return "XMOS xCORE processor family";
+ case EM_MCHP_PIC: return "Microchip 8-bit PIC(r) family";
+ case EM_KM32: return "KM211 KM32 32-bit processor";
+ case EM_KMX32: return "KM211 KMX32 32-bit processor";
+ case EM_KMX16: return "KM211 KMX16 16-bit processor";
+ case EM_KMX8: return "KM211 KMX8 8-bit processor";
+ case EM_KVARC: return "KM211 KVARC processor";
+ case EM_CDP: return "Paneve CDP architecture family";
+ case EM_COGE: return "Cognitive Smart Memory Processor";
+ case EM_COOL: return "Bluechip Systems CoolEngine";
+ case EM_NORC: return "Nanoradio Optimized RISC";
+ case EM_CSR_KALIMBA: return "CSR Kalimba architecture family";
+ case EM_Z80: return "Zilog Z80";
+ case EM_AMDGPU: return "AMD GPU architecture";
+ case EM_TI_PRU: return "TI PRU I/O processor";
default:
snprintf (buff, sizeof (buff), _("<unknown>: 0x%x"), e_machine);
return buff;
case E_ARC_MACH_ARC700:
strcat (buf, ", ARC700");
break;
- case E_ARC_MACH_NPS400:
- strcat (buf, ", NPS400");
- break;
/* The only times we should end up here are (a) A corrupt ELF, (b) A
new ELF with new architecture being read by an old version of
decode_NDS32_machine_flags (e_flags, buf, sizeof buf);
break;
+ case EM_RISCV:
+ if (e_flags & EF_RISCV_RVC)
+ strcat (buf, ", RVC");
+
+ switch (e_flags & EF_RISCV_FLOAT_ABI)
+ {
+ case EF_RISCV_FLOAT_ABI_SOFT:
+ strcat (buf, ", soft-float ABI");
+ break;
+
+ case EF_RISCV_FLOAT_ABI_SINGLE:
+ strcat (buf, ", single-float ABI");
+ break;
+
+ case EF_RISCV_FLOAT_ABI_DOUBLE:
+ strcat (buf, ", double-float ABI");
+ break;
+
+ case EF_RISCV_FLOAT_ABI_QUAD:
+ strcat (buf, ", quad-float ABI");
+ break;
+ }
+ break;
+
case EM_SH:
switch ((e_flags & EF_SH_MACH_MASK))
{
case ELFOSABI_NSK: return "HP - Non-Stop Kernel";
case ELFOSABI_AROS: return "AROS";
case ELFOSABI_FENIXOS: return "FenixOS";
+ case ELFOSABI_CLOUDABI: return "Nuxi CloudABI";
+ case ELFOSABI_OPENVOS: return "Stratus Technologies OpenVOS";
default:
if (osabi >= 64)
switch (elf_header.e_machine)
if (result != NULL)
return result;
- sprintf (buff, "LOPROC+%lx", p_type - PT_LOPROC);
+ sprintf (buff, "LOPROC+%#lx", p_type - PT_LOPROC);
}
else if ((p_type >= PT_LOOS) && (p_type <= PT_HIOS))
{
if (result != NULL)
return result;
- sprintf (buff, "LOOS+%lx", p_type - PT_LOOS);
+ sprintf (buff, "LOOS+%#lx", p_type - PT_LOOS);
}
else
snprintf (buff, sizeof (buff), _("<unknown>: %lx"), p_type);
if (elf_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
result = get_solaris_section_type (sh_type);
else
- result = NULL;
+ {
+ switch (sh_type)
+ {
+ case SHT_GNU_INCREMENTAL_INPUTS: result = "GNU_INCREMENTAL_INPUTS"; break;
+ case SHT_GNU_ATTRIBUTES: result = "GNU_ATTRIBUTES"; break;
+ case SHT_GNU_HASH: result = "GNU_HASH"; break;
+ case SHT_GNU_LIBLIST: result = "GNU_LIBLIST"; break;
+ default:
+ result = NULL;
+ break;
+ }
+ }
break;
}
error (_("Out of memory allocating dump request table.\n"));
else
{
- /* Copy current flag settings. */
- memcpy (new_dump_sects, dump_sects, num_dump_sects * sizeof (* dump_sects));
+ if (dump_sects)
+ {
+ /* Copy current flag settings. */
+ memcpy (new_dump_sects, dump_sects, num_dump_sects * sizeof (* dump_sects));
- free (dump_sects);
+ free (dump_sects);
+ }
dump_sects = new_dump_sects;
num_dump_sects = section + 1;
default:
/* xgettext:c-format */
error (_("Invalid option '-%c'\n"), c);
- /* Drop through. */
+ /* Fall through. */
case '?':
usage (stderr);
}
{
Elf_Internal_Phdr * segment;
unsigned int i;
+ Elf_Internal_Phdr * previous_load = NULL;
if (elf_header.e_phnum == 0)
{
(segment->p_flags & PF_R ? 'R' : ' '),
(segment->p_flags & PF_W ? 'W' : ' '),
(segment->p_flags & PF_X ? 'E' : ' '));
- print_vma (segment->p_align, HEX);
+ print_vma (segment->p_align, PREFIX_HEX);
}
- }
- if (do_segments)
- putc ('\n', stdout);
+ putc ('\n', stdout);
+ }
switch (segment->p_type)
{
+ case PT_LOAD:
+#if 0 /* Do not warn about out of order PT_LOAD segments. Although officially
+ required by the ELF standard, several programs, including the Linux
+ kernel, make use of non-ordered segments. */
+ if (previous_load
+ && previous_load->p_vaddr > segment->p_vaddr)
+ error (_("LOAD segments must be sorted in order of increasing VirtAddr\n"));
+#endif
+ if (segment->p_memsz < segment->p_filesz)
+ error (_("the segment's file size is larger than its memory size\n"));
+ previous_load = segment;
+ break;
+
+ case PT_PHDR:
+ /* PR 20815 - Verify that the program header is loaded into memory. */
+ if (i > 0 && previous_load != NULL)
+ error (_("the PHDR segment must occur before any LOAD segment\n"));
+ if (elf_header.e_machine != EM_PARISC)
+ {
+ unsigned int j;
+
+ for (j = 1; j < elf_header.e_phnum; j++)
+ if (program_headers[j].p_vaddr <= segment->p_vaddr
+ && (program_headers[j].p_vaddr + program_headers[j].p_memsz)
+ >= (segment->p_vaddr + segment->p_filesz))
+ break;
+ if (j == elf_header.e_phnum)
+ error (_("the PHDR segment is not covered by a LOAD segment\n"));
+ }
+ break;
+
case PT_DYNAMIC:
if (dynamic_addr)
error (_("more than one dynamic segment\n"));
/* 20 */ { STRING_COMMA_LEN ("COMPRESSED") },
/* ARM specific. */
/* 21 */ { STRING_COMMA_LEN ("ENTRYSECT") },
- /* 22 */ { STRING_COMMA_LEN ("ARM_NOREAD") },
+ /* 22 */ { STRING_COMMA_LEN ("ARM_PURECODE") },
/* 23 */ { STRING_COMMA_LEN ("COMDEF") }
};
switch (flag)
{
case SHF_ENTRYSECT: sindex = 21; break;
- case SHF_ARM_NOREAD: sindex = 22; break;
+ case SHF_ARM_PURECODE: sindex = 22; break;
case SHF_COMDEF: sindex = 23; break;
default: break;
}
&& flag == SHF_X86_64_LARGE)
*p = 'l';
else if (elf_header.e_machine == EM_ARM
- && flag == SHF_ARM_NOREAD)
+ && flag == SHF_ARM_PURECODE)
*p = 'y';
else if (flag & SHF_MASKOS)
{
}
static unsigned int
-get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf)
+get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf, bfd_size_type size)
{
if (is_32bit_elf)
{
Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) buf;
+
+ if (size < sizeof (* echdr))
+ {
+ error (_("Compressed section is too small even for a compression header\n"));
+ return 0;
+ }
+
chdr->ch_type = BYTE_GET (echdr->ch_type);
chdr->ch_size = BYTE_GET (echdr->ch_size);
chdr->ch_addralign = BYTE_GET (echdr->ch_addralign);
else
{
Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) buf;
+
+ if (size < sizeof (* echdr))
+ {
+ error (_("Compressed section is too small even for a compression header\n"));
+ return 0;
+ }
+
chdr->ch_type = BYTE_GET (echdr->ch_type);
chdr->ch_size = BYTE_GET (echdr->ch_size);
chdr->ch_addralign = BYTE_GET (echdr->ch_addralign);
i < elf_header.e_shnum;
i++, section++)
{
+ /* Run some sanity checks on the section header. */
+
+ /* Check the sh_link field. */
+ switch (section->sh_type)
+ {
+ case SHT_SYMTAB_SHNDX:
+ case SHT_GROUP:
+ case SHT_HASH:
+ case SHT_GNU_HASH:
+ case SHT_GNU_versym:
+ case SHT_REL:
+ case SHT_RELA:
+ if (section->sh_link < 1
+ || section->sh_link >= elf_header.e_shnum
+ || (section_headers[section->sh_link].sh_type != SHT_SYMTAB
+ && section_headers[section->sh_link].sh_type != SHT_DYNSYM))
+ warn (_("[%2u]: Link field (%u) should index a symtab section.\n"),
+ i, section->sh_link);
+ break;
+
+ case SHT_DYNAMIC:
+ case SHT_SYMTAB:
+ case SHT_DYNSYM:
+ case SHT_GNU_verneed:
+ case SHT_GNU_verdef:
+ case SHT_GNU_LIBLIST:
+ if (section->sh_link < 1
+ || section->sh_link >= elf_header.e_shnum
+ || section_headers[section->sh_link].sh_type != SHT_STRTAB)
+ warn (_("[%2u]: Link field (%u) should index a string section.\n"),
+ i, section->sh_link);
+ break;
+
+ case SHT_INIT_ARRAY:
+ case SHT_FINI_ARRAY:
+ case SHT_PREINIT_ARRAY:
+ if (section->sh_type < SHT_LOOS && section->sh_link != 0)
+ warn (_("[%2u]: Unexpected value (%u) in link field.\n"),
+ i, section->sh_link);
+ break;
+
+ default:
+ /* FIXME: Add support for target specific section types. */
+#if 0 /* Currently we do not check other section types as there are too
+ many special cases. Stab sections for example have a type
+ of SHT_PROGBITS but an sh_link field that links to the .stabstr
+ section. */
+ if (section->sh_type < SHT_LOOS && section->sh_link != 0)
+ warn (_("[%2u]: Unexpected value (%u) in link field.\n"),
+ i, section->sh_link);
+#endif
+ break;
+ }
+
+ /* Check the sh_info field. */
+ switch (section->sh_type)
+ {
+ case SHT_REL:
+ case SHT_RELA:
+ if (section->sh_info < 1
+ || section->sh_info >= elf_header.e_shnum
+ || (section_headers[section->sh_info].sh_type != SHT_PROGBITS
+ && section_headers[section->sh_info].sh_type != SHT_NOBITS
+ && section_headers[section->sh_info].sh_type != SHT_NOTE
+ && section_headers[section->sh_info].sh_type != SHT_INIT_ARRAY
+ /* FIXME: Are other section types valid ? */
+ && section_headers[section->sh_info].sh_type < SHT_LOOS))
+ {
+ if (section->sh_info == 0
+ && (streq (SECTION_NAME (section), ".rel.dyn")
+ || streq (SECTION_NAME (section), ".rela.dyn")))
+ /* The .rel.dyn and .rela.dyn sections have an sh_info field
+ of zero. The relocations in these sections may apply
+ to many different sections. */
+ ;
+ else
+ warn (_("[%2u]: Info field (%u) should index a relocatable section.\n"),
+ i, section->sh_info);
+ }
+ break;
+
+ case SHT_DYNAMIC:
+ case SHT_HASH:
+ case SHT_SYMTAB_SHNDX:
+ case SHT_INIT_ARRAY:
+ case SHT_FINI_ARRAY:
+ case SHT_PREINIT_ARRAY:
+ if (section->sh_info != 0)
+ warn (_("[%2u]: Unexpected value (%u) in info field.\n"),
+ i, section->sh_info);
+ break;
+
+ case SHT_GROUP:
+ case SHT_SYMTAB:
+ case SHT_DYNSYM:
+ /* A symbol index - we assume that it is valid. */
+ break;
+
+ default:
+ /* FIXME: Add support for target specific section types. */
+ if (section->sh_type == SHT_NOBITS)
+ /* NOBITS section headers with non-zero sh_info fields can be
+ created when a binary is stripped of everything but its debug
+ information. The stripped sections have their headers
+ preserved but their types set to SHT_NOBITS. So do not check
+ this type of section. */
+ ;
+ else if (section->sh_flags & SHF_INFO_LINK)
+ {
+ if (section->sh_info < 1 || section->sh_info >= elf_header.e_shnum)
+ warn (_("[%2u]: Expected link to another section in info field"), i);
+ }
+ else if (section->sh_type < SHT_LOOS && section->sh_info != 0)
+ warn (_("[%2u]: Unexpected value (%u) in info field.\n"),
+ i, section->sh_info);
+ break;
+ }
+
printf (" [%2u] ", i);
if (do_section_details)
printf ("%s\n ", printable_section_name (section));
/* 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);
+
+ (void) get_compression_header (&chdr, buf, sizeof (buf));
+
if (chdr.ch_type == ELFCOMPRESS_ZLIB)
printf (" ZLIB, ");
else
|| elf_header.e_machine == EM_K1OM)
printf (_("l (large), "));
else if (elf_header.e_machine == EM_ARM)
- printf (_("y (noread), "));
+ printf (_("y (purecode), "));
printf ("p (processor specific)\n");
}
static const char *
get_group_flags (unsigned int flags)
{
- static char buff[32];
- switch (flags)
- {
- case 0:
- return "";
+ static char buff[128];
- case GRP_COMDAT:
- return "COMDAT ";
+ if (flags == 0)
+ return "";
+ else if (flags == GRP_COMDAT)
+ return "COMDAT ";
- default:
- snprintf (buff, sizeof (buff), _("[<unknown>: 0x%x] "), flags);
- break;
+ snprintf (buff, 14, _("[0x%x: "), flags);
+
+ flags &= ~ GRP_COMDAT;
+ if (flags & GRP_MASKOS)
+ {
+ strcat (buff, "<OS specific>");
+ flags &= ~ GRP_MASKOS;
+ }
+
+ if (flags & GRP_MASKPROC)
+ {
+ strcat (buff, "<PROC specific>");
+ flags &= ~ GRP_MASKPROC;
}
+
+ if (flags)
+ strcat (buff, "<unknown>");
+
+ strcat (buff, "]");
return buff;
}
case DT_MIPS_TIME_STAMP:
{
- char timebuf[20];
+ char timebuf[128];
struct tm * tmp;
time_t atime = entry->d_un.d_val;
case DT_MIPS_DELTA_SYM_NO:
case DT_MIPS_DELTA_CLASSSYM_NO:
case DT_MIPS_COMPACT_SIZE:
- print_vma (entry->d_un.d_ptr, DEC);
+ print_vma (entry->d_un.d_val, DEC);
break;
default:
case DT_SYMENT :
case DT_RELENT :
dynamic_info[entry->d_tag] = entry->d_un.d_val;
+ /* Fall through. */
case DT_PLTPADSZ:
case DT_MOVEENT :
case DT_MOVESZ :
int j;
int isum;
- /* Check for very large indicies. */
+ /* Check for very large indices. */
if (idx > (size_t) (endbuf - (char *) edefs))
break;
ent.vd_ndx, ent.vd_cnt);
/* Check for overflow. */
- if (ent.vd_aux > (size_t) (endbuf - vstart))
+ if (ent.vd_aux + sizeof (* eaux) > (size_t) (endbuf - vstart))
break;
vstart += ent.vd_aux;
}
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)
+get_symbol_version_string (FILE * file,
+ bfd_boolean 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)
{
unsigned char data[2];
unsigned short vers_data;
}
putchar ('\n');
+
+ if (ELF_ST_BIND (psym->st_info) == STB_LOCAL
+ && si >= section->sh_info
+ /* Irix 5 and 6 MIPS binaries are known to ignore this requirement. */
+ && elf_header.e_machine != EM_MIPS
+ /* Solaris binaries have been found to violate this requirement as
+ well. Not sure if this is a bug or an ABI requirement. */
+ && elf_header.e_ident[EI_OSABI] != ELFOSABI_SOLARIS)
+ warn (_("local symbol %u found at index >= %s's sh_info value of %u\n"),
+ si, printable_section_name (section), section->sh_info);
}
free (symtab);
return 1;
}
+#define IN_RANGE(START,END,ADDR,OFF) \
+ (((ADDR) >= (START)) && ((ADDR) + (OFF) < (END)))
+
/* Check to see if the given reloc needs to be handled in a target specific
manner. If so then process the reloc and return TRUE otherwise return
- FALSE. */
+ FALSE.
+
+ If called with reloc == NULL, then this is a signal that reloc processing
+ for the current section has finished, and any saved state should be
+ discarded. */
static bfd_boolean
target_specific_reloc_handling (Elf_Internal_Rela * reloc,
unsigned char * start,
- Elf_Internal_Sym * symtab)
+ unsigned char * end,
+ Elf_Internal_Sym * symtab,
+ unsigned long num_syms)
{
- unsigned int reloc_type = get_reloc_type (reloc->r_info);
+ unsigned int reloc_type = 0;
+ unsigned long sym_index = 0;
+
+ if (reloc)
+ {
+ reloc_type = get_reloc_type (reloc->r_info);
+ sym_index = get_reloc_symindex (reloc->r_info);
+ }
switch (elf_header.e_machine)
{
{
static Elf_Internal_Sym * saved_sym = NULL;
+ if (reloc == NULL)
+ {
+ saved_sym = NULL;
+ return TRUE;
+ }
+
switch (reloc_type)
{
case 10: /* R_MSP430_SYM_DIFF */
if (uses_msp430x_relocs ())
break;
+ /* Fall through. */
case 21: /* R_MSP430X_SYM_DIFF */
- saved_sym = symtab + get_reloc_symindex (reloc->r_info);
+ /* PR 21139. */
+ if (sym_index >= num_syms)
+ error (_("MSP430 SYM_DIFF reloc contains invalid symbol index %lu\n"),
+ sym_index);
+ else
+ saved_sym = symtab + sym_index;
return TRUE;
case 1: /* R_MSP430_32 or R_MSP430_ABS32 */
handle_sym_diff:
if (saved_sym != NULL)
{
+ int reloc_size = reloc_type == 1 ? 4 : 2;
bfd_vma value;
- value = reloc->r_addend
- + (symtab[get_reloc_symindex (reloc->r_info)].st_value
- - saved_sym->st_value);
+ if (sym_index >= num_syms)
+ error (_("MSP430 reloc contains invalid symbol index %lu\n"),
+ sym_index);
+ else
+ {
+ value = reloc->r_addend + (symtab[sym_index].st_value
+ - saved_sym->st_value);
- byte_put (start + reloc->r_offset, value, reloc_type == 1 ? 4 : 2);
+ if (IN_RANGE (start, end, start + reloc->r_offset, reloc_size))
+ byte_put (start + reloc->r_offset, value, reloc_size);
+ else
+ /* PR 21137 */
+ error (_("MSP430 sym diff reloc contains invalid offset: 0x%lx\n"),
+ (long) reloc->r_offset);
+ }
saved_sym = NULL;
return TRUE;
{
static Elf_Internal_Sym * saved_sym = NULL;
+ if (reloc == NULL)
+ {
+ saved_sym = NULL;
+ return TRUE;
+ }
+
switch (reloc_type)
{
case 34: /* R_MN10300_ALIGN */
return TRUE;
case 33: /* R_MN10300_SYM_DIFF */
- saved_sym = symtab + get_reloc_symindex (reloc->r_info);
+ if (sym_index >= num_syms)
+ error (_("MN10300_SYM_DIFF reloc contains invalid symbol index %lu\n"),
+ sym_index);
+ else
+ saved_sym = symtab + sym_index;
return TRUE;
+
case 1: /* R_MN10300_32 */
case 2: /* R_MN10300_16 */
if (saved_sym != NULL)
{
+ int reloc_size = reloc_type == 1 ? 4 : 2;
bfd_vma value;
- value = reloc->r_addend
- + (symtab[get_reloc_symindex (reloc->r_info)].st_value
- - saved_sym->st_value);
+ if (sym_index >= num_syms)
+ error (_("MN10300 reloc contains invalid symbol index %lu\n"),
+ sym_index);
+ else
+ {
+ value = reloc->r_addend + (symtab[sym_index].st_value
+ - saved_sym->st_value);
- byte_put (start + reloc->r_offset, value, reloc_type == 1 ? 4 : 2);
+ if (IN_RANGE (start, end, start + reloc->r_offset, reloc_size))
+ byte_put (start + reloc->r_offset, value, reloc_size);
+ else
+ error (_("MN10300 sym diff reloc contains invalid offset: 0x%lx\n"),
+ (long) reloc->r_offset);
+ }
saved_sym = NULL;
return TRUE;
static bfd_vma saved_sym2 = 0;
static bfd_vma value;
+ if (reloc == NULL)
+ {
+ saved_sym1 = saved_sym2 = 0;
+ return TRUE;
+ }
+
switch (reloc_type)
{
case 0x80: /* R_RL78_SYM. */
saved_sym1 = saved_sym2;
- saved_sym2 = symtab[get_reloc_symindex (reloc->r_info)].st_value;
- saved_sym2 += reloc->r_addend;
+ if (sym_index >= num_syms)
+ error (_("RL78_SYM reloc contains invalid symbol index %lu\n"),
+ sym_index);
+ else
+ {
+ saved_sym2 = symtab[sym_index].st_value;
+ saved_sym2 += reloc->r_addend;
+ }
return TRUE;
case 0x83: /* R_RL78_OPsub. */
break;
case 0x41: /* R_RL78_ABS32. */
- byte_put (start + reloc->r_offset, value, 4);
+ if (IN_RANGE (start, end, start + reloc->r_offset, 4))
+ byte_put (start + reloc->r_offset, value, 4);
+ else
+ error (_("RL78 sym diff reloc contains invalid offset: 0x%lx\n"),
+ (long) reloc->r_offset);
value = 0;
return TRUE;
case 0x43: /* R_RL78_ABS16. */
- byte_put (start + reloc->r_offset, value, 2);
+ if (IN_RANGE (start, end, start + reloc->r_offset, 2))
+ byte_put (start + reloc->r_offset, value, 2);
+ else
+ error (_("RL78 sym diff reloc contains invalid offset: 0x%lx\n"),
+ (long) reloc->r_offset);
value = 0;
return TRUE;
case EM_960:
return reloc_type == 2; /* R_960_32. */
case EM_AARCH64:
- return reloc_type == 258; /* R_AARCH64_ABS32 */
+ return (reloc_type == 258
+ || reloc_type == 1); /* R_AARCH64_ABS32 || R_AARCH64_P32_ABS32 */
case EM_ADAPTEVA_EPIPHANY:
return reloc_type == 3;
case EM_ALPHA:
return reloc_type == 1; /* R_PPC64_ADDR32. */
case EM_PPC:
return reloc_type == 1; /* R_PPC_ADDR32. */
+ case EM_TI_PRU:
+ return reloc_type == 11; /* R_PRU_BFD_RELOC_32. */
+ case EM_RISCV:
+ return reloc_type == 1; /* R_RISCV_32. */
case EM_RL78:
return reloc_type == 1; /* R_RL78_DIR32. */
case EM_RX:
return reloc_type == 80; /* R_PARISC_DIR64. */
case EM_PPC64:
return reloc_type == 38; /* R_PPC64_ADDR64. */
+ case EM_RISCV:
+ return reloc_type == 2; /* R_RISCV_64. */
case EM_SPARC32PLUS:
case EM_SPARCV9:
case EM_SPARC:
case EM_CYGNUS_MN10200:
case EM_MN10200:
return reloc_type == 4; /* R_MN10200_24. */
+ case EM_FT32:
+ return reloc_type == 5; /* R_FT32_20. */
default:
return FALSE;
}
case EM_MSP430:
if (uses_msp430x_relocs ())
return reloc_type == 2; /* R_MSP430_ABS16. */
+ /* Fall through. */
case EM_MSP430_OLD:
return reloc_type == 5; /* R_MSP430_16_BYTE. */
case EM_NDS32:
return reloc_type == 9; /* R_NIOS_16. */
case EM_OR1K:
return reloc_type == 2; /* R_OR1K_16. */
+ case EM_TI_PRU:
+ return reloc_type == 8; /* R_PRU_BFD_RELOC_16. */
case EM_TI_C6000:
return reloc_type == 2; /* R_C6000_ABS16. */
case EM_VISIUM:
case EM_PARISC: /* R_PARISC_NONE. */
case EM_PPC64: /* R_PPC64_NONE. */
case EM_PPC: /* R_PPC_NONE. */
+ case EM_RISCV: /* R_RISCV_NONE. */
case EM_S390: /* R_390_NONE. */
case EM_S390_OLD:
case EM_SH: /* R_SH_NONE. */
|| reloc_type == 205 /* R_NDS32_DIFF16. */
|| reloc_type == 206 /* R_NDS32_DIFF32. */
|| reloc_type == 207 /* R_NDS32_ULEB128. */);
+ case EM_TI_PRU:
+ return (reloc_type == 0 /* R_PRU_NONE. */
+ || reloc_type == 65 /* R_PRU_DIFF8. */
+ || reloc_type == 66 /* R_PRU_DIFF16. */
+ || reloc_type == 67 /* R_PRU_DIFF32. */);
case EM_XTENSA_OLD:
case EM_XTENSA:
return (reloc_type == 0 /* R_XTENSA_NONE. */
const Elf_Internal_Shdr * section,
unsigned char * start,
bfd_size_type size,
- void ** relocs_return,
+ void ** relocs_return,
unsigned long * num_relocs_return)
{
Elf_Internal_Shdr * relsec;
is_rela = FALSE;
symsec = section_headers + relsec->sh_link;
+ if (symsec->sh_type != SHT_SYMTAB
+ && symsec->sh_type != SHT_DYNSYM)
+ return;
symtab = GET_ELF_SYMBOLS ((FILE *) file, symsec, & num_syms);
for (rp = relocs; rp < relocs + num_relocs; ++rp)
reloc_type = get_reloc_type (rp->r_info);
- if (target_specific_reloc_handling (rp, start, symtab))
+ if (target_specific_reloc_handling (rp, start, end, symtab, num_syms))
continue;
else if (is_none_reloc (reloc_type))
continue;
}
free (symtab);
+ /* Let the target specific reloc processing code know that
+ we have finished with these relocs. */
+ target_specific_reloc_handling (NULL, NULL, NULL, NULL, 0);
if (relocs_return)
{
{
Elf_Internal_Chdr chdr;
unsigned int compression_header_size
- = get_compression_header (& chdr, (unsigned char *) start);
+ = get_compression_header (& chdr, (unsigned char *) start,
+ num_bytes);
if (chdr.ch_type != ELFCOMPRESS_ZLIB)
{
new_size -= 12;
}
- if (uncompressed_size
- && uncompress_section_contents (& start,
- uncompressed_size, & new_size))
- num_bytes = new_size;
+ if (uncompressed_size)
+ {
+ if (uncompress_section_contents (& start,
+ uncompressed_size, & new_size))
+ num_bytes = new_size;
+ else
+ {
+ error (_("Unable to decompress section %s\n"),
+ printable_section_name (section));
+ return;
+ }
+ }
+ else
+ start = real_start;
}
/* If the section being dumped has relocations against it the user might
{
Elf_Internal_Chdr chdr;
unsigned int compression_header_size
- = get_compression_header (& chdr, start);
+ = get_compression_header (& chdr, start, section_size);
if (chdr.ch_type != ELFCOMPRESS_ZLIB)
{
new_size -= 12;
}
- if (uncompressed_size
- && uncompress_section_contents (& start, uncompressed_size,
- & new_size))
- section_size = new_size;
+ if (uncompressed_size)
+ {
+ if (uncompress_section_contents (& start, uncompressed_size,
+ & new_size))
+ {
+ section_size = new_size;
+ }
+ else
+ {
+ error (_("Unable to decompress section %s\n"),
+ printable_section_name (section));
+ /* FIXME: Print the section anyway ? */
+ return;
+ }
+ }
+ else
+ start = real_start;
}
if (relocate)
if ((sec->sh_flags & SHF_COMPRESSED) != 0)
{
Elf_Internal_Chdr chdr;
- unsigned int compression_header_size
- = get_compression_header (&chdr, start);
+ unsigned int compression_header_size;
+
+ if (size < (is_32bit_elf
+ ? sizeof (Elf32_External_Chdr)
+ : sizeof (Elf64_External_Chdr)))
+ {
+ warn (_("compressed section %s is too small to contain a compression header"),
+ section->name);
+ return 0;
+ }
+
+ compression_header_size = get_compression_header (&chdr, start, size);
+
if (chdr.ch_type != ELFCOMPRESS_ZLIB)
{
warn (_("section '%s' has unsupported compress type: %d\n"),
size -= 12;
}
- if (uncompressed_size
- && uncompress_section_contents (&start, uncompressed_size,
- &size))
+ if (uncompressed_size)
{
- /* Free the compressed buffer, update the section buffer
- and the section size if uncompress is successful. */
- free (section->start);
- section->start = start;
+ if (uncompress_section_contents (&start, uncompressed_size,
+ &size))
+ {
+ /* Free the compressed buffer, update the section buffer
+ and the section size if uncompress is successful. */
+ free (section->start);
+ section->start = start;
+ }
+ else
+ {
+ error (_("Unable to decompress section %s\n"),
+ printable_section_name (sec));
+ return 0;
+ }
}
+
section->size = size;
}
/* Check to see if the user requested a
dump of a section that does not exist. */
- while (i++ < num_dump_sects)
- if (dump_sects[i])
- warn (_("Section %d was not dumped because it does not exist!\n"), i);
+ while (i < num_dump_sects)
+ {
+ if (dump_sects[i])
+ warn (_("Section %d was not dumped because it does not exist!\n"), i);
+ i++;
+ }
}
static void
const unsigned char * const end)
{
unsigned int len;
- int val;
+ unsigned int val;
if (tag == Tag_GNU_Power_ABI_FP)
{
val = read_uleb128 (p, &len, end);
p += len;
printf (" Tag_GNU_Power_ABI_FP: ");
+ if (len == 0)
+ {
+ printf (_("<corrupt>\n"));
+ return p;
+ }
- switch (val)
+ if (val > 15)
+ printf ("(%#x), ", val);
+
+ switch (val & 3)
{
case 0:
- printf (_("Hard or soft float\n"));
+ printf (_("unspecified hard/soft float, "));
break;
case 1:
- printf (_("Hard float\n"));
+ printf (_("hard float, "));
break;
case 2:
- printf (_("Soft float\n"));
+ printf (_("soft float, "));
break;
case 3:
- printf (_("Single-precision hard float\n"));
+ printf (_("single-precision hard float, "));
break;
- default:
- printf ("??? (%d)\n", val);
+ }
+
+ switch (val & 0xC)
+ {
+ case 0:
+ printf (_("unspecified long double\n"));
+ break;
+ case 4:
+ printf (_("128-bit IBM long double\n"));
+ break;
+ case 8:
+ printf (_("64-bit long double\n"));
+ break;
+ case 12:
+ printf (_("128-bit IEEE long double\n"));
break;
}
return p;
- }
+ }
if (tag == Tag_GNU_Power_ABI_Vector)
{
val = read_uleb128 (p, &len, end);
p += len;
printf (" Tag_GNU_Power_ABI_Vector: ");
- switch (val)
+ if (len == 0)
+ {
+ printf (_("<corrupt>\n"));
+ return p;
+ }
+
+ if (val > 3)
+ printf ("(%#x), ", val);
+
+ switch (val & 3)
{
case 0:
- printf (_("Any\n"));
+ printf (_("unspecified\n"));
break;
case 1:
- printf (_("Generic\n"));
+ printf (_("generic\n"));
break;
case 2:
printf ("AltiVec\n");
case 3:
printf ("SPE\n");
break;
- default:
- printf ("??? (%d)\n", val);
- break;
}
return p;
- }
+ }
if (tag == Tag_GNU_Power_ABI_Struct_Return)
{
- if (p == end)
+ val = read_uleb128 (p, &len, end);
+ p += len;
+ printf (" Tag_GNU_Power_ABI_Struct_Return: ");
+ if (len == 0)
{
- warn (_("corrupt Tag_GNU_Power_ABI_Struct_Return\n"));
+ printf (_("<corrupt>\n"));
return p;
}
- val = read_uleb128 (p, &len, end);
- p += len;
- printf (" Tag_GNU_Power_ABI_Struct_Return: ");
- switch (val)
- {
- case 0:
- printf (_("Any\n"));
- break;
- case 1:
- printf ("r3/r4\n");
- break;
- case 2:
- printf (_("Memory\n"));
- break;
- default:
- printf ("??? (%d)\n", val);
- break;
- }
+ if (val > 2)
+ printf ("(%#x), ", val);
+
+ switch (val & 3)
+ {
+ case 0:
+ printf (_("unspecified\n"));
+ break;
+ case 1:
+ printf ("r3/r4\n");
+ break;
+ case 2:
+ printf (_("memory\n"));
+ break;
+ case 3:
+ printf ("???\n");
+ break;
+ }
return p;
}
goto do_numlist;
case 3:
printf (_("Symbol Attributes:"));
+ /* Fall through. */
do_numlist:
for (;;)
{
fputs ("\n\tDSP ASE", stdout);
if (mask & AFL_ASE_DSPR2)
fputs ("\n\tDSP R2 ASE", stdout);
+ if (mask & AFL_ASE_DSPR3)
+ fputs ("\n\tDSP R3 ASE", stdout);
if (mask & AFL_ASE_EVA)
fputs ("\n\tEnhanced VA Scheme", stdout);
if (mask & AFL_ASE_MCU)
{
Elf32_Lib liblist;
time_t atime;
- char timebuf[20];
+ char timebuf[128];
struct tm * tmp;
liblist.l_name = BYTE_GET (elib[cnt].l_name);
cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (* iopt));
if (iopt == NULL)
{
- error (_("Out of memory allocatinf space for MIPS options\n"));
+ error (_("Out of memory allocating space for MIPS options\n"));
return 0;
}
{
Elf32_Lib liblist;
time_t atime;
- char timebuf[20];
+ char timebuf[128];
struct tm * tmp;
liblist.l_name = BYTE_GET (elib[cnt].l_name);
static const char *
get_gnu_elf_note_type (unsigned e_type)
{
- static char buff[64];
-
+ /* NB/ Keep this switch statement in sync with print_gnu_note (). */
switch (e_type)
{
case NT_GNU_ABI_TAG:
case NT_GNU_GOLD_VERSION:
return _("NT_GNU_GOLD_VERSION (gold version)");
default:
- break;
- }
+ {
+ static char buff[64];
- snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type);
- return buff;
+ snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type);
+ return buff;
+ }
+ }
}
static int
print_gnu_note (Elf_Internal_Note *pnote)
{
+ /* NB/ Keep this switch statement in sync with get_gnu_elf_note_type (). */
switch (pnote->type)
{
case NT_GNU_BUILD_ID:
printf ("\n");
}
break;
+
+ case NT_GNU_HWCAP:
+ {
+ unsigned long num_entries, mask;
+
+ /* Hardware capabilities information. Word 0 is the number of entries.
+ Word 1 is a bitmask of enabled entries. The rest of the descriptor
+ is a series of entries, where each entry is a single byte followed
+ by a nul terminated string. The byte gives the bit number to test
+ if enabled in the bitmask. */
+ printf (_(" Hardware Capabilities: "));
+ if (pnote->descsz < 8)
+ {
+ printf (_("<corrupt GNU_HWCAP>\n"));
+ break;
+ }
+ num_entries = byte_get ((unsigned char *) pnote->descdata, 4);
+ mask = byte_get ((unsigned char *) pnote->descdata + 4, 4);
+ printf (_("num entries: %ld, enabled mask: %lx\n"), num_entries, mask);
+ /* FIXME: Add code to display the entries... */
+ }
+ break;
+
+ default:
+ /* Handle unrecognised types. An error message should have already been
+ created by get_gnu_elf_note_type(), so all that we need to do is to
+ display the data. */
+ {
+ unsigned long i;
+
+ printf (_(" Description data: "));
+ for (i = 0; i < pnote->descsz; ++i)
+ printf ("%02x ", pnote->descdata[i] & 0xff);
+ printf ("\n");
+ }
+ break;
}
return 1;
return 0;
}
-static int
+static int
process_netbsd_elf_note (Elf_Internal_Note * pnote)
{
unsigned int version;
printf (" NetBSD\t\t0x%08lx\tIDENT %u (%u.%u%s%c)\n", pnote->descsz,
version, version / 100000000, (version / 1000000) % 100,
(version / 10000) % 100 > 26 ? "Z" : "",
- 'A' + (version / 10000) % 26);
+ 'A' + (version / 10000) % 26);
else
printf (" NetBSD\t\t0x%08lx\tIDENT %u (%u.%u.%u)\n", pnote->descsz,
version, version / 100000000, (version / 1000000) % 100,
- (version / 100) % 100);
+ (version / 100) % 100);
return 1;
case NT_NETBSD_MARCH:
If the value of namesz is zero, there is no name present. */
static int
-process_note (Elf_Internal_Note * pnote)
+process_note (Elf_Internal_Note * pnote,
+ FILE * file ATTRIBUTE_UNUSED,
+ Elf_Internal_Shdr * section ATTRIBUTE_UNUSED)
{
const char * name = pnote->namesz ? pnote->namedata : "(NONE)";
const char * nt;
note type strings. */
nt = get_note_type (pnote->type);
- printf (" %-20s 0x%08lx\t%s\n", name, pnote->descsz, nt);
+ printf (" ");
+ print_symbol (-20, name);
+ printf (" 0x%08lx\t%s\n", pnote->descsz, nt);
if (const_strneq (pnote->namedata, "IPF/VMS"))
return print_ia64_vms_note (pnote);
return print_stapsdt_note (pnote);
else if (const_strneq (pnote->namedata, "CORE"))
return print_core_note (pnote);
- else
- return 1;
-}
+ else if (pnote->descsz)
+ {
+ unsigned long i;
+
+ printf (_(" description data: "));
+ for (i = 0; i < pnote->descsz; i++)
+ printf ("%02x ", pnote->descdata[i]);
+ printf ("\n");
+ }
+
+ return 1;
+}
static int
-process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length)
+process_notes_at (FILE * file,
+ Elf_Internal_Shdr * section,
+ bfd_vma offset,
+ bfd_vma length)
{
Elf_External_Note * pnotes;
Elf_External_Note * external;
if (length <= 0)
return 0;
- pnotes = (Elf_External_Note *) get_data (NULL, file, offset, 1, length,
- _("notes"));
+ if (section)
+ {
+ pnotes = (Elf_External_Note *) get_section_contents (section, file);
+ if (pnotes)
+ apply_relocations (file, section, (unsigned char *) pnotes, length, NULL, NULL);
+ }
+ else
+ pnotes = (Elf_External_Note *) get_data (NULL, file, offset, 1, length,
+ _("notes"));
if (pnotes == NULL)
return 0;
external = pnotes;
- printf (_("\nDisplaying notes found at file offset 0x%08lx with length 0x%08lx:\n"),
- (unsigned long) offset, (unsigned long) length);
+ if (section)
+ printf (_("\nDisplaying notes found in: %s\n"), printable_section_name (section));
+ else
+ printf (_("\nDisplaying notes found at file offset 0x%08lx with length 0x%08lx:\n"),
+ (unsigned long) offset, (unsigned long) length);
+
printf (_(" %-20s %10s\tDescription\n"), _("Owner"), _("Data size"));
end = (char *) pnotes + length;
inote.namedata = temp;
}
- res &= process_note (& inote);
+ res &= process_note (& inote, file, section);
if (temp != NULL)
{
i++, segment++)
{
if (segment->p_type == PT_NOTE)
- res &= process_corefile_note_segment (file,
- (bfd_vma) segment->p_offset,
- (bfd_vma) segment->p_filesz);
+ res &= process_notes_at (file, NULL,
+ (bfd_vma) segment->p_offset,
+ (bfd_vma) segment->p_filesz);
}
return res;
{
if (section->sh_type == SHT_NOTE)
{
- res &= process_corefile_note_segment (file,
- (bfd_vma) section->sh_offset,
- (bfd_vma) section->sh_size);
+ res &= process_notes_at (file, section,
+ (bfd_vma) section->sh_offset,
+ (bfd_vma) section->sh_size);
n++;
}
return process_nds32_specific (file);
break;
case EM_PPC:
+ case EM_PPC64:
return process_power_specific (file);
break;
case EM_S390:
/* Determine how to read the rest of the header. */
switch (elf_header.e_ident[EI_DATA])
{
- default: /* fall through */
- case ELFDATANONE: /* fall through */
+ default:
+ case ELFDATANONE:
case ELFDATA2LSB:
byte_get = byte_get_little_endian;
byte_put = byte_put_little_endian;