+ arm_sec->next_rela = arm_sec->rela;
+ }
+
+ if (arm_sec->data == NULL)
+ return 0;
+
+ word = byte_get (arm_sec->data + word_offset, 4);
+
+ wrapped = FALSE;
+ for (rp = arm_sec->next_rela; rp != arm_sec->rela + arm_sec->nrelas; rp++)
+ {
+ bfd_vma prelval, offset;
+
+ if (rp->r_offset > word_offset && !wrapped)
+ {
+ rp = arm_sec->rela;
+ wrapped = TRUE;
+ }
+ if (rp->r_offset > word_offset)
+ break;
+
+ if (rp->r_offset & 3)
+ {
+ warn (_("Skipping unexpected relocation at offset 0x%lx\n"),
+ (unsigned long) rp->r_offset);
+ continue;
+ }
+
+ if (rp->r_offset < word_offset)
+ continue;
+
+ relname = elf_arm_reloc_type (ELF32_R_TYPE (rp->r_info));
+
+ if (streq (relname, "R_ARM_NONE"))
+ continue;
+
+ if (! streq (relname, "R_ARM_PREL31"))
+ {
+ warn (_("Skipping unexpected relocation type %s\n"), relname);
+ continue;
+ }
+
+ sym = aux->symtab + ELF32_R_SYM (rp->r_info);
+
+ if (arm_sec->rel_type == SHT_REL)
+ {
+ offset = word & 0x7fffffff;
+ if (offset & 0x40000000)
+ offset |= ~ (bfd_vma) 0x7fffffff;
+ }
+ else
+ offset = rp->r_addend;
+
+ offset += sym->st_value;
+ prelval = offset - (arm_sec->sec->sh_addr + rp->r_offset);
+
+ word = (word & ~ (bfd_vma) 0x7fffffff) | (prelval & 0x7fffffff);
+ addr->section = sym->st_shndx;
+ addr->offset = offset;
+ break;
+ }
+
+ *wordp = word;
+ arm_sec->next_rela = rp;
+
+ return 1;
+}
+
+static void
+decode_arm_unwind (struct arm_unw_aux_info *aux,
+ unsigned int word, unsigned int remaining,
+ bfd_vma data_offset, Elf_Internal_Shdr *data_sec,
+ struct arm_section *data_arm_sec)
+{
+ int per_index;
+ unsigned int more_words;
+ struct absaddr addr;
+
+#define ADVANCE \
+ if (remaining == 0 && more_words) \
+ { \
+ data_offset += 4; \
+ if (!arm_section_get_word (aux, data_arm_sec, data_sec, \
+ data_offset, &word, &addr)) \
+ return; \
+ remaining = 4; \
+ more_words--; \
+ } \
+
+#define GET_OP(OP) \
+ ADVANCE; \
+ if (remaining) \
+ { \
+ remaining--; \
+ (OP) = word >> 24; \
+ word <<= 8; \
+ } \
+ else \
+ { \
+ printf (_("[Truncated opcode]\n")); \
+ return; \
+ } \
+ printf (_("0x%02x "), OP)
+
+ if (remaining == 0)
+ {
+ /* Fetch the first word. */
+ if (!arm_section_get_word (aux, data_arm_sec, data_sec, data_offset,
+ &word, &addr))
+ return;
+ remaining = 4;
+ }
+
+ if ((word & 0x80000000) == 0)
+ {
+ /* Expand prel31 for personality routine. */
+ bfd_vma fn;
+ const char *procname;
+
+ fn = word;
+ if (fn & 0x40000000)
+ fn |= ~ (bfd_vma) 0x7fffffff;
+ fn = fn + data_sec->sh_addr + data_offset;
+
+ printf (_(" Personality routine: "));
+ procname = arm_print_vma_and_name (aux, fn, addr);
+ fputc ('\n', stdout);
+
+ /* The GCC personality routines use the standard compact
+ encoding, starting with one byte giving the number of
+ words. */
+ if (procname != NULL
+ && (const_strneq (procname, "__gcc_personality_v0")
+ || const_strneq (procname, "__gxx_personality_v0")
+ || const_strneq (procname, "__gcj_personality_v0")
+ || const_strneq (procname, "__gnu_objc_personality_v0")))
+ {
+ remaining = 0;
+ more_words = 1;
+ ADVANCE;
+ if (!remaining)
+ {
+ printf (_(" [Truncated data]\n"));
+ return;
+ }
+ more_words = word >> 24;
+ word <<= 8;
+ remaining--;
+ }
+ else
+ return;
+ }
+ else
+ {
+
+ per_index = (word >> 24) & 0x7f;
+ if (per_index != 0 && per_index != 1 && per_index != 2)
+ {
+ printf (_(" [reserved compact index %d]\n"), per_index);
+ return;
+ }
+
+ printf (_(" Compact model %d\n"), per_index);
+ if (per_index == 0)
+ {
+ more_words = 0;
+ word <<= 8;
+ remaining--;
+ }
+ else
+ {
+ more_words = (word >> 16) & 0xff;
+ word <<= 16;
+ remaining -= 2;
+ }
+ }
+
+ /* Decode the unwinding instructions. */
+ while (1)
+ {
+ unsigned int op, op2;
+
+ ADVANCE;
+ if (remaining == 0)
+ break;
+ remaining--;
+ op = word >> 24;
+ word <<= 8;
+
+ printf (_(" 0x%02x "), op);
+
+ if ((op & 0xc0) == 0x00)
+ {
+ int offset = ((op & 0x3f) << 2) + 4;
+ printf (_(" vsp = vsp + %d"), offset);
+ }
+ else if ((op & 0xc0) == 0x40)
+ {
+ int offset = ((op & 0x3f) << 2) + 4;
+ printf (_(" vsp = vsp - %d"), offset);
+ }
+ else if ((op & 0xf0) == 0x80)
+ {
+ GET_OP (op2);
+ if (op == 0x80 && op2 == 0)
+ printf (_("Refuse to unwind"));
+ else
+ {
+ unsigned int mask = ((op & 0x0f) << 8) | op2;
+ int first = 1;
+ int i;
+
+ printf ("pop {");
+ for (i = 0; i < 12; i++)
+ if (mask & (1 << i))
+ {
+ if (first)
+ first = 0;
+ else
+ printf (", ");
+ printf ("r%d", 4 + i);
+ }
+ printf ("}");
+ }
+ }
+ else if ((op & 0xf0) == 0x90)
+ {
+ if (op == 0x9d || op == 0x9f)
+ printf (_(" [Reserved]"));
+ else
+ printf (_(" vsp = r%d"), op & 0x0f);
+ }
+ else if ((op & 0xf0) == 0xa0)
+ {
+ int end = 4 + (op & 0x07);
+ int first = 1;
+ int i;
+ printf (" pop {");
+ for (i = 4; i <= end; i++)
+ {
+ if (first)
+ first = 0;
+ else
+ printf (", ");
+ printf ("r%d", i);
+ }
+ if (op & 0x08)
+ {
+ if (first)
+ printf (", ");
+ printf ("r14");
+ }
+ printf ("}");
+ }
+ else if (op == 0xb0)
+ printf (_(" finish"));
+ else if (op == 0xb1)
+ {
+ GET_OP (op2);
+ if (op2 == 0 || (op2 & 0xf0) != 0)
+ printf (_("[Spare]"));
+ else
+ {
+ unsigned int mask = op2 & 0x0f;
+ int first = 1;
+ int i;
+ printf ("pop {");
+ for (i = 0; i < 12; i++)
+ if (mask & (1 << i))
+ {
+ if (first)
+ first = 0;
+ else
+ printf (", ");
+ printf ("r%d", i);
+ }
+ printf ("}");
+ }
+ }
+ else if (op == 0xb2)
+ {
+ unsigned char buf[9];
+ unsigned int i, len;
+ unsigned long offset;
+ for (i = 0; i < sizeof (buf); i++)
+ {
+ GET_OP (buf[i]);
+ if ((buf[i] & 0x80) == 0)
+ break;
+ }
+ assert (i < sizeof (buf));
+ offset = read_uleb128 (buf, &len);
+ assert (len == i + 1);
+ offset = offset * 4 + 0x204;
+ printf (_("vsp = vsp + %ld"), offset);
+ }
+ else
+ {
+ if (op == 0xb3 || op == 0xc6 || op == 0xc7 || op == 0xc8 || op == 0xc9)
+ {
+ GET_OP (op2);
+ printf (_("[unsupported two-byte opcode]"));
+ }
+ else
+ {
+ printf (_(" [unsupported opcode]"));
+ }
+ }
+ printf ("\n");
+ }
+
+ /* Decode the descriptors. Not implemented. */
+}
+
+static void
+dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec)
+{
+ struct arm_section exidx_arm_sec, extab_arm_sec;
+ unsigned int i, exidx_len;
+
+ memset (&exidx_arm_sec, 0, sizeof (exidx_arm_sec));
+ memset (&extab_arm_sec, 0, sizeof (extab_arm_sec));
+ exidx_len = exidx_sec->sh_size / 8;
+
+ for (i = 0; i < exidx_len; i++)
+ {
+ unsigned int exidx_fn, exidx_entry;
+ struct absaddr fn_addr, entry_addr;
+ bfd_vma fn;
+
+ fputc ('\n', stdout);
+
+ if (!arm_section_get_word (aux, &exidx_arm_sec, exidx_sec,
+ 8 * i, &exidx_fn, &fn_addr)
+ || !arm_section_get_word (aux, &exidx_arm_sec, exidx_sec,
+ 8 * i + 4, &exidx_entry, &entry_addr))
+ {
+ arm_free_section (&exidx_arm_sec);
+ arm_free_section (&extab_arm_sec);
+ return;
+ }
+
+ fn = exidx_fn & 0x7fffffff;
+ if (fn & 0x40000000)
+ fn |= ~ (bfd_vma) 0x7fffffff;
+ fn = fn + exidx_sec->sh_addr + 8 * i;
+
+ arm_print_vma_and_name (aux, fn, entry_addr);
+ fputs (": ", stdout);
+
+ if (exidx_entry == 1)
+ {
+ print_vma (exidx_entry, PREFIX_HEX);
+ fputs (" [cantunwind]\n", stdout);
+ }
+ else if (exidx_entry & 0x80000000)
+ {
+ print_vma (exidx_entry, PREFIX_HEX);
+ fputc ('\n', stdout);
+ decode_arm_unwind (aux, exidx_entry, 4, 0, NULL, NULL);
+ }
+ else
+ {
+ bfd_vma table, table_offset = 0;
+ Elf_Internal_Shdr *table_sec;
+
+ fputs ("@", stdout);
+ table = exidx_entry;
+ if (table & 0x40000000)
+ table |= ~ (bfd_vma) 0x7fffffff;
+ table = table + exidx_sec->sh_addr + 8 * i + 4;
+ print_vma (table, PREFIX_HEX);
+ printf ("\n");
+
+ /* Locate the matching .ARM.extab. */
+ if (entry_addr.section != SHN_UNDEF
+ && entry_addr.section < elf_header.e_shnum)
+ {
+ table_sec = section_headers + entry_addr.section;
+ table_offset = entry_addr.offset;
+ }
+ else
+ {
+ table_sec = find_section_by_address (table);
+ if (table_sec != NULL)
+ table_offset = table - table_sec->sh_addr;
+ }
+ if (table_sec == NULL)
+ {
+ warn (_("Could not locate .ARM.extab section containing 0x%lx.\n"),
+ (unsigned long) table);
+ continue;
+ }
+ decode_arm_unwind (aux, 0, 0, table_offset, table_sec,
+ &extab_arm_sec);
+ }
+ }
+
+ printf ("\n");
+
+ arm_free_section (&exidx_arm_sec);
+ arm_free_section (&extab_arm_sec);
+}
+
+static int
+arm_process_unwind (FILE *file)
+{
+ struct arm_unw_aux_info aux;
+ Elf_Internal_Shdr *unwsec = NULL;
+ Elf_Internal_Shdr *strsec;
+ Elf_Internal_Shdr *sec;
+ unsigned long i;
+
+ memset (& aux, 0, sizeof (aux));
+ aux.file = file;
+
+ if (string_table == NULL)
+ return 1;
+
+ for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
+ {
+ if (sec->sh_type == SHT_SYMTAB && sec->sh_link < elf_header.e_shnum)
+ {
+ aux.nsyms = sec->sh_size / sec->sh_entsize;
+ aux.symtab = GET_ELF_SYMBOLS (file, sec);
+
+ strsec = section_headers + sec->sh_link;
+ aux.strtab = get_data (NULL, file, strsec->sh_offset,
+ 1, strsec->sh_size, _("string table"));
+ aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
+ }
+ else if (sec->sh_type == SHT_ARM_EXIDX)
+ unwsec = sec;
+ }
+
+ if (!unwsec)
+ printf (_("\nThere are no unwind sections in this file.\n"));
+
+ for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
+ {
+ if (sec->sh_type == SHT_ARM_EXIDX)
+ {
+ printf (_("\nUnwind table index '%s' at offset 0x%lx contains %lu entries:\n"),
+ SECTION_NAME (sec),
+ (unsigned long) sec->sh_offset,
+ (unsigned long) (sec->sh_size / (2 * eh_addr_size)));
+
+ dump_arm_unwind (&aux, sec);
+ }
+ }
+
+ if (aux.symtab)
+ free (aux.symtab);
+ if (aux.strtab)
+ free ((char *) aux.strtab);
+
+ return 1;
+}
+
+static int
+process_unwind (FILE * file)
+{
+ struct unwind_handler
+ {
+ int machtype;
+ int (* handler)(FILE *);
+ } handlers[] =
+ {
+ { EM_ARM, arm_process_unwind },
+ { EM_IA_64, ia64_process_unwind },
+ { EM_PARISC, hppa_process_unwind },
+ { 0, 0 }
+ };
+ int i;
+
+ if (!do_unwind)
+ return 1;
+
+ for (i = 0; handlers[i].handler != NULL; i++)
+ if (elf_header.e_machine == handlers[i].machtype)
+ return handlers[i].handler (file);
+
+ printf (_("\nThere are no unwind sections in this file.\n"));
+ return 1;
+}
+
+static void
+dynamic_section_mips_val (Elf_Internal_Dyn * entry)
+{
+ switch (entry->d_tag)
+ {
+ case DT_MIPS_FLAGS:
+ if (entry->d_un.d_val == 0)
+ printf (_("NONE\n"));
+ else
+ {
+ static const char * opts[] =
+ {
+ "QUICKSTART", "NOTPOT", "NO_LIBRARY_REPLACEMENT",
+ "NO_MOVE", "SGI_ONLY", "GUARANTEE_INIT", "DELTA_C_PLUS_PLUS",
+ "GUARANTEE_START_INIT", "PIXIE", "DEFAULT_DELAY_LOAD",
+ "REQUICKSTART", "REQUICKSTARTED", "CORD", "NO_UNRES_UNDEF",
+ "RLD_ORDER_SAFE"
+ };
+ unsigned int cnt;
+ int first = 1;
+
+ for (cnt = 0; cnt < ARRAY_SIZE (opts); ++cnt)
+ if (entry->d_un.d_val & (1 << cnt))
+ {
+ printf ("%s%s", first ? "" : " ", opts[cnt]);
+ first = 0;
+ }
+ puts ("");
+ }
+ break;
+
+ case DT_MIPS_IVERSION:
+ if (VALID_DYNAMIC_NAME (entry->d_un.d_val))
+ printf (_("Interface Version: %s\n"), GET_DYNAMIC_NAME (entry->d_un.d_val));
+ else
+ printf (_("<corrupt: %ld>\n"), (long) entry->d_un.d_ptr);
+ break;
+
+ case DT_MIPS_TIME_STAMP:
+ {
+ char timebuf[20];
+ struct tm * tmp;
+
+ time_t atime = entry->d_un.d_val;
+ tmp = gmtime (&atime);
+ snprintf (timebuf, sizeof (timebuf), "%04u-%02u-%02uT%02u:%02u:%02u",
+ tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ printf (_("Time Stamp: %s\n"), timebuf);
+ }
+ break;
+
+ case DT_MIPS_RLD_VERSION:
+ case DT_MIPS_LOCAL_GOTNO:
+ case DT_MIPS_CONFLICTNO:
+ case DT_MIPS_LIBLISTNO:
+ case DT_MIPS_SYMTABNO:
+ case DT_MIPS_UNREFEXTNO:
+ case DT_MIPS_HIPAGENO:
+ case DT_MIPS_DELTA_CLASS_NO:
+ case DT_MIPS_DELTA_INSTANCE_NO:
+ case DT_MIPS_DELTA_RELOC_NO:
+ case DT_MIPS_DELTA_SYM_NO:
+ case DT_MIPS_DELTA_CLASSSYM_NO:
+ case DT_MIPS_COMPACT_SIZE:
+ printf ("%ld\n", (long) entry->d_un.d_ptr);
+ break;
+
+ default:
+ printf ("%#lx\n", (unsigned long) entry->d_un.d_ptr);
+ }
+}
+
+static void
+dynamic_section_parisc_val (Elf_Internal_Dyn * entry)
+{
+ switch (entry->d_tag)
+ {
+ case DT_HP_DLD_FLAGS:
+ {
+ static struct
+ {
+ long int bit;
+ const char * str;
+ }
+ flags[] =
+ {
+ { DT_HP_DEBUG_PRIVATE, "HP_DEBUG_PRIVATE" },
+ { DT_HP_DEBUG_CALLBACK, "HP_DEBUG_CALLBACK" },
+ { DT_HP_DEBUG_CALLBACK_BOR, "HP_DEBUG_CALLBACK_BOR" },
+ { DT_HP_NO_ENVVAR, "HP_NO_ENVVAR" },
+ { DT_HP_BIND_NOW, "HP_BIND_NOW" },
+ { DT_HP_BIND_NONFATAL, "HP_BIND_NONFATAL" },
+ { DT_HP_BIND_VERBOSE, "HP_BIND_VERBOSE" },
+ { DT_HP_BIND_RESTRICTED, "HP_BIND_RESTRICTED" },
+ { DT_HP_BIND_SYMBOLIC, "HP_BIND_SYMBOLIC" },
+ { DT_HP_RPATH_FIRST, "HP_RPATH_FIRST" },
+ { DT_HP_BIND_DEPTH_FIRST, "HP_BIND_DEPTH_FIRST" },
+ { DT_HP_GST, "HP_GST" },
+ { DT_HP_SHLIB_FIXED, "HP_SHLIB_FIXED" },
+ { DT_HP_MERGE_SHLIB_SEG, "HP_MERGE_SHLIB_SEG" },
+ { DT_HP_NODELETE, "HP_NODELETE" },
+ { DT_HP_GROUP, "HP_GROUP" },
+ { DT_HP_PROTECT_LINKAGE_TABLE, "HP_PROTECT_LINKAGE_TABLE" }
+ };
+ int first = 1;
+ size_t cnt;
+ bfd_vma val = entry->d_un.d_val;
+
+ for (cnt = 0; cnt < ARRAY_SIZE (flags); ++cnt)
+ if (val & flags[cnt].bit)
+ {
+ if (! first)
+ putchar (' ');
+ fputs (flags[cnt].str, stdout);
+ first = 0;
+ val ^= flags[cnt].bit;
+ }
+
+ if (val != 0 || first)
+ {
+ if (! first)
+ putchar (' ');
+ print_vma (val, HEX);
+ }
+ }
+ break;