mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-09 04:21:49 +08:00
Correct reading of .dynamic section.
(dynamic_section): Now a global variable. (process_mips_fpe_exception, process_mips_specific, process_arch_specific): New functions. (get_file_header): Call process_arch_specific.
This commit is contained in:
parent
5821de310f
commit
6c4b8d0f36
@ -1,3 +1,11 @@
|
|||||||
|
1998-07-20 07:14 Ulrich Drepper <drepper@cygnus.com>
|
||||||
|
|
||||||
|
* readelf.c: Correct reading of .dynamic section.
|
||||||
|
(dynamic_section): Now a global variable.
|
||||||
|
(process_mips_fpe_exception, process_mips_specific,
|
||||||
|
process_arch_specific): New functions.
|
||||||
|
(get_file_header): Call process_arch_specific.
|
||||||
|
|
||||||
1998-07-19 15:15 Ulrich Drepper <drepper@cygnus.com>
|
1998-07-19 15:15 Ulrich Drepper <drepper@cygnus.com>
|
||||||
|
|
||||||
* readelf.c: Fix several versioning related bugs. Produce nicer
|
* readelf.c: Fix several versioning related bugs. Produce nicer
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "bfd.h"
|
#include "bfd.h"
|
||||||
#include "elf/common.h"
|
#include "elf/common.h"
|
||||||
@ -55,8 +56,9 @@ char program_interpreter [64];
|
|||||||
int dynamic_info [DT_JMPREL + 1];
|
int dynamic_info [DT_JMPREL + 1];
|
||||||
int version_info [16];
|
int version_info [16];
|
||||||
int loadaddr = 0;
|
int loadaddr = 0;
|
||||||
Elf_Internal_Ehdr elf_header;
|
Elf_Internal_Ehdr elf_header;
|
||||||
Elf_Internal_Shdr * section_headers;
|
Elf_Internal_Shdr * section_headers;
|
||||||
|
Elf_Internal_Dyn * dynamic_segment;
|
||||||
int show_name;
|
int show_name;
|
||||||
int do_dynamic;
|
int do_dynamic;
|
||||||
int do_syms;
|
int do_syms;
|
||||||
@ -123,6 +125,8 @@ static Elf_Internal_Sym * get_elf_symbols
|
|||||||
PARAMS ((FILE * file, unsigned long offset, unsigned long number));
|
PARAMS ((FILE * file, unsigned long offset, unsigned long number));
|
||||||
static int * get_dynamic_data PARAMS ((FILE * file, unsigned int number));
|
static int * get_dynamic_data PARAMS ((FILE * file, unsigned int number));
|
||||||
|
|
||||||
|
typedef int Elf32_Word;
|
||||||
|
|
||||||
#define SECTION_NAME(X) (string_table + (X)->sh_name)
|
#define SECTION_NAME(X) (string_table + (X)->sh_name)
|
||||||
|
|
||||||
#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
|
#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
|
||||||
@ -1904,7 +1908,6 @@ static int
|
|||||||
process_dynamic_segment (file)
|
process_dynamic_segment (file)
|
||||||
FILE * file;
|
FILE * file;
|
||||||
{
|
{
|
||||||
Elf_Internal_Dyn * dynamic_segment;
|
|
||||||
Elf_Internal_Dyn * entry;
|
Elf_Internal_Dyn * entry;
|
||||||
Elf32_External_Dyn * edyn;
|
Elf32_External_Dyn * edyn;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@ -1920,7 +1923,12 @@ process_dynamic_segment (file)
|
|||||||
GET_DATA_ALLOC (dynamic_addr, dynamic_size,
|
GET_DATA_ALLOC (dynamic_addr, dynamic_size,
|
||||||
edyn, Elf32_External_Dyn *, "dynamic segment");
|
edyn, Elf32_External_Dyn *, "dynamic segment");
|
||||||
|
|
||||||
dynamic_size = dynamic_size / sizeof (Elf32_External_Dyn);
|
/* SGI's ELF has more than one section in the DYNAMIC segment. Determine
|
||||||
|
how large .dynamic is now. We can do this even before the byte
|
||||||
|
swapping since the DT_NULL tag is recognizable. */
|
||||||
|
dynamic_size = 0;
|
||||||
|
while (*(Elf32_Word *) edyn[dynamic_size++].d_tag != DT_NULL)
|
||||||
|
;
|
||||||
|
|
||||||
dynamic_segment = (Elf_Internal_Dyn *)
|
dynamic_segment = (Elf_Internal_Dyn *)
|
||||||
malloc (dynamic_size * sizeof (Elf_Internal_Dyn));
|
malloc (dynamic_size * sizeof (Elf_Internal_Dyn));
|
||||||
@ -2020,13 +2028,12 @@ process_dynamic_segment (file)
|
|||||||
|
|
||||||
if (do_dynamic && dynamic_addr)
|
if (do_dynamic && dynamic_addr)
|
||||||
printf (_("\nDynamic segment at offset 0x%x contains %d entries:\n"),
|
printf (_("\nDynamic segment at offset 0x%x contains %d entries:\n"),
|
||||||
dynamic_addr, dynamic_size % 1000);
|
dynamic_addr, dynamic_size);
|
||||||
if (do_dynamic)
|
if (do_dynamic)
|
||||||
printf (_(" Tag Type Name/Value\n"));
|
printf (_(" Tag Type Name/Value\n"));
|
||||||
|
|
||||||
for (i = 0, entry = dynamic_segment;
|
for (i = 0, entry = dynamic_segment;
|
||||||
/* XXX SGI's linker produces a number which is 1000 higher. */
|
i < dynamic_size;
|
||||||
i < (dynamic_size % 1000);
|
|
||||||
i++, entry ++)
|
i++, entry ++)
|
||||||
{
|
{
|
||||||
if (do_dynamic)
|
if (do_dynamic)
|
||||||
@ -2143,8 +2150,6 @@ process_dynamic_segment (file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free (dynamic_segment);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3143,6 +3148,301 @@ process_section_contents (file)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
process_mips_fpe_exception (mask)
|
||||||
|
int mask;
|
||||||
|
{
|
||||||
|
if (mask)
|
||||||
|
{
|
||||||
|
int first = 1;
|
||||||
|
if (mask & OEX_FPU_INEX)
|
||||||
|
fputs ("INEX", stdout), first = 0;
|
||||||
|
if (mask & OEX_FPU_UFLO)
|
||||||
|
printf ("%sUFLO", first ? "" : "|"), first = 0;
|
||||||
|
if (mask & OEX_FPU_OFLO)
|
||||||
|
printf ("%sOFLO", first ? "" : "|"), first = 0;
|
||||||
|
if (mask & OEX_FPU_DIV0)
|
||||||
|
printf ("%sDIV0", first ? "" : "|"), first = 0;
|
||||||
|
if (mask & OEX_FPU_INVAL)
|
||||||
|
printf ("%sINVAL", first ? "" : "|");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fputs ("0", stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
process_mips_specific (file)
|
||||||
|
FILE *file;
|
||||||
|
{
|
||||||
|
Elf_Internal_Dyn * entry;
|
||||||
|
size_t liblist_offset = 0;
|
||||||
|
size_t liblistno = 0;
|
||||||
|
size_t options_offset = 0;
|
||||||
|
|
||||||
|
/* We have a lot of special sections. Thanks SGI! */
|
||||||
|
if (dynamic_segment == NULL)
|
||||||
|
/* No information available. */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (entry = dynamic_segment; entry->d_tag != DT_NULL; ++entry)
|
||||||
|
switch (entry->d_tag)
|
||||||
|
{
|
||||||
|
case DT_MIPS_LIBLIST:
|
||||||
|
liblist_offset = entry->d_un.d_val - loadaddr;
|
||||||
|
break;
|
||||||
|
case DT_MIPS_LIBLISTNO:
|
||||||
|
liblistno = entry->d_un.d_val;
|
||||||
|
break;
|
||||||
|
case DT_MIPS_OPTIONS:
|
||||||
|
options_offset = entry->d_un.d_val - loadaddr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (liblist_offset != 0 && liblistno != 0 && do_dynamic)
|
||||||
|
{
|
||||||
|
Elf32_External_Lib *elib;
|
||||||
|
size_t cnt;
|
||||||
|
|
||||||
|
GET_DATA_ALLOC (liblist_offset, liblistno * sizeof (Elf32_External_Lib),
|
||||||
|
elib, Elf32_External_Lib *, "liblist");
|
||||||
|
|
||||||
|
printf ("\nSection '.liblist' contains %d entries:\n", liblistno);
|
||||||
|
fputs (" Library Time Stamp Checksum Version Flags\n",
|
||||||
|
stdout);
|
||||||
|
|
||||||
|
for (cnt = 0; cnt < liblistno; ++cnt)
|
||||||
|
{
|
||||||
|
Elf32_Lib liblist;
|
||||||
|
time_t time;
|
||||||
|
char timebuf[17];
|
||||||
|
|
||||||
|
liblist.l_name = BYTE_GET (elib[cnt].l_name);
|
||||||
|
time = BYTE_GET (elib[cnt].l_time_stamp);
|
||||||
|
liblist.l_checksum = BYTE_GET (elib[cnt].l_checksum);
|
||||||
|
liblist.l_version = BYTE_GET (elib[cnt].l_version);
|
||||||
|
liblist.l_flags = BYTE_GET (elib[cnt].l_flags);
|
||||||
|
|
||||||
|
strftime (timebuf, 17, "%Y-%m-%dT%H:%M", gmtime (&time));
|
||||||
|
|
||||||
|
printf ("%3d: %-20s %s %#10lx %-7ld %#lx\n", cnt,
|
||||||
|
dynamic_strings + liblist.l_name, timebuf,
|
||||||
|
liblist.l_checksum, liblist.l_version, liblist.l_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
free (elib);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options_offset != 0)
|
||||||
|
{
|
||||||
|
Elf_External_Options *eopt;
|
||||||
|
Elf_Internal_Shdr *sect = section_headers;
|
||||||
|
Elf_Internal_Options *iopt;
|
||||||
|
Elf_Internal_Options *option;
|
||||||
|
size_t offset;
|
||||||
|
int cnt;
|
||||||
|
|
||||||
|
/* Find the section header so that we get the size. */
|
||||||
|
while (sect->sh_type != SHT_MIPS_OPTIONS)
|
||||||
|
++sect;
|
||||||
|
|
||||||
|
GET_DATA_ALLOC (options_offset, sect->sh_size, eopt,
|
||||||
|
Elf_External_Options *, "options");
|
||||||
|
|
||||||
|
iopt = (Elf_Internal_Options *) malloc ((sect->sh_size / sizeof (eopt))
|
||||||
|
* sizeof (*iopt));
|
||||||
|
if (iopt == NULL)
|
||||||
|
{
|
||||||
|
error (_("Out of memory"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = cnt = 0;
|
||||||
|
option = iopt;
|
||||||
|
while (offset < sect->sh_size)
|
||||||
|
{
|
||||||
|
Elf_External_Options *eoption;
|
||||||
|
|
||||||
|
eoption = (Elf_External_Options *) ((char *) eopt + offset);
|
||||||
|
|
||||||
|
option->kind = BYTE_GET (eoption->kind);
|
||||||
|
option->size = BYTE_GET (eoption->size);
|
||||||
|
option->section = BYTE_GET (eoption->section);
|
||||||
|
option->info = BYTE_GET (eoption->info);
|
||||||
|
|
||||||
|
offset += option->size;
|
||||||
|
++option;
|
||||||
|
++cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf (_("\nSection '%s' contains %d entries:\n"),
|
||||||
|
string_table + sect->sh_name, cnt);
|
||||||
|
|
||||||
|
option = iopt;
|
||||||
|
while (cnt-- > 0)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
switch (option->kind)
|
||||||
|
{
|
||||||
|
case ODK_NULL:
|
||||||
|
/* This shouldn't happen. */
|
||||||
|
printf (" NULL %d %x", option->section, option->info);
|
||||||
|
break;
|
||||||
|
case ODK_REGINFO:
|
||||||
|
printf (" REGINFO ");
|
||||||
|
if (elf_header.e_machine == EM_MIPS)
|
||||||
|
{
|
||||||
|
/* 32bit form. */
|
||||||
|
Elf32_External_RegInfo *ereg;
|
||||||
|
Elf32_RegInfo reginfo;
|
||||||
|
|
||||||
|
ereg = (Elf32_External_RegInfo *) (option + 1);
|
||||||
|
reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask);
|
||||||
|
reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]);
|
||||||
|
reginfo.ri_cprmask[1] = BYTE_GET (ereg->ri_cprmask[1]);
|
||||||
|
reginfo.ri_cprmask[2] = BYTE_GET (ereg->ri_cprmask[2]);
|
||||||
|
reginfo.ri_cprmask[3] = BYTE_GET (ereg->ri_cprmask[3]);
|
||||||
|
reginfo.ri_gp_value = BYTE_GET (ereg->ri_gp_value);
|
||||||
|
|
||||||
|
printf ("GPR %08lx GP %ld\n",
|
||||||
|
reginfo.ri_gprmask, reginfo.ri_gp_value);
|
||||||
|
printf (" CPR0 %08lx CPR1 %08lx CPR2 %08lx CPR3 %08lx\n",
|
||||||
|
reginfo.ri_cprmask[0], reginfo.ri_cprmask[1],
|
||||||
|
reginfo.ri_cprmask[2], reginfo.ri_cprmask[3]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* 64 bit form. */
|
||||||
|
Elf64_External_RegInfo *ereg;
|
||||||
|
Elf64_Internal_RegInfo reginfo;
|
||||||
|
|
||||||
|
ereg = (Elf64_External_RegInfo *) (option + 1);
|
||||||
|
reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask);
|
||||||
|
reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]);
|
||||||
|
reginfo.ri_cprmask[1] = BYTE_GET (ereg->ri_cprmask[1]);
|
||||||
|
reginfo.ri_cprmask[2] = BYTE_GET (ereg->ri_cprmask[2]);
|
||||||
|
reginfo.ri_cprmask[3] = BYTE_GET (ereg->ri_cprmask[3]);
|
||||||
|
reginfo.ri_gp_value = BYTE_GET (ereg->ri_gp_value);
|
||||||
|
|
||||||
|
printf ("GPR %08lx GP %ld\n",
|
||||||
|
reginfo.ri_gprmask, reginfo.ri_gp_value);
|
||||||
|
printf (" CPR0 %08lx CPR1 %08lx CPR2 %08lx CPR3 %08lx\n",
|
||||||
|
reginfo.ri_cprmask[0], reginfo.ri_cprmask[1],
|
||||||
|
reginfo.ri_cprmask[2], reginfo.ri_cprmask[3]);
|
||||||
|
}
|
||||||
|
++option;
|
||||||
|
continue;
|
||||||
|
case ODK_EXCEPTIONS:
|
||||||
|
fputs (" EXCEPTIONS fpe_min(", stdout);
|
||||||
|
process_mips_fpe_exception (option->info & OEX_FPU_MIN);
|
||||||
|
fputs (") fpe_max(", stdout);
|
||||||
|
process_mips_fpe_exception ((option->info & OEX_FPU_MAX) >> 8);
|
||||||
|
fputs (")", stdout);
|
||||||
|
|
||||||
|
if (option->info & OEX_PAGE0)
|
||||||
|
fputs (" PAGE0", stdout);
|
||||||
|
if (option->info & OEX_SMM)
|
||||||
|
fputs (" SMM", stdout);
|
||||||
|
if (option->info & OEX_FPDBUG)
|
||||||
|
fputs (" FPDBUG", stdout);
|
||||||
|
if (option->info & OEX_DISMISS)
|
||||||
|
fputs (" DISMISS", stdout);
|
||||||
|
break;
|
||||||
|
case ODK_PAD:
|
||||||
|
fputs (" PAD ", stdout);
|
||||||
|
if (option->info & OPAD_PREFIX)
|
||||||
|
fputs (" PREFIX", stdout);
|
||||||
|
if (option->info & OPAD_POSTFIX)
|
||||||
|
fputs (" POSTFIX", stdout);
|
||||||
|
if (option->info & OPAD_SYMBOL)
|
||||||
|
fputs (" SYMBOL", stdout);
|
||||||
|
break;
|
||||||
|
case ODK_HWPATCH:
|
||||||
|
fputs (" HWPATCH ", stdout);
|
||||||
|
if (option->info & OHW_R4KEOP)
|
||||||
|
fputs (" R4KEOP", stdout);
|
||||||
|
if (option->info & OHW_R8KPFETCH)
|
||||||
|
fputs (" R8KPFETCH", stdout);
|
||||||
|
if (option->info & OHW_R5KEOP)
|
||||||
|
fputs (" R5KEOP", stdout);
|
||||||
|
if (option->info & OHW_R5KCVTL)
|
||||||
|
fputs (" R5KCVTL", stdout);
|
||||||
|
break;
|
||||||
|
case ODK_FILL:
|
||||||
|
fputs (" FILL ", stdout);
|
||||||
|
/* XXX Print content of info word? */
|
||||||
|
break;
|
||||||
|
case ODK_TAGS:
|
||||||
|
fputs (" TAGS ", stdout);
|
||||||
|
/* XXX Print content of info word? */
|
||||||
|
break;
|
||||||
|
case ODK_HWAND:
|
||||||
|
fputs (" HWAND ", stdout);
|
||||||
|
if (option->info & OHWA0_R4KEOP_CHECKED)
|
||||||
|
fputs (" R4KEOP_CHECKED", stdout);
|
||||||
|
if (option->info & OHWA0_R4KEOP_CLEAN)
|
||||||
|
fputs (" R4KEOP_CLEAN", stdout);
|
||||||
|
break;
|
||||||
|
case ODK_HWOR:
|
||||||
|
fputs (" HWOR ", stdout);
|
||||||
|
if (option->info & OHWA0_R4KEOP_CHECKED)
|
||||||
|
fputs (" R4KEOP_CHECKED", stdout);
|
||||||
|
if (option->info & OHWA0_R4KEOP_CLEAN)
|
||||||
|
fputs (" R4KEOP_CLEAN", stdout);
|
||||||
|
break;
|
||||||
|
case ODK_GP_GROUP:
|
||||||
|
printf (" GP_GROUP %#06x self-contained %#06x",
|
||||||
|
option->info & OGP_GROUP,
|
||||||
|
(option->info & OGP_SELF) >> 16);
|
||||||
|
break;
|
||||||
|
case ODK_IDENT:
|
||||||
|
printf (" IDENT %#06x self-contained %#06x",
|
||||||
|
option->info & OGP_GROUP,
|
||||||
|
(option->info & OGP_SELF) >> 16);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* This shouldn't happen. */
|
||||||
|
printf (" %3d ??? %d %x",
|
||||||
|
option->kind, option->section, option->info);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = sizeof (*eopt);
|
||||||
|
while (len < option->size)
|
||||||
|
if (((char *) option)[len] >= ' '
|
||||||
|
&& ((char *) option)[len++] < 0x7f)
|
||||||
|
printf ("%c", ((char *) option)[len++]);
|
||||||
|
else
|
||||||
|
printf ("\\%03o", ((char *) option)[len++]);
|
||||||
|
|
||||||
|
fputs ("\n", stdout);
|
||||||
|
++option;
|
||||||
|
}
|
||||||
|
|
||||||
|
free (eopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
process_arch_specific (file)
|
||||||
|
FILE *file;
|
||||||
|
{
|
||||||
|
switch (elf_header.e_machine)
|
||||||
|
{
|
||||||
|
case EM_MIPS:
|
||||||
|
case EM_MIPS_RS4_BE:
|
||||||
|
return process_mips_specific (file);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_file_header (file)
|
get_file_header (file)
|
||||||
FILE * file;
|
FILE * file;
|
||||||
@ -3236,6 +3536,8 @@ process_file (file_name)
|
|||||||
|
|
||||||
process_section_contents (file);
|
process_section_contents (file);
|
||||||
|
|
||||||
|
process_arch_specific (file);
|
||||||
|
|
||||||
fclose (file);
|
fclose (file);
|
||||||
|
|
||||||
if (section_headers)
|
if (section_headers)
|
||||||
|
Loading…
Reference in New Issue
Block a user