aboutsummaryrefslogtreecommitdiff
path: root/binutils/readelf.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2003-06-26 12:46:17 +0000
committerNick Clifton <nickc@redhat.com>2003-06-26 12:46:17 +0000
commitd93f0186ba5c2d134603dc0e001ce0c9fcb3465b (patch)
treeab5e30d430f0a1b9c6d266acaf9e7e3b76165e14 /binutils/readelf.c
parented1653a7a6e4a758fa05f05f7e5d5b3257b84a42 (diff)
downloadgdb-d93f0186ba5c2d134603dc0e001ce0c9fcb3465b.zip
gdb-d93f0186ba5c2d134603dc0e001ce0c9fcb3465b.tar.gz
gdb-d93f0186ba5c2d134603dc0e001ce0c9fcb3465b.tar.bz2
Fix computation of offsets in PT_LOAD sections.
Diffstat (limited to 'binutils/readelf.c')
-rw-r--r--binutils/readelf.c224
1 files changed, 123 insertions, 101 deletions
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 42dd18d..f5a8824 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -106,11 +106,11 @@ Elf_Internal_Syminfo *dynamic_syminfo;
unsigned long dynamic_syminfo_offset;
unsigned int dynamic_syminfo_nent;
char program_interpreter[64];
-long dynamic_info[DT_JMPREL + 1];
-long version_info[16];
-long loadaddr = 0;
+bfd_vma dynamic_info[DT_JMPREL + 1];
+bfd_vma version_info[16];
Elf_Internal_Ehdr elf_header;
Elf_Internal_Shdr *section_headers;
+Elf_Internal_Phdr *program_headers;
Elf_Internal_Dyn *dynamic_segment;
Elf_Internal_Shdr *symtab_shndx_hdr;
int show_name;
@@ -282,6 +282,8 @@ static int get_32bit_program_headers
PARAMS ((FILE *, Elf_Internal_Phdr *));
static int get_64bit_program_headers
PARAMS ((FILE *, Elf_Internal_Phdr *));
+static int get_program_headers
+ PARAMS ((FILE *));
static int get_file_header
PARAMS ((FILE *));
static Elf_Internal_Sym *get_32bit_elf_symbols
@@ -296,6 +298,8 @@ static int get_32bit_dynamic_segment
PARAMS ((FILE *));
static int get_64bit_dynamic_segment
PARAMS ((FILE *));
+static long offset_from_vma
+ PARAMS ((FILE *, bfd_vma vma, bfd_size_type size));
#ifdef SUPPORT_DISASSEMBLY
static int disassemble_section
PARAMS ((Elf_Internal_Shdr *, FILE *));
@@ -3179,13 +3183,45 @@ get_64bit_program_headers (file, program_headers)
return 1;
}
+/* Returns 1 if the program headers were read into `program_headers'. */
+
+static int
+get_program_headers (file)
+ FILE *file;
+{
+ Elf_Internal_Phdr *phdrs;
+
+ /* Check cache of prior read. */
+ if (program_headers != NULL)
+ return 1;
+
+ phdrs = (Elf_Internal_Phdr *) malloc
+ (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
+
+ if (phdrs == NULL)
+ {
+ error (_("Out of memory\n"));
+ return 0;
+ }
+
+ if (is_32bit_elf
+ ? get_32bit_program_headers (file, phdrs)
+ : get_64bit_program_headers (file, phdrs))
+ {
+ program_headers = phdrs;
+ return 1;
+ }
+
+ free (phdrs);
+ return 0;
+}
+
/* Returns 1 if the program headers were loaded. */
static int
process_program_headers (file)
FILE *file;
{
- Elf_Internal_Phdr *program_headers;
Elf_Internal_Phdr *segment;
unsigned int i;
@@ -3207,25 +3243,8 @@ process_program_headers (file)
printf ("\n");
}
- program_headers = (Elf_Internal_Phdr *) malloc
- (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
-
- if (program_headers == NULL)
- {
- error (_("Out of memory\n"));
+ if (! get_program_headers (file))
return 0;
- }
-
- if (is_32bit_elf)
- i = get_32bit_program_headers (file, program_headers);
- else
- i = get_64bit_program_headers (file, program_headers);
-
- if (i == 0)
- {
- free (program_headers);
- return 0;
- }
if (do_segments)
{
@@ -3249,7 +3268,6 @@ process_program_headers (file)
}
}
- loadaddr = -1;
dynamic_addr = 0;
dynamic_size = 0;
@@ -3337,18 +3355,6 @@ process_program_headers (file)
switch (segment->p_type)
{
- case PT_LOAD:
- if (loadaddr == -1)
- {
- unsigned long align_mask = -segment->p_align;
-
- if (align_mask == 0)
- --align_mask;
- loadaddr = ((segment->p_vaddr & align_mask)
- - (segment->p_offset & align_mask));
- }
- break;
-
case PT_DYNAMIC:
if (dynamic_addr)
error (_("more than one dynamic segment\n"));
@@ -3376,12 +3382,6 @@ process_program_headers (file)
putc ('\n', stdout);
}
- if (loadaddr == -1)
- {
- /* Very strange. */
- loadaddr = 0;
- }
-
if (do_segments && section_headers != NULL)
{
printf (_("\n Section to Segment mapping:\n"));
@@ -3418,12 +3418,44 @@ process_program_headers (file)
}
}
- free (program_headers);
-
return 1;
}
+/* Find the file offset corresponding to VMA by using the program headers. */
+
+static long
+offset_from_vma (file, vma, size)
+ FILE *file;
+ bfd_vma vma;
+ bfd_size_type size;
+{
+ Elf_Internal_Phdr *seg;
+
+ if (! get_program_headers (file))
+ {
+ warn (_("Cannot interpret virtual addresses without program headers.\n"));
+ return (long) vma;
+ }
+
+ for (seg = program_headers;
+ seg < program_headers + elf_header.e_phnum;
+ ++seg)
+ {
+ if (seg->p_type != PT_LOAD)
+ continue;
+
+ if (vma >= (seg->p_vaddr & -seg->p_align)
+ && vma + size <= seg->p_vaddr + seg->p_filesz)
+ return vma - seg->p_vaddr + seg->p_offset;
+ }
+
+ warn (_("Virtual address 0x%lx not located in any PT_LOAD segment.\n"),
+ (long) vma);
+ return (long) vma;
+}
+
+
static int
get_32bit_section_headers (file, num)
FILE *file;
@@ -3996,7 +4028,9 @@ process_relocs (file)
(_("\n'%s' relocation section at offset 0x%lx contains %ld bytes:\n"),
name, rel_offset, rel_size);
- dump_relocations (file, rel_offset - loadaddr, rel_size,
+ dump_relocations (file,
+ offset_from_vma (file, rel_offset, rel_size),
+ rel_size,
dynamic_symbols, num_dynamic_syms,
dynamic_strings, is_rela);
}
@@ -4222,14 +4256,13 @@ slurp_ia64_unwind_table (file, aux, sec)
Elf_Internal_Shdr *sec;
{
unsigned long size, addr_size, nrelas, i;
- Elf_Internal_Phdr *prog_hdrs, *seg;
+ Elf_Internal_Phdr *seg;
struct unw_table_entry *tep;
Elf_Internal_Shdr *relsec;
Elf_Internal_Rela *rela, *rp;
unsigned char *table, *tp;
Elf_Internal_Sym *sym;
const char *relname;
- int result;
addr_size = is_32bit_elf ? 4 : 8;
@@ -4238,21 +4271,12 @@ slurp_ia64_unwind_table (file, aux, sec)
if (elf_header.e_phnum)
{
- prog_hdrs = (Elf_Internal_Phdr *)
- xmalloc (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
-
- if (is_32bit_elf)
- result = get_32bit_program_headers (file, prog_hdrs);
- else
- result = get_64bit_program_headers (file, prog_hdrs);
-
- if (!result)
- {
- free (prog_hdrs);
+ if (! get_program_headers (file))
return 0;
- }
- for (seg = prog_hdrs; seg < prog_hdrs + elf_header.e_phnum; ++seg)
+ for (seg = program_headers;
+ seg < program_headers + elf_header.e_phnum;
+ ++seg)
{
if (seg->p_type != PT_LOAD)
continue;
@@ -4264,8 +4288,6 @@ slurp_ia64_unwind_table (file, aux, sec)
break;
}
}
-
- free (prog_hdrs);
}
/* Second, build the unwind table from the contents of the unwind section: */
@@ -4818,7 +4840,7 @@ process_dynamic_segment (file)
we default to reading in the entire file (!) and
processing that. This is overkill, I know, but it
should work. */
- section.sh_offset = entry->d_un.d_val - loadaddr;
+ section.sh_offset = offset_from_vma (file, entry->d_un.d_val, 0);
if (fseek (file, 0, SEEK_END))
error (_("Unable to seek to end of file!"));
@@ -4860,7 +4882,7 @@ process_dynamic_segment (file)
processing that. This is overkill, I know, but it
should work. */
- offset = entry->d_un.d_val - loadaddr;
+ offset = offset_from_vma (file, entry->d_un.d_val, 0);
if (fseek (file, 0, SEEK_END))
error (_("Unable to seek to end of file\n"));
str_tab_len = ftell (file) - offset;
@@ -4896,7 +4918,8 @@ process_dynamic_segment (file)
else if (entry->d_tag == DT_SYMINSZ)
syminsz = entry->d_un.d_val;
else if (entry->d_tag == DT_SYMINFO)
- dynamic_syminfo_offset = entry->d_un.d_val - loadaddr;
+ dynamic_syminfo_offset = offset_from_vma (file, entry->d_un.d_val,
+ syminsz);
}
if (dynamic_syminfo_offset != 0 && syminsz != 0)
@@ -5585,7 +5608,9 @@ process_version_sections (file)
edata =
((unsigned char *)
get_data (NULL, file,
- version_info[DT_VERSIONTAGIDX (DT_VERSYM)] - loadaddr,
+ offset_from_vma
+ (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
+ total * sizeof (short)),
total * sizeof (short), _("version symbol data")));
if (!edata)
{
@@ -5641,8 +5666,9 @@ process_version_sections (file)
Elf_Internal_Verneed ivn;
unsigned long offset;
- offset = version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
- - loadaddr;
+ offset = offset_from_vma
+ (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
+ sizeof (Elf_External_Verneed));
do
{
@@ -5697,8 +5723,9 @@ process_version_sections (file)
Elf_External_Verdef evd;
unsigned long offset;
- offset = (version_info[DT_VERSIONTAGIDX (DT_VERDEF)]
- - loadaddr);
+ offset = offset_from_vma
+ (file, version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
+ sizeof evd);
do
{
@@ -5925,7 +5952,9 @@ process_symbol_table (file)
if (dynamic_info[DT_HASH] && ((do_using_dynamic && dynamic_strings != NULL)
|| do_histogram))
{
- if (fseek (file, dynamic_info[DT_HASH] - loadaddr, SEEK_SET))
+ if (fseek (file, offset_from_vma (file, dynamic_info[DT_HASH],
+ sizeof nb + sizeof nc),
+ SEEK_SET))
{
error (_("Unable to seek to start of dynamic information"));
return 0;
@@ -6056,8 +6085,9 @@ process_symbol_table (file)
int is_nobits;
int check_def;
- offset = version_info[DT_VERSIONTAGIDX (DT_VERSYM)]
- - loadaddr;
+ offset = offset_from_vma
+ (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
+ sizeof data + si * sizeof (vers_data));
get_data (&data, file, offset + si * sizeof (vers_data),
sizeof (data), _("version data"));
@@ -6079,8 +6109,9 @@ process_symbol_table (file)
Elf_Internal_Vernaux ivna;
/* We must test both. */
- offset = (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
- - loadaddr);
+ offset = offset_from_vma
+ (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
+ sizeof evn);
do
{
@@ -6140,9 +6171,10 @@ process_symbol_table (file)
Elf_External_Verdaux evda;
unsigned long offset;
- offset
- = (version_info[DT_VERSIONTAGIDX (DT_VERDEF)]
- - loadaddr);
+ offset = offset_from_vma
+ (file,
+ version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
+ sizeof (Elf_External_Verdef));
do
{
@@ -9733,16 +9765,20 @@ process_mips_specific (file)
switch (entry->d_tag)
{
case DT_MIPS_LIBLIST:
- liblist_offset = entry->d_un.d_val - loadaddr;
+ liblist_offset
+ = offset_from_vma (file, entry->d_un.d_val,
+ liblistno * sizeof (Elf32_External_Lib));
break;
case DT_MIPS_LIBLISTNO:
liblistno = entry->d_un.d_val;
break;
case DT_MIPS_OPTIONS:
- options_offset = entry->d_un.d_val - loadaddr;
+ options_offset = offset_from_vma (file, entry->d_un.d_val, 0);
break;
case DT_MIPS_CONFLICT:
- conflicts_offset = entry->d_un.d_val - loadaddr;
+ conflicts_offset
+ = offset_from_vma (file, entry->d_un.d_val,
+ conflictsno * sizeof (Elf32_External_Conflict));
break;
case DT_MIPS_CONFLICTNO:
conflictsno = entry->d_un.d_val;
@@ -10394,30 +10430,12 @@ static int
process_corefile_note_segments (file)
FILE *file;
{
- Elf_Internal_Phdr *program_headers;
Elf_Internal_Phdr *segment;
unsigned int i;
int res = 1;
- program_headers = (Elf_Internal_Phdr *) malloc
- (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
-
- if (program_headers == NULL)
- {
- error (_("Out of memory\n"));
+ if (! get_program_headers (file))
return 0;
- }
-
- if (is_32bit_elf)
- i = get_32bit_program_headers (file, program_headers);
- else
- i = get_64bit_program_headers (file, program_headers);
-
- if (i == 0)
- {
- free (program_headers);
- return 0;
- }
for (i = 0, segment = program_headers;
i < elf_header.e_phnum;
@@ -10429,8 +10447,6 @@ process_corefile_note_segments (file)
(bfd_vma) segment->p_filesz);
}
- free (program_headers);
-
return res;
}
@@ -10647,6 +10663,12 @@ process_file (file_name)
fclose (file);
+ if (program_headers)
+ {
+ free (program_headers);
+ program_headers = NULL;
+ }
+
if (section_headers)
{
free (section_headers);