/* readelf.c -- display contents of an ELF format file
- Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
Originally developed by Eric Youngdale <eric@andante.jic.com>
Modifications by Nick Clifton <nickc@redhat.com>
\f
/* The difference between readelf and objdump:
- Both programs are capabale of displaying the contents of ELF format files,
+ Both programs are capable of displaying the contents of ELF format files,
so why does the binutils project have two file dumpers ?
The reason is that objdump sees an ELF file through a BFD filter of the
if (psym->st_shndx < SHN_LORESERVE)
sec_index = psym->st_shndx;
- else if (psym->st_shndx > SHN_LORESERVE)
+ else if (psym->st_shndx > SHN_HIRESERVE)
sec_index = psym->st_shndx - (SHN_HIRESERVE + 1
- SHN_LORESERVE);
case EF_ARM_EABI_VER3:
strcat (buf, ", Version3 EABI");
+ break;
+
+ case EF_ARM_EABI_VER4:
+ strcat (buf, ", Version4 EABI");
while (e_flags)
{
unsigned flag;
decode_ARM_machine_flags (e_flags, buf);
break;
+ case EM_CYGNUS_FRV:
+ switch (e_flags & EF_FRV_CPU_MASK)
+ {
+ case EF_FRV_CPU_GENERIC:
+ break;
+
+ default:
+ strcat (buf, ", fr???");
+ break;
+
+ case EF_FRV_CPU_FR300:
+ strcat (buf, ", fr300");
+ break;
+
+ case EF_FRV_CPU_FR400:
+ strcat (buf, ", fr400");
+ break;
+ case EF_FRV_CPU_FR405:
+ strcat (buf, ", fr405");
+ break;
+
+ case EF_FRV_CPU_FR450:
+ strcat (buf, ", fr450");
+ break;
+
+ case EF_FRV_CPU_FR500:
+ strcat (buf, ", fr500");
+ break;
+ case EF_FRV_CPU_FR550:
+ strcat (buf, ", fr550");
+ break;
+
+ case EF_FRV_CPU_SIMPLE:
+ strcat (buf, ", simple");
+ break;
+ case EF_FRV_CPU_TOMCAT:
+ strcat (buf, ", tomcat");
+ break;
+ }
+ break;
+
case EM_68K:
if (e_flags & EF_CPU32)
strcat (buf, ", cpu32");
case EF_SH5: strcat (buf, ", sh5"); break;
case EF_SH2E: strcat (buf, ", sh2e"); break;
case EF_SH4A: strcat (buf, ", sh4a"); break;
+ case EF_SH2A: strcat (buf, ", sh2a"); break;
case EF_SH4_NOFPU: strcat (buf, ", sh4-nofpu"); break;
case EF_SH4A_NOFPU: strcat (buf, ", sh4a-nofpu"); break;
+ case EF_SH2A_NOFPU: strcat (buf, ", sh2a-nofpu"); break;
default: strcat (buf, ", unknown ISA"); break;
}
return NULL;
}
+static const char *
+get_x86_64_section_type_name (unsigned int sh_type)
+{
+ switch (sh_type)
+ {
+ case SHT_X86_64_UNWIND: return "X86_64_UNWIND";
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static const char *
+get_arm_section_type_name (unsigned int sh_type)
+{
+ switch (sh_type)
+ {
+ case SHT_ARM_EXIDX:
+ return "ARM_EXIDX";
+ default:
+ break;
+ }
+ return NULL;
+}
+
static const char *
get_section_type_name (unsigned int sh_type)
{
case EM_IA_64:
result = get_ia64_section_type_name (sh_type);
break;
+ case EM_X86_64:
+ result = get_x86_64_section_type_name (sh_type);
+ break;
+ case EM_ARM:
+ result = get_arm_section_type_name (sh_type);
+ break;
default:
result = NULL;
break;
<= segment->p_vaddr + segment->p_memsz)
: ((bfd_vma) section->sh_offset >= segment->p_offset
&& (section->sh_offset + section->sh_size
- <= segment->p_offset + segment->p_filesz))))
+ <= segment->p_offset + segment->p_filesz)))
+ /* .tbss is special. It doesn't contribute memory space
+ to normal segments. */
+ && (!((section->sh_flags & SHF_TLS) != 0
+ && section->sh_type == SHT_NOBITS)
+ || segment->p_type == PT_TLS))
printf ("%s ", SECTION_NAME (section));
}
group->root = g;
}
+ if (symtab)
+ free (symtab);
if (strtab)
free (strtab);
if (start)
printf ("DW_OP_const1u: %lu", (unsigned long) byte_get (data++, 1));
break;
case DW_OP_const1s:
- printf ("DW_OP_const1s: %ld", (long) byte_get (data++, 1));
+ printf ("DW_OP_const1s: %ld", (long) byte_get_signed (data++, 1));
break;
case DW_OP_const2u:
printf ("DW_OP_const2u: %lu", (unsigned long) byte_get (data, 2));
data += 2;
break;
case DW_OP_const2s:
- printf ("DW_OP_const2s: %ld", (long) byte_get (data, 2));
+ printf ("DW_OP_const2s: %ld", (long) byte_get_signed (data, 2));
data += 2;
break;
case DW_OP_const4u:
data += 4;
break;
case DW_OP_const4s:
- printf ("DW_OP_const4s: %ld", (long) byte_get (data, 4));
+ printf ("DW_OP_const4s: %ld", (long) byte_get_signed (data, 4));
data += 4;
break;
case DW_OP_const8u:
printf ("DW_OP_xor");
break;
case DW_OP_bra:
- printf ("DW_OP_bra: %ld", (long) byte_get (data, 2));
+ printf ("DW_OP_bra: %ld", (long) byte_get_signed (data, 2));
data += 2;
break;
case DW_OP_eq:
printf ("DW_OP_ne");
break;
case DW_OP_skip:
- printf ("DW_OP_skip: %ld", (long) byte_get (data, 2));
+ printf ("DW_OP_skip: %ld", (long) byte_get_signed (data, 2));
data += 2;
break;
return data;
}
+/* Apply addends of RELA relocations. */
+
+static int
+debug_apply_rela_addends (FILE *file,
+ Elf_Internal_Shdr *section,
+ int reloc_size,
+ unsigned char *sec_data,
+ unsigned char *start,
+ unsigned char *end)
+{
+ Elf_Internal_Shdr *relsec;
+
+ if (end - start < reloc_size)
+ return 1;
+
+ for (relsec = section_headers;
+ relsec < section_headers + elf_header.e_shnum;
+ ++relsec)
+ {
+ unsigned long nrelas;
+ Elf_Internal_Rela *rela, *rp;
+ Elf_Internal_Shdr *symsec;
+ Elf_Internal_Sym *symtab;
+ Elf_Internal_Sym *sym;
+
+ if (relsec->sh_type != SHT_RELA
+ || SECTION_HEADER (relsec->sh_info) != section
+ || relsec->sh_size == 0)
+ continue;
+
+ if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
+ &rela, &nrelas))
+ return 0;
+
+ symsec = SECTION_HEADER (relsec->sh_link);
+ symtab = GET_ELF_SYMBOLS (file, symsec);
+
+ for (rp = rela; rp < rela + nrelas; ++rp)
+ {
+ unsigned char *loc;
+
+ if (rp->r_offset >= (bfd_vma) (start - sec_data)
+ && rp->r_offset < (bfd_vma) (end - sec_data) - reloc_size)
+ loc = sec_data + rp->r_offset;
+ else
+ continue;
+
+ if (is_32bit_elf)
+ {
+ sym = symtab + ELF32_R_SYM (rp->r_info);
+
+ if (ELF32_R_SYM (rp->r_info) != 0
+ && ELF32_ST_TYPE (sym->st_info) != STT_SECTION)
+ {
+ warn (_("Skipping unexpected symbol type %u\n"),
+ ELF32_ST_TYPE (sym->st_info));
+ continue;
+ }
+ }
+ else
+ {
+ sym = symtab + ELF64_R_SYM (rp->r_info);
+
+ if (ELF64_R_SYM (rp->r_info) != 0
+ && ELF64_ST_TYPE (sym->st_info) != STT_SECTION)
+ {
+ warn (_("Skipping unexpected symbol type %u\n"),
+ ELF64_ST_TYPE (sym->st_info));
+ continue;
+ }
+ }
+
+ byte_put (loc, rp->r_addend, reloc_size);
+ }
+
+ free (symtab);
+ free (rela);
+ break;
+ }
+ return 1;
+}
+
static int
display_debug_info (Elf_Internal_Shdr *section,
unsigned char *start,
while (start < end)
{
DWARF2_Internal_CompUnit compunit;
- Elf_Internal_Shdr *relsec;
unsigned char *hdrptr;
unsigned char *cu_abbrev_offset_ptr;
unsigned char *tags;
compunit.cu_version = byte_get (hdrptr, 2);
hdrptr += 2;
- /* Apply addends of RELA relocations. */
- for (relsec = section_headers;
- relsec < section_headers + elf_header.e_shnum;
- ++relsec)
- {
- unsigned long nrelas;
- Elf_Internal_Rela *rela, *rp;
- Elf_Internal_Shdr *symsec;
- Elf_Internal_Sym *symtab;
- Elf_Internal_Sym *sym;
-
- if (relsec->sh_type != SHT_RELA
- || SECTION_HEADER (relsec->sh_info) != section
- || relsec->sh_size == 0)
- continue;
-
- if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
- & rela, & nrelas))
- return 0;
-
- symsec = SECTION_HEADER (relsec->sh_link);
- symtab = GET_ELF_SYMBOLS (file, symsec);
-
- for (rp = rela; rp < rela + nrelas; ++rp)
- {
- unsigned char *loc;
-
- if (rp->r_offset >= (bfd_vma) (hdrptr - section_begin)
- && section->sh_size > (bfd_vma) offset_size
- && rp->r_offset <= section->sh_size - offset_size)
- loc = section_begin + rp->r_offset;
- else
- continue;
-
- if (is_32bit_elf)
- {
- sym = symtab + ELF32_R_SYM (rp->r_info);
-
- if (ELF32_R_SYM (rp->r_info) != 0
- && ELF32_ST_TYPE (sym->st_info) != STT_SECTION)
- {
- warn (_("Skipping unexpected symbol type %u\n"),
- ELF32_ST_TYPE (sym->st_info));
- continue;
- }
- }
- else
- {
- sym = symtab + ELF64_R_SYM (rp->r_info);
-
- if (ELF64_R_SYM (rp->r_info) != 0
- && ELF64_ST_TYPE (sym->st_info) != STT_SECTION)
- {
- warn (_("Skipping unexpected symbol type %u\n"),
- ELF64_ST_TYPE (sym->st_info));
- continue;
- }
- }
-
- byte_put (loc, rp->r_addend, offset_size);
- }
+ cu_offset = start - section_begin;
+ start += compunit.cu_length + initial_length_size;
- free (rela);
- break;
- }
+ if (elf_header.e_type == ET_REL
+ && !debug_apply_rela_addends (file, section, offset_size,
+ section_begin, hdrptr, start))
+ return 0;
cu_abbrev_offset_ptr = hdrptr;
compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
hdrptr += 1;
tags = hdrptr;
- cu_offset = start - section_begin;
- start += compunit.cu_length + initial_length_size;
printf (_(" Compilation Unit @ %lx:\n"), cu_offset);
printf (_(" Length: %ld\n"), compunit.cu_length);
block_end = saved_start + length + initial_length_size;
cie_id = byte_get (start, offset_size); start += offset_size;
+ if (elf_header.e_type == ET_REL
+ && !debug_apply_rela_addends (file, section, offset_size,
+ section_start, start, block_end))
+ return 0;
+
if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
{
int version;
encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
fc->pc_begin = get_encoded_value (start, fc->fde_encoding);
- if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel)
+ if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
+ /* Don't adjust for ET_REL since there's invariably a pcrel
+ reloc here, which we haven't applied. */
+ && elf_header.e_type != ET_REL)
fc->pc_begin += section->sh_addr + (start - section_start);
start += encoded_ptr_size;
fc->pc_range = byte_get (start, encoded_ptr_size);
case DW_CFA_set_loc:
vma = get_encoded_value (start, fc->fde_encoding);
- if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel)
+ if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
+ && elf_header.e_type != ET_REL)
vma += section->sh_addr + (start - section_start);
start += encoded_ptr_size;
if (do_debug_frames_interp)