#include "elf/mmix.h"
#include "elf/mn10200.h"
#include "elf/mn10300.h"
-#include "elf/ms1.h"
+#include "elf/mt.h"
#include "elf/msp430.h"
#include "elf/or32.h"
#include "elf/pj.h"
static struct group *section_groups;
static struct group **section_headers_groups;
+/* A linked list of the section names for which dumps were requested
+ by name. */
+struct dump_list_entry
+{
+ char *name;
+ int type;
+ struct dump_list_entry *next;
+};
+static struct dump_list_entry *dump_sects_byname;
+
/* A dynamic array of flags indicating for which sections a hex dump
has been requested (via the -x switch) and/or a disassembly dump
(via the -i switch). */
/* A dynamic array of flags indicating for which sections a dump of
some kind has been requested. It is reset on a per-object file
- basis and then initialised from the cmdline_dump_sects array and
- the results of interpreting the -w switch. */
+ basis and then initialised from the cmdline_dump_sects array,
+ the results of interpreting the -w switch, and the
+ dump_sects_byname list. */
char *dump_sects = NULL;
unsigned int num_dump_sects = 0;
case EM_XTENSA_OLD:
case EM_M32R:
case EM_M32C:
- case EM_MS1:
+ case EM_MT:
case EM_BLACKFIN:
return TRUE;
rtype = elf_m32c_reloc_type (type);
break;
- case EM_MS1:
- rtype = elf_ms1_reloc_type (type);
+ case EM_MT:
+ rtype = elf_mt_reloc_type (type);
break;
case EM_BLACKFIN:
case EM_XTENSA_OLD:
case EM_XTENSA: return "Tensilica Xtensa Processor";
case EM_M32C: return "Renesas M32c";
- case EM_MS1: return "Morpho Techologies MS1 processor";
+ case EM_MT: return "Morpho Techologies MT processor";
+ case EM_BLACKFIN: return "Analog Devices Blackfin";
default:
snprintf (buff, sizeof (buff), _("<unknown>: %x"), e_machine);
return buff;
fprintf (stdout, _("\
-I --histogram Display histogram of bucket list lengths\n\
-W --wide Allow output width to exceed 80 characters\n\
+ @<file> Read options from <file>\n\
-H --help Display this information\n\
-v --version Display the version number of readelf\n"));
fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO);
return;
}
+/* Request a dump by section name. */
+
+static void
+request_dump_byname (const char *section, int type)
+{
+ struct dump_list_entry *new_request;
+
+ new_request = malloc (sizeof (struct dump_list_entry));
+ if (!new_request)
+ error (_("Out of memory allocating dump request table."));
+
+ new_request->name = strdup (section);
+ if (!new_request->name)
+ error (_("Out of memory allocating dump request table."));
+
+ new_request->type = type;
+
+ new_request->next = dump_sects_byname;
+ dump_sects_byname = new_request;
+}
+
static void
parse_args (int argc, char **argv)
{
do_dump++;
section = strtoul (optarg, & cp, 0);
if (! *cp && section >= 0)
- {
- request_dump (section, HEX_DUMP);
- break;
- }
- goto oops;
+ request_dump (section, HEX_DUMP);
+ else
+ request_dump_byname (optarg, HEX_DUMP);
+ break;
case 'w':
do_dump++;
if (optarg == 0)
do_wide++;
break;
default:
+#ifdef SUPPORT_DISASSEMBLY
oops:
+#endif
/* xgettext:c-format */
error (_("Invalid option '-%c'\n"), c);
/* Drop through. */
bfd_vma offset;
};
+#define ABSADDR(a) \
+ ((a).section \
+ ? section_headers [(a).section].sh_addr + (a).offset \
+ : (a).offset)
+
struct ia64_unw_aux_info
{
struct ia64_unw_table_entry
printf ("], info at +0x%lx\n",
(unsigned long) (tp->info.offset - aux->seg_base));
- head = aux->info + (tp->info.offset - aux->info_addr);
+ head = aux->info + (ABSADDR (tp->info) - aux->info_addr);
stamp = byte_get ((unsigned char *) head, sizeof (stamp));
printf (" v%u, flags=0x%lx (%s%s), len=%lu bytes\n",
}
static const char *
+get_mips_symbol_other (unsigned int other)
+{
+ switch (other)
+ {
+ case STO_OPTIONAL: return "OPTIONAL";
+ case STO_MIPS16: return "MIPS16";
+ default: return NULL;
+ }
+}
+
+static const char *
+get_symbol_other (unsigned int other)
+{
+ const char * result = NULL;
+ static char buff [32];
+
+ if (other == 0)
+ return "";
+
+ switch (elf_header.e_machine)
+ {
+ case EM_MIPS:
+ result = get_mips_symbol_other (other);
+ default:
+ break;
+ }
+
+ if (result)
+ return result;
+
+ snprintf (buff, sizeof buff, _("<other>: %x"), other);
+ return buff;
+}
+
+static const char *
get_symbol_index_type (unsigned int type)
{
static char buff[32];
printf (" %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info)));
printf (" %6s", get_symbol_binding (ELF_ST_BIND (psym->st_info)));
printf (" %3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
+ /* Check to see if any other bits in the st_other field are set.
+ Note - displaying this information disrupts the layout of the
+ table being generated, but for the moment this case is very rare. */
+ if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))
+ printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)));
printf (" %3.3s ", get_symbol_index_type (psym->st_shndx));
if (VALID_DYNAMIC_NAME (psym->st_name))
print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
printf (" %-7s", get_symbol_type (ELF_ST_TYPE (psym->st_info)));
printf (" %-6s", get_symbol_binding (ELF_ST_BIND (psym->st_info)));
printf (" %-3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
+ /* Check to see if any other bits in the st_other field are set.
+ Note - displaying this information disrupts the layout of the
+ table being generated, but for the moment this case is very rare. */
+ if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))
+ printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)));
printf (" %4s ", get_symbol_index_type (psym->st_shndx));
print_symbol (25, psym->st_name < strtab_size
? strtab + psym->st_name : "<corrupt>");
return result;
}
+/* Set DUMP_SECTS for all sections where dumps were requested
+ based on section name. */
+
+static void
+initialise_dumps_byname (void)
+{
+ struct dump_list_entry *cur;
+
+ for (cur = dump_sects_byname; cur; cur = cur->next)
+ {
+ unsigned int i;
+ int any;
+
+ for (i = 0, any = 0; i < elf_header.e_shnum; i++)
+ if (streq (SECTION_NAME (section_headers + i), cur->name))
+ {
+ request_dump (i, cur->type);
+ any = 1;
+ }
+
+ if (!any)
+ warn (_("Section '%s' was not dumped because it does not exist!\n"),
+ cur->name);
+ }
+}
+
static void
process_section_contents (FILE *file)
{
if (! do_dump)
return;
+ initialise_dumps_byname ();
+
for (i = 0, section = section_headers;
i < elf_header.e_shnum && i < num_dump_sects;
i++, section++)
fputs ("0", stdout);
}
+/* ARM EABI attributes section. */
+typedef struct
+{
+ int tag;
+ const char *name;
+ /* 0 = special, 1 = string, 2 = uleb123, > 0x80 == table lookup. */
+ int type;
+ const char **table;
+} arm_attr_public_tag;
+
+static const char *arm_attr_tag_CPU_arch[] =
+ {"Pre-v4", "v4", "v4T", "v5T", "v5TE", "v5TEJ", "v6", "v6KZ", "v6T2",
+ "v6K", "v7"};
+static const char *arm_attr_tag_ARM_ISA_use[] = {"No", "Yes"};
+static const char *arm_attr_tag_THUMB_ISA_use[] =
+ {"No", "Thumb-1", "Thumb-2"};
+static const char *arm_attr_tag_VFP_arch[] = {"No", "VFPv1", "VFPv2"};
+static const char *arm_attr_tag_WMMX_arch[] = {"No", "WMMXv1"};
+static const char *arm_attr_tag_NEON_arch[] = {"No", "NEONv1"};
+static const char *arm_attr_tag_ABI_PCS_config[] =
+ {"None", "Bare platform", "Linux application", "Linux DSO", "PalmOS 2004",
+ "PalmOS (reserved)", "SymbianOS 2004", "SymbianOS (reserved)"};
+static const char *arm_attr_tag_ABI_PCS_R9_use[] =
+ {"V6", "SB", "TLS", "Unused"};
+static const char *arm_attr_tag_ABI_PCS_RW_data[] =
+ {"Absolute", "PC-relative", "SB-relative", "None"};
+static const char *arm_attr_tag_ABI_PCS_RO_DATA[] =
+ {"Absolute", "PC-relative", "None"};
+static const char *arm_attr_tag_ABI_PCS_GOT_use[] =
+ {"None", "direct", "GOT-indirect"};
+static const char *arm_attr_tag_ABI_PCS_wchar_t[] =
+ {"None", "??? 1", "2", "??? 3", "4"};
+static const char *arm_attr_tag_ABI_FP_rounding[] = {"Unused", "Needed"};
+static const char *arm_attr_tag_ABI_FP_denormal[] = {"Unused", "Needed"};
+static const char *arm_attr_tag_ABI_FP_exceptions[] = {"Unused", "Needed"};
+static const char *arm_attr_tag_ABI_FP_user_exceptions[] = {"Unused", "Needed"};
+static const char *arm_attr_tag_ABI_FP_number_model[] =
+ {"Unused", "Finite", "RTABI", "IEEE 754"};
+static const char *arm_attr_tag_ABI_align8_needed[] = {"No", "Yes", "4-byte"};
+static const char *arm_attr_tag_ABI_align8_preserved[] =
+ {"No", "Yes, except leaf SP", "Yes"};
+static const char *arm_attr_tag_ABI_enum_size[] =
+ {"Unused", "small", "int", "forced to int"};
+static const char *arm_attr_tag_ABI_HardFP_use[] =
+ {"As Tag_VFP_arch", "SP only", "DP only", "SP and DP"};
+static const char *arm_attr_tag_ABI_VFP_args[] =
+ {"AAPCS", "VFP registers", "custom"};
+static const char *arm_attr_tag_ABI_WMMX_args[] =
+ {"AAPCS", "WMMX registers", "custom"};
+static const char *arm_attr_tag_ABI_optimization_goals[] =
+ {"None", "Prefer Speed", "Aggressive Speed", "Prefer Size",
+ "Aggressive Size", "Prefer Debug", "Aggressive Debug"};
+static const char *arm_attr_tag_ABI_FP_optimization_goals[] =
+ {"None", "Prefer Speed", "Aggressive Speed", "Prefer Size",
+ "Aggressive Size", "Prefer Accuracy", "Aggressive Accuracy"};
+
+#define LOOKUP(id, name) \
+ {id, #name, 0x80 | ARRAY_SIZE(arm_attr_tag_##name), arm_attr_tag_##name}
+static arm_attr_public_tag arm_attr_public_tags[] =
+{
+ {4, "CPU_raw_name", 1, NULL},
+ {5, "CPU_name", 1, NULL},
+ LOOKUP(6, CPU_arch),
+ {7, "CPU_arch_profile", 0, NULL},
+ LOOKUP(8, ARM_ISA_use),
+ LOOKUP(9, THUMB_ISA_use),
+ LOOKUP(10, VFP_arch),
+ LOOKUP(11, WMMX_arch),
+ LOOKUP(12, NEON_arch),
+ LOOKUP(13, ABI_PCS_config),
+ LOOKUP(14, ABI_PCS_R9_use),
+ LOOKUP(15, ABI_PCS_RW_data),
+ LOOKUP(16, ABI_PCS_RO_DATA),
+ LOOKUP(17, ABI_PCS_GOT_use),
+ LOOKUP(18, ABI_PCS_wchar_t),
+ LOOKUP(19, ABI_FP_rounding),
+ LOOKUP(20, ABI_FP_denormal),
+ LOOKUP(21, ABI_FP_exceptions),
+ LOOKUP(22, ABI_FP_user_exceptions),
+ LOOKUP(23, ABI_FP_number_model),
+ LOOKUP(24, ABI_align8_needed),
+ LOOKUP(25, ABI_align8_preserved),
+ LOOKUP(26, ABI_enum_size),
+ LOOKUP(27, ABI_HardFP_use),
+ LOOKUP(28, ABI_VFP_args),
+ LOOKUP(29, ABI_WMMX_args),
+ LOOKUP(30, ABI_optimization_goals),
+ LOOKUP(31, ABI_FP_optimization_goals),
+ {32, "compatibility", 0, NULL}
+};
+#undef LOOKUP
+
+/* Read an unsigned LEB128 encoded value from p. Set *PLEN to the number of
+ bytes read. */
+static unsigned int
+read_uleb128 (unsigned char *p, unsigned int *plen)
+{
+ unsigned char c;
+ unsigned int val;
+ int shift;
+ int len;
+
+ val = 0;
+ shift = 0;
+ len = 0;
+ do
+ {
+ c = *(p++);
+ len++;
+ val |= ((unsigned int)c & 0x7f) << shift;
+ shift += 7;
+ }
+ while (c & 0x80);
+
+ *plen = len;
+ return val;
+}
+
+static unsigned char *
+display_arm_attribute (unsigned char *p)
+{
+ int tag;
+ unsigned int len;
+ int val;
+ arm_attr_public_tag *attr;
+ unsigned i;
+ int type;
+
+ tag = read_uleb128 (p, &len);
+ p += len;
+ attr = NULL;
+ for (i = 0; i < ARRAY_SIZE(arm_attr_public_tags); i++)
+ {
+ if (arm_attr_public_tags[i].tag == tag)
+ {
+ attr = &arm_attr_public_tags[i];
+ break;
+ }
+ }
+
+ if (attr)
+ {
+ printf (" Tag_%s: ", attr->name);
+ switch (attr->type)
+ {
+ case 0:
+ switch (tag)
+ {
+ case 7: /* Tag_CPU_arch_profile. */
+ val = read_uleb128 (p, &len);
+ p += len;
+ switch (val)
+ {
+ case 0: printf ("None\n"); break;
+ case 'A': printf ("Application\n"); break;
+ case 'R': printf ("Realtime\n"); break;
+ case 'M': printf ("Microcontroller\n"); break;
+ default: printf ("??? (%d)\n", val); break;
+ }
+ break;
+
+ case 32: /* Tag_compatibility. */
+ val = read_uleb128 (p, &len);
+ p += len;
+ printf ("flag = %d, vendor = %s\n", val, p);
+ p += strlen((char *)p) + 1;
+ break;
+
+ default:
+ abort();
+ }
+ return p;
+
+ case 1:
+ case 2:
+ type = attr->type;
+ break;
+
+ default:
+ assert (attr->type & 0x80);
+ val = read_uleb128 (p, &len);
+ p += len;
+ type = attr->type & 0x7f;
+ if (val >= type)
+ printf ("??? (%d)\n", val);
+ else
+ printf ("%s\n", attr->table[val]);
+ return p;
+ }
+ }
+ else
+ {
+ if (tag & 1)
+ type = 1; /* String. */
+ else
+ type = 2; /* uleb128. */
+ printf (" Tag_unknown_%d: ", tag);
+ }
+
+ if (type == 1)
+ {
+ printf ("\"%s\"\n", p);
+ p += strlen((char *)p) + 1;
+ }
+ else
+ {
+ val = read_uleb128 (p, &len);
+ p += len;
+ printf ("%d (0x%x)\n", val, val);
+ }
+
+ return p;
+}
+
+static int
+process_arm_specific (FILE *file)
+{
+ Elf_Internal_Shdr *sect;
+ unsigned char *contents;
+ unsigned char *p;
+ unsigned char *end;
+ bfd_vma section_len;
+ bfd_vma len;
+ unsigned i;
+
+ /* Find the section header so that we get the size. */
+ for (i = 0, sect = section_headers;
+ i < elf_header.e_shnum;
+ i++, sect++)
+ {
+ if (sect->sh_type != SHT_ARM_ATTRIBUTES)
+ continue;
+
+ contents = get_data (NULL, file, sect->sh_offset, 1, sect->sh_size,
+ _("attributes"));
+
+ if (!contents)
+ continue;
+ p = contents;
+ if (*p == 'A')
+ {
+ len = sect->sh_size - 1;
+ p++;
+ while (len > 0)
+ {
+ int namelen;
+ bfd_boolean public_section;
+
+ section_len = byte_get (p, 4);
+ p += 4;
+ if (section_len > len)
+ {
+ printf (_("ERROR: Bad section length (%d > %d)\n"),
+ (int)section_len, (int)len);
+ section_len = len;
+ }
+ len -= section_len;
+ printf ("Attribute Section: %s\n", p);
+ if (strcmp ((char *)p, "aeabi") == 0)
+ public_section = TRUE;
+ else
+ public_section = FALSE;
+ namelen = strlen ((char *)p) + 1;
+ p += namelen;
+ section_len -= namelen + 4;
+ while (section_len > 0)
+ {
+ int tag = *(p++);
+ int val;
+ bfd_vma size;
+ size = byte_get (p, 4);
+ if (size > section_len)
+ {
+ printf (_("ERROR: Bad subsection length (%d > %d)\n"),
+ (int)size, (int)section_len);
+ size = section_len;
+ }
+ section_len -= size;
+ end = p + size - 1;
+ p += 4;
+ switch (tag)
+ {
+ case 1:
+ printf ("File Attributes\n");
+ break;
+ case 2:
+ printf ("Section Attributes:");
+ goto do_numlist;
+ case 3:
+ printf ("Symbol Attributes:");
+ do_numlist:
+ for (;;)
+ {
+ unsigned int i;
+ val = read_uleb128 (p, &i);
+ p += i;
+ if (val == 0)
+ break;
+ printf (" %d", val);
+ }
+ printf ("\n");
+ break;
+ default:
+ printf ("Unknown tag: %d\n", tag);
+ public_section = FALSE;
+ break;
+ }
+ if (public_section)
+ {
+ while (p < end)
+ p = display_arm_attribute(p);
+ }
+ else
+ {
+ /* ??? Do something sensible, like dump hex. */
+ printf (" Unknown section contexts\n");
+ p = end;
+ }
+ }
+ }
+ }
+ else
+ {
+ printf (_("Unknown format '%c'\n"), *p);
+ }
+
+ free(contents);
+ }
+ return 1;
+}
+
static int
process_mips_specific (FILE *file)
{
switch (elf_header.e_machine)
{
+ case EM_ARM:
+ return process_arm_specific (file);
case EM_MIPS:
case EM_MIPS_RS3_LE:
return process_mips_specific (file);