/* readelf.c -- display contents of an ELF format file
- Copyright (C) 1998-2021 Free Software Foundation, Inc.
+ Copyright (C) 1998-2022 Free Software Foundation, Inc.
Originally developed by Eric Youngdale <eric@andante.jic.com>
Modifications by Nick Clifton <nickc@redhat.com>
#include <zlib.h>
#include <wchar.h>
+#if defined HAVE_MSGPACK
+#include <msgpack.h>
+#endif
+
#if __GNUC__ >= 2
/* Define BFD64 here, even if our default architecture is 32 bit ELF
as this will allow us to read in and parse 64bit and 32bit ELF files.
#include "bfd.h"
#include "bucomm.h"
#include "elfcomm.h"
+#include "demanguse.h"
#include "dwarf.h"
#include "ctf-api.h"
#include "demangle.h"
#include "elf/aarch64.h"
#include "elf/alpha.h"
+#include "elf/amdgpu.h"
#include "elf/arc.h"
#include "elf/arm.h"
#include "elf/avr.h"
static bool do_not_show_symbol_truncation = false;
static bool do_demangle = false; /* Pretty print C++ symbol names. */
static bool process_links = false;
+static bool dump_any_debugging = false;
static int demangle_flags = DMGL_ANSI | DMGL_PARAMS;
static int sym_base = 0;
}
print_mode;
+typedef enum unicode_display_type
+{
+ unicode_default = 0,
+ unicode_locale,
+ unicode_escape,
+ unicode_hex,
+ unicode_highlight,
+ unicode_invalid
+} unicode_display_type;
+
+static unicode_display_type unicode_display = unicode_default;
+
+typedef enum
+{
+ reltype_unknown,
+ reltype_rel,
+ reltype_rela,
+ reltype_relr
+} relocation_type;
+
/* Versioned symbol info. */
enum versioned_symbol_info
{
if (c == 0)
break;
- /* Do not print control characters directly as they can affect terminal
- settings. Such characters usually appear in the names generated
- by the assembler for local labels. */
- if (ISCNTRL (c))
+ if (ISPRINT (c))
+ {
+ putchar (c);
+ width_remaining --;
+ num_printed ++;
+ }
+ else if (ISCNTRL (c))
{
+ /* Do not print control characters directly as they can affect terminal
+ settings. Such characters usually appear in the names generated
+ by the assembler for local labels. */
+
if (width_remaining < 2)
break;
width_remaining -= 2;
num_printed += 2;
}
- else if (ISPRINT (c))
+ else if (c == 0x7f)
{
- putchar (c);
- width_remaining --;
- num_printed ++;
+ if (width_remaining < 5)
+ break;
+ printf ("<DEL>");
+ width_remaining -= 5;
+ num_printed += 5;
+ }
+ else if (unicode_display != unicode_locale
+ && unicode_display != unicode_default)
+ {
+ /* Display unicode characters as something else. */
+ unsigned char bytes[4];
+ bool is_utf8;
+ unsigned int nbytes;
+
+ bytes[0] = c;
+
+ if (bytes[0] < 0xc0)
+ {
+ nbytes = 1;
+ is_utf8 = false;
+ }
+ else
+ {
+ bytes[1] = *symbol++;
+
+ if ((bytes[1] & 0xc0) != 0x80)
+ {
+ is_utf8 = false;
+ /* Do not consume this character. It may only
+ be the first byte in the sequence that was
+ corrupt. */
+ --symbol;
+ nbytes = 1;
+ }
+ else if ((bytes[0] & 0x20) == 0)
+ {
+ is_utf8 = true;
+ nbytes = 2;
+ }
+ else
+ {
+ bytes[2] = *symbol++;
+
+ if ((bytes[2] & 0xc0) != 0x80)
+ {
+ is_utf8 = false;
+ symbol -= 2;
+ nbytes = 1;
+ }
+ else if ((bytes[0] & 0x10) == 0)
+ {
+ is_utf8 = true;
+ nbytes = 3;
+ }
+ else
+ {
+ bytes[3] = *symbol++;
+
+ nbytes = 4;
+
+ if ((bytes[3] & 0xc0) != 0x80)
+ {
+ is_utf8 = false;
+ symbol -= 3;
+ nbytes = 1;
+ }
+ else
+ is_utf8 = true;
+ }
+ }
+ }
+
+ if (unicode_display == unicode_invalid)
+ is_utf8 = false;
+
+ if (unicode_display == unicode_hex || ! is_utf8)
+ {
+ unsigned int i;
+
+ if (width_remaining < (nbytes * 2) + 2)
+ break;
+
+ putchar (is_utf8 ? '<' : '{');
+ printf ("0x");
+ for (i = 0; i < nbytes; i++)
+ printf ("%02x", bytes[i]);
+ putchar (is_utf8 ? '>' : '}');
+ }
+ else
+ {
+ if (unicode_display == unicode_highlight && isatty (1))
+ printf ("\x1B[31;47m"); /* Red. */
+
+ switch (nbytes)
+ {
+ case 2:
+ if (width_remaining < 6)
+ break;
+ printf ("\\u%02x%02x",
+ (bytes[0] & 0x1c) >> 2,
+ ((bytes[0] & 0x03) << 6) | (bytes[1] & 0x3f));
+ break;
+ case 3:
+ if (width_remaining < 6)
+ break;
+ printf ("\\u%02x%02x",
+ ((bytes[0] & 0x0f) << 4) | ((bytes[1] & 0x3c) >> 2),
+ ((bytes[1] & 0x03) << 6) | (bytes[2] & 0x3f));
+ break;
+ case 4:
+ if (width_remaining < 8)
+ break;
+ printf ("\\u%02x%02x%02x",
+ ((bytes[0] & 0x07) << 6) | ((bytes[1] & 0x3c) >> 2),
+ ((bytes[1] & 0x03) << 6) | ((bytes[2] & 0x3c) >> 2),
+ ((bytes[2] & 0x03) << 6) | (bytes[3] & 0x3f));
+
+ break;
+ default:
+ /* URG. */
+ break;
+ }
+
+ if (unicode_display == unicode_highlight && isatty (1))
+ printf ("\033[0m"); /* Default colour. */
+ }
+
+ if (bytes[nbytes - 1] == 0)
+ break;
}
else
{
return true;
}
+static bool
+slurp_relr_relocs (Filedata * filedata,
+ unsigned long relr_offset,
+ unsigned long relr_size,
+ bfd_vma ** relrsp,
+ unsigned long * nrelrsp)
+{
+ void *relrs;
+ size_t size = 0, nentries, i;
+ bfd_vma base = 0, addr, entry;
+
+ relrs = get_data (NULL, filedata, relr_offset, 1, relr_size,
+ _("RELR relocation data"));
+ if (!relrs)
+ return false;
+
+ if (is_32bit_elf)
+ nentries = relr_size / sizeof (Elf32_External_Relr);
+ else
+ nentries = relr_size / sizeof (Elf64_External_Relr);
+ for (i = 0; i < nentries; i++)
+ {
+ if (is_32bit_elf)
+ entry = BYTE_GET (((Elf32_External_Relr *)relrs)[i].r_data);
+ else
+ entry = BYTE_GET (((Elf64_External_Relr *)relrs)[i].r_data);
+ if ((entry & 1) == 0)
+ size++;
+ else
+ while ((entry >>= 1) != 0)
+ if ((entry & 1) == 1)
+ size++;
+ }
+
+ *relrsp = (bfd_vma *) xmalloc (size * sizeof (bfd_vma));
+ if (*relrsp == NULL)
+ {
+ free (relrs);
+ error (_("out of memory parsing relocs\n"));
+ return false;
+ }
+
+ size = 0;
+ for (i = 0; i < nentries; i++)
+ {
+ const bfd_vma entry_bytes = is_32bit_elf ? 4 : 8;
+
+ if (is_32bit_elf)
+ entry = BYTE_GET (((Elf32_External_Relr *)relrs)[i].r_data);
+ else
+ entry = BYTE_GET (((Elf64_External_Relr *)relrs)[i].r_data);
+ if ((entry & 1) == 0)
+ {
+ (*relrsp)[size++] = entry;
+ base = entry + entry_bytes;
+ }
+ else
+ {
+ for (addr = base; (entry >>= 1) != 0; addr += entry_bytes)
+ if ((entry & 1) != 0)
+ (*relrsp)[size++] = addr;
+ base += entry_bytes * (entry_bytes * CHAR_BIT - 1);
+ }
+ }
+
+ *nrelrsp = size;
+ free (relrs);
+ return true;
+}
+
/* Returns the reloc type extracted from the reloc info field. */
static unsigned int
unsigned long nsyms,
char * strtab,
unsigned long strtablen,
- int is_rela,
+ relocation_type rel_type,
bool is_dynsym)
{
unsigned long i;
Elf_Internal_Rela * rels;
bool res = true;
- if (is_rela == UNKNOWN)
- is_rela = guess_is_rela (filedata->file_header.e_machine);
+ if (rel_type == reltype_unknown)
+ rel_type = guess_is_rela (filedata->file_header.e_machine) ? reltype_rela : reltype_rel;
- if (is_rela)
+ if (rel_type == reltype_rela)
{
if (!slurp_rela_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
return false;
}
- else
+ else if (rel_type == reltype_rel)
{
if (!slurp_rel_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
return false;
}
+ else if (rel_type == reltype_relr)
+ {
+ bfd_vma * relrs;
+ const char *format
+ = is_32bit_elf ? "%08" BFD_VMA_FMT "x\n" : "%016" BFD_VMA_FMT "x\n";
+
+ if (!slurp_relr_relocs (filedata, rel_offset, rel_size, &relrs,
+ &rel_size))
+ return false;
+
+ printf (ngettext (" %lu offset\n", " %lu offsets\n", rel_size), rel_size);
+ for (i = 0; i < rel_size; i++)
+ printf (format, relrs[i]);
+ free (relrs);
+ return true;
+ }
if (is_32bit_elf)
{
- if (is_rela)
+ if (rel_type == reltype_rela)
{
if (do_wide)
printf (_(" Offset Info Type Sym. Value Symbol's Name + Addend\n"));
}
else
{
- if (is_rela)
+ if (rel_type == reltype_rela)
{
if (do_wide)
printf (_(" Offset Info Type Symbol's Value Symbol's Name + Addend\n"));
rtype = elf_loongarch_reloc_type (type);
break;
+ case EM_AMDGPU:
+ rtype = elf_amdgpu_reloc_type (type);
+ break;
}
if (rtype == NULL)
if (filedata->file_header.e_machine == EM_ALPHA
&& rtype != NULL
&& streq (rtype, "R_ALPHA_LITUSE")
- && is_rela)
+ && rel_type == reltype_rela)
{
switch (rels[i].r_addend)
{
if (ELF_ST_TYPE (psym->st_info) == STT_SECTION)
{
- if (psym->st_shndx < filedata->file_header.e_shnum)
+ if (psym->st_shndx < filedata->file_header.e_shnum
+ && filedata->section_headers != NULL)
sec_name = section_name_print (filedata,
filedata->section_headers
+ psym->st_shndx);
version_string);
}
- if (is_rela)
+ if (rel_type == reltype_rela)
{
bfd_vma off = rels[i].r_addend;
}
}
}
- else if (is_rela)
+ else if (rel_type == reltype_rela)
{
bfd_vma off = rels[i].r_addend;
}
}
+static const char *
+get_riscv_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_RISCV_VARIANT_CC: return "RISCV_VARIANT_CC";
+ default:
+ return NULL;
+ }
+}
+
static const char *
get_dynamic_type (Filedata * filedata, unsigned long type)
{
case EM_ALTERA_NIOS2:
result = get_nios2_dynamic_type (type);
break;
+ case EM_RISCV:
+ result = get_riscv_dynamic_type (type);
+ break;
default:
if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
result = get_solaris_dynamic_type (type);
r += snprintf (buf + r, size -r, ", L2C");
}
+static void
+decode_AMDGPU_machine_flags (Filedata *filedata, unsigned int e_flags,
+ char *buf)
+{
+ unsigned char *e_ident = filedata->file_header.e_ident;
+ unsigned char osabi = e_ident[EI_OSABI];
+ unsigned char abiversion = e_ident[EI_ABIVERSION];
+ unsigned int mach;
+
+ /* HSA OS ABI v2 used a different encoding, but we don't need to support it,
+ it has been deprecated for a while.
+
+ The PAL, MESA3D and NONE OS ABIs are not properly versioned, at the time
+ of writing, they use the same flags as HSA v3, so the code below uses that
+ assumption. */
+ if (osabi == ELFOSABI_AMDGPU_HSA && abiversion < ELFABIVERSION_AMDGPU_HSA_V3)
+ return;
+
+ mach = e_flags & EF_AMDGPU_MACH;
+ switch (mach)
+ {
+#define AMDGPU_CASE(code, string) \
+ case code: strcat (buf, ", " string); break;
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX600, "gfx600")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX601, "gfx601")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX700, "gfx700")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX701, "gfx701")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX702, "gfx702")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX703, "gfx703")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX704, "gfx704")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX801, "gfx801")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX802, "gfx802")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX803, "gfx803")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX810, "gfx810")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX900, "gfx900")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX902, "gfx902")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX904, "gfx904")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX906, "gfx906")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX908, "gfx908")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX909, "gfx909")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX90C, "gfx90c")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1010, "gfx1010")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1011, "gfx1011")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1012, "gfx1012")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1030, "gfx1030")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1031, "gfx1031")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1032, "gfx1032")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1033, "gfx1033")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX602, "gfx602")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX705, "gfx705")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX805, "gfx805")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1035, "gfx1035")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1034, "gfx1034")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX90A, "gfx90a")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX940, "gfx940")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1013, "gfx1013")
+ AMDGPU_CASE (EF_AMDGPU_MACH_AMDGCN_GFX1036, "gfx1036")
+ default:
+ sprintf (buf, _(", <unknown AMDGPU GPU type: %#x>"), mach);
+ break;
+#undef AMDGPU_CASE
+ }
+
+ buf += strlen (buf);
+ e_flags &= ~EF_AMDGPU_MACH;
+
+ if ((osabi == ELFOSABI_AMDGPU_HSA
+ && abiversion == ELFABIVERSION_AMDGPU_HSA_V3)
+ || osabi != ELFOSABI_AMDGPU_HSA)
+ {
+ /* For HSA v3 and other OS ABIs. */
+ if (e_flags & EF_AMDGPU_FEATURE_XNACK_V3)
+ {
+ strcat (buf, ", xnack on");
+ buf += strlen (buf);
+ e_flags &= ~EF_AMDGPU_FEATURE_XNACK_V3;
+ }
+
+ if (e_flags & EF_AMDGPU_FEATURE_SRAMECC_V3)
+ {
+ strcat (buf, ", sramecc on");
+ buf += strlen (buf);
+ e_flags &= ~EF_AMDGPU_FEATURE_SRAMECC_V3;
+ }
+ }
+ else
+ {
+ /* For HSA v4+. */
+ int xnack, sramecc;
+
+ xnack = e_flags & EF_AMDGPU_FEATURE_XNACK_V4;
+ switch (xnack)
+ {
+ case EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4:
+ break;
+
+ case EF_AMDGPU_FEATURE_XNACK_ANY_V4:
+ strcat (buf, ", xnack any");
+ break;
+
+ case EF_AMDGPU_FEATURE_XNACK_OFF_V4:
+ strcat (buf, ", xnack off");
+ break;
+
+ case EF_AMDGPU_FEATURE_XNACK_ON_V4:
+ strcat (buf, ", xnack on");
+ break;
+
+ default:
+ sprintf (buf, _(", <unknown xnack value: %#x>"), xnack);
+ break;
+ }
+
+ buf += strlen (buf);
+ e_flags &= ~EF_AMDGPU_FEATURE_XNACK_V4;
+
+ sramecc = e_flags & EF_AMDGPU_FEATURE_SRAMECC_V4;
+ switch (sramecc)
+ {
+ case EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4:
+ break;
+
+ case EF_AMDGPU_FEATURE_SRAMECC_ANY_V4:
+ strcat (buf, ", sramecc any");
+ break;
+
+ case EF_AMDGPU_FEATURE_SRAMECC_OFF_V4:
+ strcat (buf, ", sramecc off");
+ break;
+
+ case EF_AMDGPU_FEATURE_SRAMECC_ON_V4:
+ strcat (buf, ", sramecc on");
+ break;
+
+ default:
+ sprintf (buf, _(", <unknown sramecc value: %#x>"), sramecc);
+ break;
+ }
+
+ buf += strlen (buf);
+ e_flags &= ~EF_AMDGPU_FEATURE_SRAMECC_V4;
+ }
+
+ if (e_flags != 0)
+ sprintf (buf, _(", unknown flags bits: %#x"), e_flags);
+}
+
static char *
get_machine_flags (Filedata * filedata, unsigned e_flags, unsigned e_machine)
{
}
break;
+ case EM_AMDGPU:
+ decode_AMDGPU_machine_flags (filedata, e_flags, buf);
+ break;
+
case EM_CYGNUS_MEP:
switch (e_flags & EF_MEP_CPU_MASK)
{
if (osabi >= 64)
switch (filedata->file_header.e_machine)
{
+ case EM_AMDGPU:
+ switch (osabi)
+ {
+ case ELFOSABI_AMDGPU_HSA: return "AMD HSA";
+ case ELFOSABI_AMDGPU_PAL: return "AMD PAL";
+ case ELFOSABI_AMDGPU_MESA3D: return "AMD Mesa3D";
+ default:
+ break;
+ }
+ break;
+
case EM_ARM:
switch (osabi)
{
{"syms", no_argument, 0, 's'},
{"silent-truncation",no_argument, 0, 'T'},
{"section-details", no_argument, 0, 't'},
+ {"unicode", required_argument, NULL, 'U'},
{"unwind", no_argument, 0, 'u'},
{"version-info", no_argument, 0, 'V'},
{"version", no_argument, 0, 'v'},
Force base for symbol sizes. The options are \n\
mixed (the default), octal, decimal, hexadecimal.\n"));
fprintf (stream, _("\
- -C --demangle[=STYLE] Decode low-level symbol names into user-level names\n\
- The STYLE, if specified, can be `auto' (the default),\n\
- `gnu', `lucid', `arm', `hp', `edg', `gnu-v3', `java'\n\
- or `gnat'\n"));
+ -C --demangle[=STYLE] Decode mangled/processed symbol names\n"));
+ display_demangler_styles (stream, _("\
+ STYLE can be "));
fprintf (stream, _("\
--no-demangle Do not demangle low-level symbol names. (default)\n"));
fprintf (stream, _("\
--recurse-limit Enable a demangling recursion limit. (default)\n"));
fprintf (stream, _("\
--no-recurse-limit Disable a demangling recursion limit\n"));
+ fprintf (stream, _("\
+ -U[dlexhi] --unicode=[default|locale|escape|hex|highlight|invalid]\n\
+ Display unicode characters as determined by the current locale\n\
+ (default), escape sequences, \"<hex sequences>\", highlighted\n\
+ escape sequences, or treat them as invalid and display as\n\
+ \"{hex sequences}\"\n"));
fprintf (stream, _("\
-n --notes Display the core notes (if present)\n"));
fprintf (stream, _("\
-wN --debug-dump=no-follow-links\n\
Do not follow links to separate debug info files\n\
(default)\n"));
+#endif
+#if HAVE_LIBDEBUGINFOD
+ fprintf (stream, _("\
+ -wD --debug-dump=use-debuginfod\n\
+ When following links, also query debuginfod servers (default)\n"));
+ fprintf (stream, _("\
+ -wE --debug-dump=do-not-use-debuginfod\n\
+ When following links, do not query debuginfod servers\n"));
#endif
fprintf (stream, _("\
--dwarf-depth=N Do not display DIEs at depth N or greater\n"));
usage (stderr);
while ((c = getopt_long
- (argc, argv, "ACDHILNPR:STVWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
+ (argc, argv, "ACDHILNPR:STU:VWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
{
switch (c)
{
case 'P':
process_links = true;
do_follow_links = true;
+ dump_any_debugging = true;
break;
case 'x':
request_dump (dumpdata, HEX_DUMP);
break;
case 'w':
do_dump = true;
+ dump_any_debugging = true;
if (optarg == NULL)
{
do_debugging = true;
break;
case OPTION_DEBUG_DUMP:
do_dump = true;
+ dump_any_debugging = true;
if (optarg == NULL)
{
do_debugging = true;
/* Ignored for backward compatibility. */
break;
+ case 'U':
+ if (optarg == NULL)
+ error (_("Missing arg to -U/--unicode")); /* Can this happen ? */
+ else if (streq (optarg, "default") || streq (optarg, "d"))
+ unicode_display = unicode_default;
+ else if (streq (optarg, "locale") || streq (optarg, "l"))
+ unicode_display = unicode_locale;
+ else if (streq (optarg, "escape") || streq (optarg, "e"))
+ unicode_display = unicode_escape;
+ else if (streq (optarg, "invalid") || streq (optarg, "i"))
+ unicode_display = unicode_invalid;
+ else if (streq (optarg, "hex") || streq (optarg, "x"))
+ unicode_display = unicode_hex;
+ else if (streq (optarg, "highlight") || streq (optarg, "h"))
+ unicode_display = unicode_highlight;
+ else
+ error (_("invalid argument to -U/--unicode: %s"), optarg);
+ break;
+
case OPTION_SYM_BASE:
sym_base = 0;
if (optarg != NULL)
if (filedata->section_headers != NULL
&& header->e_phnum == PN_XNUM
&& filedata->section_headers[0].sh_info != 0)
- {
- header->e_phnum = filedata->section_headers[0].sh_info;
- printf (" (%u)", header->e_phnum);
- }
+ printf (" (%u)", filedata->section_headers[0].sh_info);
putc ('\n', stdout);
printf (_(" Size of section headers: %u (bytes)\n"),
header->e_shentsize);
{
if (header->e_phnum == PN_XNUM
&& filedata->section_headers[0].sh_info != 0)
- header->e_phnum = filedata->section_headers[0].sh_info;
+ {
+ /* Throw away any cached read of PN_XNUM headers. */
+ free (filedata->program_headers);
+ filedata->program_headers = NULL;
+ header->e_phnum = filedata->section_headers[0].sh_info;
+ }
if (header->e_shnum == SHN_UNDEF)
header->e_shnum = filedata->section_headers[0].sh_size;
if (header->e_shstrndx == (SHN_XINDEX & 0xffff))
warn (_("Section '%s': zero-sized relocation section\n"), name);
break;
+ case SHT_RELR:
+ CHECK_ENTSIZE (section, i, Relr);
+ break;
+
case SHT_NOTE:
case SHT_PROGBITS:
/* Having a zero sized section is not illegal according to the
const char * name;
int reloc;
int size;
- int rela;
+ relocation_type rel_type;
}
dynamic_relocations [] =
{
- { "REL", DT_REL, DT_RELSZ, false },
- { "RELA", DT_RELA, DT_RELASZ, true },
- { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN }
+ { "REL", DT_REL, DT_RELSZ, reltype_rel },
+ { "RELA", DT_RELA, DT_RELASZ, reltype_rela },
+ { "RELR", DT_RELR, DT_RELRSZ, reltype_relr },
+ { "PLT", DT_JMPREL, DT_PLTRELSZ, reltype_unknown }
};
/* Process the reloc section. */
if (do_using_dynamic)
{
- int is_rela;
+ relocation_type rel_type;
const char * name;
bool has_dynamic_reloc;
unsigned int i;
for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++)
{
- is_rela = dynamic_relocations [i].rela;
+ rel_type = dynamic_relocations [i].rel_type;
name = dynamic_relocations [i].name;
rel_size = filedata->dynamic_info[dynamic_relocations [i].size];
rel_offset = filedata->dynamic_info[dynamic_relocations [i].reloc];
if (rel_size)
has_dynamic_reloc = true;
- if (is_rela == UNKNOWN)
+ if (rel_type == reltype_unknown)
{
if (dynamic_relocations [i].reloc == DT_JMPREL)
switch (filedata->dynamic_info[DT_PLTREL])
{
case DT_REL:
- is_rela = false;
+ rel_type = reltype_rel;
break;
case DT_RELA:
- is_rela = true;
+ rel_type = reltype_rela;
break;
}
}
filedata->num_dynamic_syms,
filedata->dynamic_strings,
filedata->dynamic_strings_length,
- is_rela, true /* is_dynamic */);
+ rel_type, true /* is_dynamic */);
}
}
i++, section++)
{
if ( section->sh_type != SHT_RELA
- && section->sh_type != SHT_REL)
+ && section->sh_type != SHT_REL
+ && section->sh_type != SHT_RELR)
continue;
rel_offset = section->sh_offset;
if (rel_size)
{
- int is_rela;
+ relocation_type rel_type;
unsigned long num_rela;
if (filedata->is_separate)
num_rela),
rel_offset, num_rela);
- is_rela = section->sh_type == SHT_RELA;
+ rel_type = section->sh_type == SHT_RELA ? reltype_rela :
+ section->sh_type == SHT_REL ? reltype_rel : reltype_relr;
if (section->sh_link != 0
&& section->sh_link < filedata->file_header.e_shnum)
dump_relocations (filedata, rel_offset, rel_size,
symtab, nsyms, strtab, strtablen,
- is_rela,
+ rel_type,
symsec->sh_type == SHT_DYNSYM);
free (strtab);
free (symtab);
}
else
dump_relocations (filedata, rel_offset, rel_size,
- NULL, 0, NULL, 0, is_rela,
- false /* is_dynamic */);
+ NULL, 0, NULL, 0, rel_type, false /* is_dynamic */);
found = true;
}
filedata->file_name,
filedata->dynamic_addr,
(unsigned long) filedata->dynamic_nent);
- else
- printf (ngettext ("\nDynamic section at offset 0x%lx contains %lu entry:\n",
- "\nDynamic section at offset 0x%lx contains %lu entries:\n",
- (unsigned long) filedata->dynamic_nent),
- filedata->dynamic_addr,
- (unsigned long) filedata->dynamic_nent);
+ else
+ printf (ngettext ("\nDynamic section at offset 0x%lx contains %lu entry:\n",
+ "\nDynamic section at offset 0x%lx contains %lu entries:\n",
+ (unsigned long) filedata->dynamic_nent),
+ filedata->dynamic_addr,
+ (unsigned long) filedata->dynamic_nent);
}
if (do_dynamic)
printf (_(" Tag Type Name/Value\n"));
case DT_RPATH :
case DT_SYMBOLIC:
case DT_REL :
+ case DT_RELR :
case DT_DEBUG :
case DT_TEXTREL :
case DT_JMPREL :
case DT_STRSZ :
case DT_RELSZ :
case DT_RELAENT :
+ case DT_RELRENT :
+ case DT_RELRSZ :
case DT_SYMENT :
case DT_RELENT :
filedata->dynamic_info[entry->d_tag] = entry->d_un.d_val;
case DT_PLTPADSZ:
case DT_MOVEENT :
case DT_MOVESZ :
- case DT_RELRENT :
- case DT_RELRSZ :
case DT_PREINIT_ARRAYSZ:
case DT_INIT_ARRAYSZ:
case DT_FINI_ARRAYSZ:
return NULL;
}
+static const char *
+get_riscv_symbol_other (unsigned int other)
+{
+ static char buf[32];
+ buf[0] = 0;
+
+ if (other & STO_RISCV_VARIANT_CC)
+ {
+ strcat (buf, _(" VARIANT_CC"));
+ other &= ~STO_RISCV_VARIANT_CC;
+ }
+
+ if (other != 0)
+ snprintf (buf, sizeof buf, " %x", other);
+
+
+ if (buf[0] != 0)
+ return buf + 1;
+ else
+ return buf;
+}
+
static const char *
get_symbol_other (Filedata * filedata, unsigned int other)
{
case EM_PPC64:
result = get_ppc64_symbol_other (other);
break;
+ case EM_RISCV:
+ result = get_riscv_symbol_other (other);
+ break;
default:
result = NULL;
break;
if (ELF_ST_TYPE (psym->st_info) == STT_SECTION
&& psym->st_shndx < filedata->file_header.e_shnum
+ && filedata->section_headers != NULL
&& psym->st_name == 0)
{
is_valid
case EM_MT:
return reloc_type == 2; /* R_MT_32. */
case EM_NDS32:
- return reloc_type == 20; /* R_NDS32_RELA. */
+ return reloc_type == 20; /* R_NDS32_32_RELA. */
case EM_ALTERA_NIOS2:
return reloc_type == 12; /* R_NIOS2_BFD_RELOC_32. */
case EM_NIOS32:
case EM_MSP430_OLD:
return reloc_type == 5; /* R_MSP430_16_BYTE. */
case EM_NDS32:
- return reloc_type == 19; /* R_NDS32_RELA. */
+ return reloc_type == 19; /* R_NDS32_16_RELA. */
case EM_ALTERA_NIOS2:
return reloc_type == 13; /* R_NIOS2_BFD_RELOC_16. */
case EM_NIOS32:
case EM_METAG:
return reloc_type == 3; /* R_METAG_NONE. */
case EM_NDS32:
- return (reloc_type == 0 /* R_XTENSA_NONE. */
- || reloc_type == 204 /* R_NDS32_DIFF8. */
- || reloc_type == 205 /* R_NDS32_DIFF16. */
- || reloc_type == 206 /* R_NDS32_DIFF32. */
- || reloc_type == 207 /* R_NDS32_ULEB128. */);
+ return (reloc_type == 0 /* R_NDS32_NONE. */
+ || reloc_type == 205 /* R_NDS32_DIFF8. */
+ || reloc_type == 206 /* R_NDS32_DIFF16. */
+ || reloc_type == 207 /* R_NDS32_DIFF32. */
+ || reloc_type == 208 /* R_NDS32_DIFF_ULEB128. */);
case EM_TI_PRU:
return (reloc_type == 0 /* R_PRU_NONE. */
|| reloc_type == 65 /* R_PRU_DIFF8. */
Elf_Internal_Shdr * sec;
Filedata * filedata = (Filedata *) data;
+ if (!dump_any_debugging)
+ return false;
+
/* Without section headers we cannot find any sections. */
if (filedata->section_headers == NULL)
return false;
Elf_External_Options * eopt;
size_t offset;
int cnt;
- sect = filedata->section_headers;
/* Find the section header so that we get the size. */
sect = find_section_by_type (filedata, SHT_MIPS_OPTIONS);
return _("NT_ARM_HW_BREAK (AArch hardware breakpoint registers)");
case NT_ARM_HW_WATCH:
return _("NT_ARM_HW_WATCH (AArch hardware watchpoint registers)");
+ case NT_ARM_SYSTEM_CALL:
+ return _("NT_ARM_SYSTEM_CALL (AArch system call number)");
case NT_ARM_SVE:
return _("NT_ARM_SVE (AArch SVE registers)");
case NT_ARM_PAC_MASK:
return _("func");
case NT_GO_BUILDID:
return _("GO BUILDID");
+ case FDO_PACKAGING_METADATA:
+ return _("FDO_PACKAGING_METADATA");
default:
break;
}
}
}
+static const char *
+get_amdgpu_elf_note_type (unsigned int e_type)
+{
+ switch (e_type)
+ {
+ case NT_AMDGPU_METADATA:
+ return _("NT_AMDGPU_METADATA (code object metadata)");
+ default:
+ {
+ static char buf[64];
+ snprintf (buf, sizeof (buf), _("Unknown note type: (0x%08x)"), e_type);
+ return buf;
+ }
+ }
+}
+
static void
decode_x86_isa (unsigned int bitmask)
{
return _("NT_PROCSTAT_AUXV (auxv data)");
case NT_FREEBSD_PTLWPINFO:
return _("NT_PTLWPINFO (ptrace_lwpinfo structure)");
+ case NT_FREEBSD_X86_SEGBASES:
+ return _("NT_X86_SEGBASES (x86 segment base registers)");
}
return get_note_type (filedata, e_type);
}
return false;
}
+static bool
+print_fdo_note (Elf_Internal_Note * pnote)
+{
+ if (pnote->descsz > 0 && pnote->type == FDO_PACKAGING_METADATA)
+ {
+ printf (_(" Packaging Metadata: %.*s\n"), (int) pnote->descsz, pnote->descdata);
+ return true;
+ }
+ return false;
+}
+
static const char *
get_ia64_vms_note_type (unsigned e_type)
{
return true;
}
+/* Print the contents of PNOTE as hex. */
+
+static void
+print_note_contents_hex (Elf_Internal_Note *pnote)
+{
+ if (pnote->descsz)
+ {
+ unsigned long i;
+
+ printf (_(" description data: "));
+ for (i = 0; i < pnote->descsz; i++)
+ printf ("%02x ", pnote->descdata[i] & 0xff);
+ if (!do_wide)
+ printf ("\n");
+ }
+
+ if (do_wide)
+ printf ("\n");
+}
+
+#if defined HAVE_MSGPACK
+
+static void
+print_indents (int n)
+{
+ printf (" ");
+
+ for (int i = 0; i < n; i++)
+ printf (" ");
+}
+
+/* Print OBJ in human-readable form. */
+
+static void
+dump_msgpack_obj (const msgpack_object *obj, int indent)
+{
+ switch (obj->type)
+ {
+ case MSGPACK_OBJECT_NIL:
+ printf ("(nil)");
+ break;
+
+ case MSGPACK_OBJECT_BOOLEAN:
+ printf ("%s", obj->via.boolean ? "true" : "false");
+ break;
+
+ case MSGPACK_OBJECT_POSITIVE_INTEGER:
+ printf ("%" PRIu64, obj->via.u64);
+ break;
+
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+ printf ("%" PRIi64, obj->via.i64);
+ break;
+
+ case MSGPACK_OBJECT_FLOAT32:
+ case MSGPACK_OBJECT_FLOAT64:
+ printf ("%f", obj->via.f64);
+ break;
+
+ case MSGPACK_OBJECT_STR:
+ printf ("\"%.*s\"", obj->via.str.size, obj->via.str.ptr);
+ break;
+
+ case MSGPACK_OBJECT_ARRAY:
+ {
+ const msgpack_object_array *array = &obj->via.array;
+
+ printf ("[\n");
+ ++indent;
+
+ for (uint32_t i = 0; i < array->size; ++i)
+ {
+ const msgpack_object *item = &array->ptr[i];
+
+ print_indents (indent);
+ dump_msgpack_obj (item, indent);
+ printf (",\n");
+ }
+
+ --indent;
+ print_indents (indent);
+ printf ("]");
+ break;
+ }
+ break;
+
+ case MSGPACK_OBJECT_MAP:
+ {
+ const msgpack_object_map *map = &obj->via.map;
+
+ printf ("{\n");
+ ++indent;
+
+ for (uint32_t i = 0; i < map->size; ++i)
+ {
+ const msgpack_object_kv *kv = &map->ptr[i];
+ const msgpack_object *key = &kv->key;
+ const msgpack_object *val = &kv->val;
+
+ print_indents (indent);
+ dump_msgpack_obj (key, indent);
+ printf (": ");
+ dump_msgpack_obj (val, indent);
+
+ printf (",\n");
+ }
+
+ --indent;
+ print_indents (indent);
+ printf ("}");
+
+ break;
+ }
+
+ case MSGPACK_OBJECT_BIN:
+ printf ("(bin)");
+ break;
+
+ case MSGPACK_OBJECT_EXT:
+ printf ("(ext)");
+ break;
+ }
+}
+
+static void
+dump_msgpack (const msgpack_unpacked *msg)
+{
+ print_indents (0);
+ dump_msgpack_obj (&msg->data, 0);
+ printf ("\n");
+}
+
+#endif /* defined HAVE_MSGPACK */
+
+static bool
+print_amdgpu_note (Elf_Internal_Note *pnote)
+{
+#if defined HAVE_MSGPACK
+ /* If msgpack is available, decode and dump the note's content. */
+ bool ret;
+ msgpack_unpacked msg;
+ msgpack_unpack_return msgpack_ret;
+
+ assert (pnote->type == NT_AMDGPU_METADATA);
+
+ msgpack_unpacked_init (&msg);
+ msgpack_ret = msgpack_unpack_next (&msg, pnote->descdata, pnote->descsz,
+ NULL);
+
+ switch (msgpack_ret)
+ {
+ case MSGPACK_UNPACK_SUCCESS:
+ dump_msgpack (&msg);
+ ret = true;
+ break;
+
+ default:
+ error (_("failed to unpack msgpack contents in NT_AMDGPU_METADATA note"));
+ ret = false;
+ break;
+ }
+
+ msgpack_unpacked_destroy (&msg);
+ return ret;
+#else
+ /* msgpack is not available, dump contents as hex. */
+ print_note_contents_hex (pnote);
+ return true;
+#endif
+}
+
/* Note that by the ELF standard, the name field is already null byte
terminated, and namesz includes the terminating null byte.
I.E. the value of namesz for the name "FSF" is 4.
/* GNU-specific object file notes. */
nt = get_gnu_elf_note_type (pnote->type);
+ else if (startswith (pnote->namedata, "AMDGPU"))
+ /* AMDGPU-specific object file notes. */
+ nt = get_amdgpu_elf_note_type (pnote->type);
+
else if (startswith (pnote->namedata, "FreeBSD"))
/* FreeBSD-specific core file notes. */
nt = get_freebsd_elfcore_note_type (filedata, pnote->type);
return print_stapsdt_note (pnote);
else if (startswith (pnote->namedata, "CORE"))
return print_core_note (pnote);
+ else if (startswith (pnote->namedata, "FDO"))
+ return print_fdo_note (pnote);
else if (((startswith (pnote->namedata, "GA")
&& strchr ("*$!+", pnote->namedata[2]) != NULL)
|| strchr ("*$!+", pnote->namedata[0]) != NULL)
&& (pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN
|| pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC))
return print_gnu_build_attribute_description (pnote, filedata);
+ else if (startswith (pnote->namedata, "AMDGPU")
+ && pnote->type == NT_AMDGPU_METADATA)
+ return print_amdgpu_note (pnote);
- if (pnote->descsz)
- {
- unsigned long i;
-
- printf (_(" description data: "));
- for (i = 0; i < pnote->descsz; i++)
- printf ("%02x ", pnote->descdata[i] & 0xff);
- if (!do_wide)
- printf ("\n");
- }
-
- if (do_wide)
- printf ("\n");
-
+ print_note_contents_hex (pnote);
return true;
}