* dwarf.c (process_debug_info): Check for corrupt lengths.

* readelf.c (get_reloc_type): New function.  Returns the reloc number extracted from the info field of a reloc.
  (get_reloc_symindex): New function.  Returns the symbol index
  (extracted from the info field of a reloc.
  (dump_relocations): Use the new functions.
  (slurp_ia64_unwind_table): Use the new functions.
  (slurp_hppa_unwind_table): Use the new functions.
  (dump_section_as_bytes): Use the new functions.
  (get_reloc_size): Delete function.
  (is_32bit_abs_reloc): New function.  Determines if a given reloc type is a 32-bit absolute relocation.
  (is_32bit_pcrel_reloc): New function.  Like is_32bit_abs_reloc but for pc-relative relocations.
  (is_64bit_abs_reloc): New function.  Like is_32bit_abs_reloc but for 64-bit absolute relocations.
  (is_16bit_abs_reloc): New function.  Like is_32bit_abs_reloc but for 32-bit absolute relocations.
  (debug_apply_rela_addends): Use the new functions.  Skip and warn about any unrecognised relocations.
This commit is contained in:
Nick Clifton 2007-10-28 14:00:20 +00:00
parent be55061650
commit aca885677a
3 changed files with 338 additions and 141 deletions

View File

@ -1,3 +1,26 @@
2007-10-28 Nick Clifton <nickc@redhat.com>
* dwarf.c (process_debug_info): Check for corrupt lengths.
* readelf.c (get_reloc_type): New function. Returns the reloc
number extracted from the info field of a reloc.
(get_reloc_symindex): New function. Returns the symbol index
extracted from the info field of a reloc.
(dump_relocations): Use the new functions.
(slurp_ia64_unwind_table): Use the new functions.
(slurp_hppa_unwind_table): Use the new functions.
(dump_section_as_bytes): Use the new functions.
(get_reloc_size): Delete function.
(is_32bit_abs_reloc): New function. Determines if a given reloc
type is a 32-bit absolute relocation.
(is_32bit_pcrel_reloc): New function. Like is_32bit_abs_reloc but
for pc-relative relocations.
(is_64bit_abs_reloc): New function. Like is_32bit_abs_reloc but
for 64-bit absolute relocations.
(is_16bit_abs_reloc): New function. Like is_32bit_abs_reloc but
for 32-bit absolute relocations.
(debug_apply_rela_addends): Use the new functions. Skip and warn
about any unrecognised relocations.
2007-10-26 Karl Berry <karl@freefriends.org>
* doc/binutils.texi: Move top stuff to the top.

View File

@ -1551,6 +1551,15 @@ process_debug_info (struct dwarf_section *section, void *file,
}
else
section_begin += length + 4;
/* Negative values are illegal, they may even cause infinite
looping. This can happen if we can't accurately apply
relocations to an object file. */
if ((signed long) length <= 0)
{
warn (_("Corrupt unit length (%lx) found in section %s\n"), length, section->name);
return 0;
}
}
if (num_units == 0)

View File

@ -846,6 +846,36 @@ slurp_rel_relocs (FILE *file,
return 1;
}
/* Returns the reloc type extracted from the reloc info field. */
static unsigned int
get_reloc_type (bfd_vma reloc_info)
{
if (is_32bit_elf)
return ELF32_R_TYPE (reloc_info);
switch (elf_header.e_machine)
{
case EM_MIPS:
/* Note: We assume that reloc_info has already been adjusted for us. */
return ELF64_MIPS_R_TYPE (reloc_info);
case EM_SPARCV9:
return ELF64_R_TYPE_ID (reloc_info);
default:
return ELF64_R_TYPE (reloc_info);
}
}
/* Return the symbol index extracted from the reloc info field. */
static bfd_vma
get_reloc_symindex (bfd_vma reloc_info)
{
return is_32bit_elf ? ELF32_R_SYM (reloc_info) : ELF64_R_SYM (reloc_info);
}
/* Display the contents of the relocation data found at the specified
offset. */
@ -915,53 +945,36 @@ dump_relocations (FILE *file,
for (i = 0; i < rel_size; i++)
{
const char *rtype;
const char *rtype2 = NULL;
const char *rtype3 = NULL;
bfd_vma offset;
bfd_vma info;
bfd_vma symtab_index;
bfd_vma type;
bfd_vma type2 = 0;
bfd_vma type3 = 0;
offset = rels[i].r_offset;
info = rels[i].r_info;
if (is_32bit_elf)
{
type = ELF32_R_TYPE (info);
symtab_index = ELF32_R_SYM (info);
}
else
{
/* The #ifdef BFD64 below is to prevent a compile time warning.
We know that if we do not have a 64 bit data type that we
will never execute this code anyway. */
/* The #ifdef BFD64 below is to prevent a compile time warning.
We know that if we do not have a 64 bit data type that we
will never execute this code anyway. */
#ifdef BFD64
if (elf_header.e_machine == EM_MIPS)
{
/* In little-endian objects, r_info isn't really a 64-bit
little-endian value: it has a 32-bit little-endian
symbol index followed by four individual byte fields.
Reorder INFO accordingly. */
if (elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
info = (((info & 0xffffffff) << 32)
| ((info >> 56) & 0xff)
| ((info >> 40) & 0xff00)
| ((info >> 24) & 0xff0000)
| ((info >> 8) & 0xff000000));
type = ELF64_MIPS_R_TYPE (info);
type2 = ELF64_MIPS_R_TYPE2 (info);
type3 = ELF64_MIPS_R_TYPE3 (info);
}
else if (elf_header.e_machine == EM_SPARCV9)
type = ELF64_R_TYPE_ID (info);
else
type = ELF64_R_TYPE (info);
symtab_index = ELF64_R_SYM (info);
#endif
if (!is_32bit_elf
&& elf_header.e_machine == EM_MIPS
&& elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
{
/* In little-endian objects, r_info isn't really a 64-bit
little-endian value: it has a 32-bit little-endian
symbol index followed by four individual byte fields.
Reorder INFO accordingly. */
info = (((info & 0xffffffff) << 32)
| ((info >> 56) & 0xff)
| ((info >> 40) & 0xff00)
| ((info >> 24) & 0xff0000)
| ((info >> 8) & 0xff000000));
}
#endif /* BFD64 */
type = get_reloc_type (info);
symtab_index = get_reloc_symindex (info);
if (is_32bit_elf)
{
@ -1103,11 +1116,6 @@ dump_relocations (FILE *file,
case EM_MIPS:
case EM_MIPS_RS3_LE:
rtype = elf_mips_reloc_type (type);
if (!is_32bit_elf)
{
rtype2 = elf_mips_reloc_type (type2);
rtype3 = elf_mips_reloc_type (type3);
}
break;
case EM_ALPHA:
@ -1329,8 +1337,14 @@ dump_relocations (FILE *file,
putchar ('\n');
#ifdef BFD64
if (! is_32bit_elf && elf_header.e_machine == EM_MIPS)
{
bfd_vma type2 = ELF64_MIPS_R_TYPE2 (info);
bfd_vma type3 = ELF64_MIPS_R_TYPE3 (info);
const char *rtype2 = elf_mips_reloc_type (type2);
const char *rtype3 = elf_mips_reloc_type (type3);
printf (" Type2: ");
if (rtype2 == NULL)
@ -1349,6 +1363,7 @@ dump_relocations (FILE *file,
putchar ('\n');
}
#endif /* BFD64 */
}
free (rels);
@ -5036,16 +5051,8 @@ slurp_ia64_unwind_table (FILE *file,
for (rp = rela; rp < rela + nrelas; ++rp)
{
if (is_32bit_elf)
{
relname = elf_ia64_reloc_type (ELF32_R_TYPE (rp->r_info));
sym = aux->symtab + ELF32_R_SYM (rp->r_info);
}
else
{
relname = elf_ia64_reloc_type (ELF64_R_TYPE (rp->r_info));
sym = aux->symtab + ELF64_R_SYM (rp->r_info);
}
relname = elf_ia64_reloc_type (get_reloc_type (rp->r_info));
sym = aux->symtab + get_reloc_symindex (rp->r_info);
if (! const_strneq (relname, "R_IA64_SEGREL"))
{
@ -5448,16 +5455,8 @@ slurp_hppa_unwind_table (FILE *file,
for (rp = rela; rp < rela + nrelas; ++rp)
{
if (is_32bit_elf)
{
relname = elf_hppa_reloc_type (ELF32_R_TYPE (rp->r_info));
sym = aux->symtab + ELF32_R_SYM (rp->r_info);
}
else
{
relname = elf_hppa_reloc_type (ELF64_R_TYPE (rp->r_info));
sym = aux->symtab + ELF64_R_SYM (rp->r_info);
}
relname = elf_hppa_reloc_type (get_reloc_type (rp->r_info));
sym = aux->symtab + get_reloc_symindex (rp->r_info);
/* R_PARISC_SEGREL32 or R_PARISC_SEGREL64. */
if (! const_strneq (relname, "R_PARISC_SEGREL"))
@ -7931,40 +7930,210 @@ dump_section_as_bytes (Elf_Internal_Shdr *section, FILE *file)
return 1;
}
/* Return the number of bytes affected by a given reloc.
This information is architecture and reloc dependent.
Returns 4 by default, although this is not always correct.
It should return 0 if a decision cannot be made.
FIXME: This is not the correct way to solve this problem.
The proper way is to have target specific reloc sizing functions
created by the reloc-macros.h header, in the same way that it
already creates the reloc naming functions. */
/* Returns TRUE iff RELOC_TYPE is a 32-bit absolute RELA relocation used in
DWARF debug sections. This is a target specific test. Note - we do not
go through the whole including-target-headers-multiple-times route, (as
we have already done with <elf/h8.h>) because this would become very
messy and even then this function would have to contain target specific
information (the names of the relocs instead of their numeric values).
FIXME: This is not the correct way to solve this problem. The proper way
is to have target specific reloc sizing and typing functions created by
the reloc-macros.h header, in the same way that it already creates the
reloc naming functions. */
static unsigned int
get_reloc_size (Elf_Internal_Rela * reloc)
static bfd_boolean
is_32bit_abs_reloc (unsigned int reloc_type)
{
switch (elf_header.e_machine)
{
case EM_68K:
return reloc_type == 1; /* R_68K_32. */
case EM_860:
return reloc_type == 1; /* R_860_32. */
case EM_ALPHA:
return reloc_type == 1; /* XXX Is this right ? */
case EM_AVR_OLD:
case EM_AVR:
return reloc_type == 1;
case EM_BLACKFIN:
return reloc_type == 0x12; /* R_byte4_data. */
case EM_CRIS:
return reloc_type == 3; /* R_CRIS_32. */
case EM_CR16:
return reloc_type == 3; /* R_CR16_NUM32. */
case EM_CRX:
return reloc_type == 15; /* R_CRX_NUM32. */
case EM_CYGNUS_FRV:
return reloc_type == 1;
case EM_CYGNUS_D30V:
case EM_D30V:
return reloc_type == 12; /* R_D30V_32_NORMAL. */
case EM_CYGNUS_FR30:
case EM_FR30:
return reloc_type == 3; /* R_FR30_32. */
case EM_H8S:
case EM_H8_300:
case EM_H8_300H:
case EM_H8_500:
switch (ELF32_R_TYPE (reloc->r_info))
{
/* PR gas/3800 - without this information we do not correctly
decode the debug information generated by the h8300 assembler. */
case R_H8_DIR16:
return 2;
default:
return 4;
}
return reloc_type == 1; /* R_H8_DIR32. */
case EM_IP2K_OLD:
case EM_IP2K:
return reloc_type == 2; /* R_IP2K_32. */
case EM_IQ2000:
return reloc_type == 2; /* R_IQ2000_32. */
case EM_M32C:
return reloc_type == 3; /* R_M32C_32. */
case EM_M32R:
return reloc_type == 34; /* R_M32R_32_RELA. */
case EM_MCORE:
return reloc_type == 1; /* R_MCORE_ADDR32. */
case EM_CYGNUS_MEP:
return reloc_type == 4; /* R_MEP_32. */
case EM_MIPS:
return reloc_type == 2; /* R_MIPS_32. */
case EM_MMIX:
return reloc_type == 4; /* R_MMIX_32. */
case EM_CYGNUS_MN10200:
case EM_MN10200:
return reloc_type == 1; /* R_MN10200_32. */
case EM_CYGNUS_MN10300:
case EM_MN10300:
return reloc_type == 1; /* R_MN10300_32. */
case EM_MSP430_OLD:
case EM_MSP430:
return reloc_type == 1; /* R_MSP43_32. */
case EM_MT:
return reloc_type == 2; /* R_MT_32. */
case EM_PARISC:
return reloc_type == 1; /* R_PARISC_DIR32. */
case EM_PJ:
case EM_PJ_OLD:
return reloc_type == 1; /* R_PJ_DATA_DIR32. */
case EM_PPC64:
return reloc_type == 1; /* R_PPC64_ADDR32. */
case EM_PPC:
return reloc_type == 1; /* R_PPC_ADDR32. */
case EM_S370:
return reloc_type == 1; /* R_I370_ADDR31. */
case EM_S390_OLD:
case EM_S390:
return reloc_type == 4; /* R_S390_32. */
case EM_SH:
return reloc_type == 1; /* R_SH_DIR32. */
case EM_SPARC32PLUS:
case EM_SPARCV9:
case EM_SPARC:
return reloc_type == 3 /* R_SPARC_32. */
|| reloc_type == 23; /* R_SPARC_UA32. */
case EM_CYGNUS_V850:
case EM_V850:
return reloc_type == 6; /* R_V850_ABS32. */
case EM_VAX:
return reloc_type == 1; /* R_VAX_32. */
case EM_X86_64:
return reloc_type == 10; /* R_X86_64_32. */
case EM_XSTORMY16:
return reloc_type == 1; /* R_XSTROMY16_32. */
case EM_XTENSA_OLD:
case EM_XTENSA:
return reloc_type == 1; /* R_XTENSA_32. */
case EM_ALTERA_NIOS2:
/* Fall through (what reloc type is used ?). */
case EM_NIOS32:
case EM_IA_64:
/* Fall through (what reloc type is used ?). */
default:
/* FIXME: We need to extend this switch statement to cope with other
architecture's relocs. (When those relocs are used against debug
sections, and when their size is not 4). But see the multiple
inclusions of <elf/h8.h> for an example of the hoops that we need
to jump through in order to obtain the reloc numbers. */
return 4;
error (_("Missing knowledge of 32-bit reloc types used in DWARF sections of machine number %d\n"),
elf_header.e_machine);
abort ();
}
}
/* Like is_32bit_abs_reloc except that it returns TRUE iff RELOC_TYPE is
a 32-bit pc-relative RELA relocation used in DWARF debug sections. */
static bfd_boolean
is_32bit_pcrel_reloc (unsigned int reloc_type)
{
switch (elf_header.e_machine)
{
case EM_68K:
return reloc_type == 4; /* R_68K_PC32. */
case EM_ALPHA:
return reloc_type == 10; /* R_ALPHA_SREL32. */
case EM_PARISC:
return reloc_type == 0; /* R_PARISC_NONE. *//* FIXME: This reloc is generated, but it may be a bug. */
case EM_PPC:
return reloc_type == 26; /* R_PPC_REL32. */
case EM_PPC64:
return reloc_type == 26; /* R_PPC64_REL32. */
case EM_S390_OLD:
case EM_S390:
return reloc_type == 5; /* R_390_PC32. */
case EM_SH:
return reloc_type == 2; /* R_SH_REL32. */
case EM_SPARC32PLUS:
case EM_SPARCV9:
case EM_SPARC:
return reloc_type == 6; /* R_SPARC_DISP32. */
case EM_X86_64:
return reloc_type == 2; /* R_X86_64_PC32. */
default:
/* Do not abort or issue an error message here. Not all targets use
pc-relative 32-bit relocs in their DWARF debug information and we
have already tested for target coverage in is_32bit_abs_reloc. A
more helpful warning message will be generated by debug_apply_rela_addends
anyway, so just return. */
return FALSE;
}
}
/* Like is_32bit_abs_reloc except that it returns TRUE iff RELOC_TYPE is
a 64-bit absolute RELA relocation used in DWARF debug sections. */
static bfd_boolean
is_64bit_abs_reloc (unsigned int reloc_type)
{
switch (elf_header.e_machine)
{
case EM_ALPHA:
return reloc_type == 2; /* R_ALPHA_REFQUAD. */
case EM_PPC64:
return reloc_type == 38; /* R_PPC64_ADDR64. */
case EM_SPARC32PLUS:
case EM_SPARCV9:
case EM_SPARC:
return reloc_type == 54; /* R_SPARC_UA64. */
case EM_X86_64:
return reloc_type == 1; /* R_X86_64_64. */
default:
return FALSE;
}
}
/* Like is_32bit_abs_reloc except that it returns TRUE iff RELOC_TYPE is
a 16-bit absolute RELA relocation used in DWARF debug sections. */
static bfd_boolean
is_16bit_abs_reloc (unsigned int reloc_type)
{
switch (elf_header.e_machine)
{
case EM_AVR_OLD:
case EM_AVR:
return reloc_type == 4; /* R_AVR_16. */
case EM_H8S:
case EM_H8_300:
case EM_H8_300H:
return reloc_type == R_H8_DIR16;
case EM_IP2K_OLD:
case EM_IP2K:
return reloc_type == 1; /* R_IP2K_16. */
case EM_MSP430_OLD:
case EM_MSP430:
return reloc_type == 5; /* R_MSP430_16_BYTE. */
default:
return FALSE;
}
}
@ -8011,15 +8180,36 @@ debug_apply_rela_addends (void *file,
for (rp = rela; rp < rela + nrelas; ++rp)
{
unsigned char *loc;
unsigned int reloc_type;
unsigned int reloc_size;
unsigned char *loc;
reloc_size = get_reloc_size (rp);
if (reloc_size == 0)
/* In MIPS little-endian objects, r_info isn't really a
64-bit little-endian value: it has a 32-bit little-endian
symbol index followed by four individual byte fields.
Reorder INFO accordingly. */
if (!is_32bit_elf
&& elf_header.e_machine == EM_MIPS
&& elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
rp->r_info = (((rp->r_info & 0xffffffff) << 32)
| ((rp->r_info >> 56) & 0xff)
| ((rp->r_info >> 40) & 0xff00)
| ((rp->r_info >> 24) & 0xff0000)
| ((rp->r_info >> 8) & 0xff000000));
sym = symtab + get_reloc_symindex (rp->r_info);
reloc_type = get_reloc_type (rp->r_info);
if (is_32bit_abs_reloc (reloc_type)
|| is_32bit_pcrel_reloc (reloc_type))
reloc_size = 4;
else if (is_64bit_abs_reloc (reloc_type))
reloc_size = 8;
else if (is_16bit_abs_reloc (reloc_type))
reloc_size = 2;
else
{
warn (_("skipping relocation of unknown size against offset 0x%lx in section %s\n"),
(unsigned long) rp->r_offset,
SECTION_NAME (section));
warn (_("skipping unsupported reloc type %d in section .rela%s\n"),
reloc_type, SECTION_NAME (section));
continue;
}
@ -8032,56 +8222,31 @@ debug_apply_rela_addends (void *file,
continue;
}
if (is_32bit_elf)
if (sym != symtab
&& ELF_ST_TYPE (sym->st_info) != STT_SECTION
/* Relocations against symbols without type can happen.
Gcc -feliminate-dwarf2-dups may generate symbols
without type for debug info. */
&& ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
/* Relocations against object symbols can happen,
eg when referencing a global array. For an
example of this see the _clz.o binary in libgcc.a. */
&& ELF_ST_TYPE (sym->st_info) != STT_OBJECT)
{
sym = symtab + ELF32_R_SYM (rp->r_info);
if (ELF32_R_SYM (rp->r_info) != 0
&& ELF32_ST_TYPE (sym->st_info) != STT_SECTION
/* Relocations against symbols without type can happen.
Gcc -feliminate-dwarf2-dups may generate symbols
without type for debug info. */
&& ELF32_ST_TYPE (sym->st_info) != STT_NOTYPE
/* Relocations against object symbols can happen,
eg when referencing a global array. For an
example of this see the _clz.o binary in libgcc.a. */
&& ELF32_ST_TYPE (sym->st_info) != STT_OBJECT)
{
warn (_("skipping unexpected symbol type %s in relocation in section .rela%s\n"),
get_symbol_type (ELF32_ST_TYPE (sym->st_info)),
SECTION_NAME (section));
continue;
}
warn (_("skipping unexpected symbol type %s in relocation in section .rela%s\n"),
get_symbol_type (ELF_ST_TYPE (sym->st_info)),
SECTION_NAME (section));
continue;
}
if (is_32bit_pcrel_reloc (reloc_type))
/* FIXME: Not sure how to apply a pc-rel reloc yet.
I think that it ought to be:
(rp->r_addend + sym->st_value) - rp->r_offset
but this breaks GAS CFI tests... */
byte_put (loc, (rp->r_addend + sym->st_value) /*- rp->r_offset*/, reloc_size);
else
{
/* In MIPS little-endian objects, r_info isn't really a
64-bit little-endian value: it has a 32-bit little-endian
symbol index followed by four individual byte fields.
Reorder INFO accordingly. */
if (elf_header.e_machine == EM_MIPS
&& elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
rp->r_info = (((rp->r_info & 0xffffffff) << 32)
| ((rp->r_info >> 56) & 0xff)
| ((rp->r_info >> 40) & 0xff00)
| ((rp->r_info >> 24) & 0xff0000)
| ((rp->r_info >> 8) & 0xff000000));
sym = symtab + ELF64_R_SYM (rp->r_info);
if (ELF64_R_SYM (rp->r_info) != 0
&& ELF64_ST_TYPE (sym->st_info) != STT_SECTION
&& ELF64_ST_TYPE (sym->st_info) != STT_NOTYPE
&& ELF64_ST_TYPE (sym->st_info) != STT_OBJECT)
{
warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"),
get_symbol_type (ELF64_ST_TYPE (sym->st_info)),
SECTION_NAME (section));
continue;
}
}
byte_put (loc, rp->r_addend, reloc_size);
byte_put (loc, rp->r_addend + sym->st_value, reloc_size);
}
free (symtab);