Fix computation of offsets in PT_LOAD sections.

This commit is contained in:
Nick Clifton 2003-06-26 12:46:17 +00:00
parent ed1653a7a6
commit d93f0186ba
2 changed files with 139 additions and 101 deletions

View file

@ -1,3 +1,19 @@
2003-06-26 Roland McGrath <roland@redhat.com>
* readelf.c (loadaddr): Variable removed.
(dynamic_info, version_info): Fix type long -> bfd_vma.
(program_headers): New variable.
(get_program_headers): New function, broken out of
process_program_headers.
(process_program_headers): Call it. Don't set `loadaddr'.
(slurp_ia64_unwind_table): Use get_program_headers.
(process_corefile_note_segments): Likewise.
(offset_from_vma): New function.
(process_relocs, process_dynamic_segment): Call that instead of
subtracting `loadaddr'.
(process_version_sections, process_symbol_table): Likewise.
(process_mips_specific): Likewise.
2003-06-26 Nick Clifton <nickc@redhat.com>
* objcopy (enum strip_action): Add STRIP_NONDEBUG.

View file

@ -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);