LCOV - code coverage report
Current view: top level - src - readelf.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 2941 4292 68.5 %
Date: 2017-08-02 15:24:56 Functions: 100 108 92.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Print information from ELF file in human-readable form.
       2             :    Copyright (C) 1999-2016 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             :    Written by Ulrich Drepper <drepper@redhat.com>, 1999.
       5             : 
       6             :    This file is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    elfutils is distributed in the hope that it will be useful, but
      12             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      18             : 
      19             : #ifdef HAVE_CONFIG_H
      20             : # include <config.h>
      21             : #endif
      22             : 
      23             : #include <argp.h>
      24             : #include <assert.h>
      25             : #include <ctype.h>
      26             : #include <dwarf.h>
      27             : #include <errno.h>
      28             : #include <error.h>
      29             : #include <fcntl.h>
      30             : #include <gelf.h>
      31             : #include <inttypes.h>
      32             : #include <langinfo.h>
      33             : #include <libdw.h>
      34             : #include <libdwfl.h>
      35             : #include <libintl.h>
      36             : #include <locale.h>
      37             : #include <stdarg.h>
      38             : #include <stdbool.h>
      39             : #include <stdlib.h>
      40             : #include <string.h>
      41             : #include <strings.h>
      42             : #include <time.h>
      43             : #include <unistd.h>
      44             : #include <sys/stat.h>
      45             : #include <signal.h>
      46             : 
      47             : #include <libeu.h>
      48             : #include <system.h>
      49             : #include <printversion.h>
      50             : #include "../libelf/libelfP.h"
      51             : #include "../libelf/common.h"
      52             : #include "../libebl/libeblP.h"
      53             : #include "../libdwelf/libdwelf.h"
      54             : #include "../libdw/libdwP.h"
      55             : #include "../libdwfl/libdwflP.h"
      56             : #include "../libdw/memory-access.h"
      57             : 
      58             : #include "../libdw/known-dwarf.h"
      59             : 
      60             : 
      61             : /* Name and version of program.  */
      62             : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
      63             : 
      64             : /* Bug report address.  */
      65             : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
      66             : 
      67             : /* argp key value for --elf-section, non-ascii.  */
      68             : #define ELF_INPUT_SECTION 256
      69             : 
      70             : /* Definitions of arguments for argp functions.  */
      71             : static const struct argp_option options[] =
      72             : {
      73             :   { NULL, 0, NULL, 0, N_("ELF input selection:"), 0 },
      74             :   { "elf-section", ELF_INPUT_SECTION, "SECTION", OPTION_ARG_OPTIONAL,
      75             :     N_("Use the named SECTION (default .gnu_debugdata) as (compressed) ELF "
      76             :        "input data"), 0 },
      77             :   { NULL, 0, NULL, 0, N_("ELF output selection:"), 0 },
      78             :   { "all", 'a', NULL, 0,
      79             :     N_("All these plus -p .strtab -p .dynstr -p .comment"), 0 },
      80             :   { "dynamic", 'd', NULL, 0, N_("Display the dynamic segment"), 0 },
      81             :   { "file-header", 'h', NULL, 0, N_("Display the ELF file header"), 0 },
      82             :   { "histogram", 'I', NULL, 0,
      83             :     N_("Display histogram of bucket list lengths"), 0 },
      84             :   { "program-headers", 'l', NULL, 0, N_("Display the program headers"), 0 },
      85             :   { "segments", 'l', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
      86             :   { "relocs", 'r', NULL, 0, N_("Display relocations"), 0 },
      87             :   { "section-headers", 'S', NULL, 0, N_("Display the sections' headers"), 0 },
      88             :   { "sections", 'S', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
      89             :   { "symbols", 's', "SECTION", OPTION_ARG_OPTIONAL,
      90             :     N_("Display the symbol table sections"), 0 },
      91             :   { "version-info", 'V', NULL, 0, N_("Display versioning information"), 0 },
      92             :   { "notes", 'n', NULL, 0, N_("Display the ELF notes"), 0 },
      93             :   { "arch-specific", 'A', NULL, 0,
      94             :     N_("Display architecture specific information, if any"), 0 },
      95             :   { "exception", 'e', NULL, 0,
      96             :     N_("Display sections for exception handling"), 0 },
      97             : 
      98             :   { NULL, 0, NULL, 0, N_("Additional output selection:"), 0 },
      99             :   { "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL,
     100             :     N_("Display DWARF section content.  SECTION can be one of abbrev, "
     101             :        "aranges, decodedaranges, frame, gdb_index, info, loc, line, "
     102             :        "decodedline, ranges, pubnames, str, macinfo, macro or exception"), 0 },
     103             :   { "hex-dump", 'x', "SECTION", 0,
     104             :     N_("Dump the uninterpreted contents of SECTION, by number or name"), 0 },
     105             :   { "strings", 'p', "SECTION", OPTION_ARG_OPTIONAL,
     106             :     N_("Print string contents of sections"), 0 },
     107             :   { "string-dump", 'p', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
     108             :   { "archive-index", 'c', NULL, 0,
     109             :     N_("Display the symbol index of an archive"), 0 },
     110             : 
     111             :   { NULL, 0, NULL, 0, N_("Output control:"), 0 },
     112             :   { "numeric-addresses", 'N', NULL, 0,
     113             :     N_("Do not find symbol names for addresses in DWARF data"), 0 },
     114             :   { "unresolved-address-offsets", 'U', NULL, 0,
     115             :     N_("Display just offsets instead of resolving values to addresses in DWARF data"), 0 },
     116             :   { "wide", 'W', NULL, 0,
     117             :     N_("Ignored for compatibility (lines always wide)"), 0 },
     118             :   { "decompress", 'z', NULL, 0,
     119             :     N_("Show compression information for compressed sections (when used with -S); decompress section before dumping data (when used with -p or -x)"), 0 },
     120             :   { NULL, 0, NULL, 0, NULL, 0 }
     121             : };
     122             : 
     123             : /* Short description of program.  */
     124             : static const char doc[] = N_("\
     125             : Print information from ELF file in human-readable form.");
     126             : 
     127             : /* Strings for arguments in help texts.  */
     128             : static const char args_doc[] = N_("FILE...");
     129             : 
     130             : /* Prototype for option handler.  */
     131             : static error_t parse_opt (int key, char *arg, struct argp_state *state);
     132             : 
     133             : /* Data structure to communicate with argp functions.  */
     134             : static struct argp argp =
     135             : {
     136             :   options, parse_opt, args_doc, doc, NULL, NULL, NULL
     137             : };
     138             : 
     139             : /* If non-null, the section from which we should read to (compressed) ELF.  */
     140             : static const char *elf_input_section = NULL;
     141             : 
     142             : /* Flags set by the option controlling the output.  */
     143             : 
     144             : /* True if dynamic segment should be printed.  */
     145             : static bool print_dynamic_table;
     146             : 
     147             : /* True if the file header should be printed.  */
     148             : static bool print_file_header;
     149             : 
     150             : /* True if the program headers should be printed.  */
     151             : static bool print_program_header;
     152             : 
     153             : /* True if relocations should be printed.  */
     154             : static bool print_relocations;
     155             : 
     156             : /* True if the section headers should be printed.  */
     157             : static bool print_section_header;
     158             : 
     159             : /* True if the symbol table should be printed.  */
     160             : static bool print_symbol_table;
     161             : 
     162             : /* A specific section name, or NULL to print all symbol tables.  */
     163             : static char *symbol_table_section;
     164             : 
     165             : /* True if the version information should be printed.  */
     166             : static bool print_version_info;
     167             : 
     168             : /* True if section groups should be printed.  */
     169             : static bool print_section_groups;
     170             : 
     171             : /* True if bucket list length histogram should be printed.  */
     172             : static bool print_histogram;
     173             : 
     174             : /* True if the architecture specific data should be printed.  */
     175             : static bool print_arch;
     176             : 
     177             : /* True if note section content should be printed.  */
     178             : static bool print_notes;
     179             : 
     180             : /* True if SHF_STRINGS section content should be printed.  */
     181             : static bool print_string_sections;
     182             : 
     183             : /* True if archive index should be printed.  */
     184             : static bool print_archive_index;
     185             : 
     186             : /* True if any of the control options except print_archive_index is set.  */
     187             : static bool any_control_option;
     188             : 
     189             : /* True if we should print addresses from DWARF in symbolic form.  */
     190             : static bool print_address_names = true;
     191             : 
     192             : /* True if we should print raw values instead of relativized addresses.  */
     193             : static bool print_unresolved_addresses = false;
     194             : 
     195             : /* True if we should print the .debug_aranges section using libdw.  */
     196             : static bool decodedaranges = false;
     197             : 
     198             : /* True if we should print the .debug_aranges section using libdw.  */
     199             : static bool decodedline = false;
     200             : 
     201             : /* True if we want to show more information about compressed sections.  */
     202             : static bool print_decompress = false;
     203             : 
     204             : /* Select printing of debugging sections.  */
     205             : static enum section_e
     206             : {
     207             :   section_abbrev = 1,           /* .debug_abbrev  */
     208             :   section_aranges = 2,          /* .debug_aranges  */
     209             :   section_frame = 4,            /* .debug_frame or .eh_frame & al.  */
     210             :   section_info = 8,             /* .debug_info, .debug_types  */
     211             :   section_types = section_info,
     212             :   section_line = 16,            /* .debug_line  */
     213             :   section_loc = 32,             /* .debug_loc  */
     214             :   section_pubnames = 64,        /* .debug_pubnames  */
     215             :   section_str = 128,            /* .debug_str  */
     216             :   section_macinfo = 256,        /* .debug_macinfo  */
     217             :   section_ranges = 512,         /* .debug_ranges  */
     218             :   section_exception = 1024,     /* .eh_frame & al.  */
     219             :   section_gdb_index = 2048,     /* .gdb_index  */
     220             :   section_macro = 4096,         /* .debug_macro  */
     221             :   section_all = (section_abbrev | section_aranges | section_frame
     222             :                  | section_info | section_line | section_loc
     223             :                  | section_pubnames | section_str | section_macinfo
     224             :                  | section_ranges | section_exception | section_gdb_index
     225             :                  | section_macro)
     226             : } print_debug_sections, implicit_debug_sections;
     227             : 
     228             : /* Select hex dumping of sections.  */
     229             : static struct section_argument *dump_data_sections;
     230             : static struct section_argument **dump_data_sections_tail = &dump_data_sections;
     231             : 
     232             : /* Select string dumping of sections.  */
     233             : static struct section_argument *string_sections;
     234             : static struct section_argument **string_sections_tail = &string_sections;
     235             : 
     236             : struct section_argument
     237             : {
     238             :   struct section_argument *next;
     239             :   const char *arg;
     240             :   bool implicit;
     241             : };
     242             : 
     243             : /* Numbers of sections and program headers in the file.  */
     244             : static size_t shnum;
     245             : static size_t phnum;
     246             : 
     247             : 
     248             : /* Declarations of local functions.  */
     249             : static void process_file (int fd, const char *fname, bool only_one);
     250             : static void process_elf_file (Dwfl_Module *dwflmod, int fd);
     251             : static void print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr);
     252             : static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
     253             : static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
     254             : static void print_scngrp (Ebl *ebl);
     255             : static void print_dynamic (Ebl *ebl);
     256             : static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
     257             : static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
     258             :                                GElf_Shdr *shdr);
     259             : static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
     260             :                                 GElf_Shdr *shdr);
     261             : static void print_symtab (Ebl *ebl, int type);
     262             : static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
     263             : static void print_verinfo (Ebl *ebl);
     264             : static void handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
     265             : static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
     266             : static void handle_versym (Ebl *ebl, Elf_Scn *scn,
     267             :                            GElf_Shdr *shdr);
     268             : static void print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr);
     269             : static void handle_hash (Ebl *ebl);
     270             : static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr);
     271             : static void print_liblist (Ebl *ebl);
     272             : static void print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr);
     273             : static void dump_data (Ebl *ebl);
     274             : static void dump_strings (Ebl *ebl);
     275             : static void print_strings (Ebl *ebl);
     276             : static void dump_archive_index (Elf *, const char *);
     277             : 
     278             : 
     279             : int
     280         181 : main (int argc, char *argv[])
     281             : {
     282             :   /* Set locale.  */
     283         181 :   setlocale (LC_ALL, "");
     284             : 
     285             :   /* Initialize the message catalog.  */
     286         181 :   textdomain (PACKAGE_TARNAME);
     287             : 
     288             :   /* Parse and process arguments.  */
     289             :   int remaining;
     290         181 :   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
     291             : 
     292             :   /* Before we start tell the ELF library which version we are using.  */
     293         181 :   elf_version (EV_CURRENT);
     294             : 
     295             :   /* Now process all the files given at the command line.  */
     296         181 :   bool only_one = remaining + 1 == argc;
     297             :   do
     298             :     {
     299             :       /* Open the file.  */
     300         364 :       int fd = open (argv[remaining], O_RDONLY);
     301         182 :       if (fd == -1)
     302             :         {
     303           0 :           error (0, errno, gettext ("cannot open input file"));
     304           0 :           continue;
     305             :         }
     306             : 
     307         182 :       process_file (fd, argv[remaining], only_one);
     308             : 
     309         182 :       close (fd);
     310             :     }
     311         182 :   while (++remaining < argc);
     312             : 
     313         181 :   return error_message_count != 0;
     314             : }
     315             : 
     316             : 
     317             : /* Handle program arguments.  */
     318             : static error_t
     319        1138 : parse_opt (int key, char *arg,
     320             :            struct argp_state *state __attribute__ ((unused)))
     321             : {
     322         102 :   void add_dump_section (const char *name, bool implicit)
     323             :   {
     324         102 :     struct section_argument *a = xmalloc (sizeof *a);
     325         102 :     a->arg = name;
     326         102 :     a->next = NULL;
     327         102 :     a->implicit = implicit;
     328         102 :     struct section_argument ***tailp
     329         102 :       = key == 'x' ? &dump_data_sections_tail : &string_sections_tail;
     330         102 :     **tailp = a;
     331         102 :     *tailp = &a->next;
     332         102 :   }
     333             : 
     334        1138 :   switch (key)
     335             :     {
     336          32 :     case 'a':
     337          32 :       print_file_header = true;
     338          32 :       print_program_header = true;
     339          32 :       print_relocations = true;
     340          32 :       print_section_header = true;
     341          32 :       print_symbol_table = true;
     342          32 :       print_version_info = true;
     343          32 :       print_dynamic_table = true;
     344          32 :       print_section_groups = true;
     345          32 :       print_histogram = true;
     346          32 :       print_arch = true;
     347          32 :       print_notes = true;
     348          32 :       implicit_debug_sections |= section_exception;
     349          32 :       add_dump_section (".strtab", true);
     350          32 :       add_dump_section (".dynstr", true);
     351          32 :       add_dump_section (".comment", true);
     352          32 :       any_control_option = true;
     353          32 :       break;
     354           4 :     case 'A':
     355           4 :       print_arch = true;
     356           4 :       any_control_option = true;
     357           4 :       break;
     358           2 :     case 'd':
     359           2 :       print_dynamic_table = true;
     360           2 :       any_control_option = true;
     361           2 :       break;
     362           0 :     case 'e':
     363           0 :       print_debug_sections |= section_exception;
     364           0 :       any_control_option = true;
     365           0 :       break;
     366           0 :     case 'g':
     367           0 :       print_section_groups = true;
     368           0 :       any_control_option = true;
     369           0 :       break;
     370           0 :     case 'h':
     371           0 :       print_file_header = true;
     372           0 :       any_control_option = true;
     373           0 :       break;
     374           0 :     case 'I':
     375           0 :       print_histogram = true;
     376           0 :       any_control_option = true;
     377           0 :       break;
     378           0 :     case 'l':
     379           0 :       print_program_header = true;
     380           0 :       any_control_option = true;
     381           0 :       break;
     382          10 :     case 'n':
     383          10 :       print_notes = true;
     384          10 :       any_control_option = true;
     385          10 :       break;
     386           1 :     case 'r':
     387           1 :       print_relocations = true;
     388           1 :       any_control_option = true;
     389           1 :      break;
     390          54 :     case 'S':
     391          54 :       print_section_header = true;
     392          54 :       any_control_option = true;
     393          54 :       break;
     394          14 :     case 's':
     395          14 :       print_symbol_table = true;
     396          14 :       any_control_option = true;
     397          14 :       symbol_table_section = arg;
     398          14 :       break;
     399           0 :     case 'V':
     400           0 :       print_version_info = true;
     401           0 :       any_control_option = true;
     402           0 :       break;
     403           2 :     case 'c':
     404           2 :       print_archive_index = true;
     405           2 :       break;
     406          71 :     case 'w':
     407          71 :       if (arg == NULL)
     408          33 :         print_debug_sections = section_all;
     409          38 :       else if (strcmp (arg, "abbrev") == 0)
     410           0 :         print_debug_sections |= section_abbrev;
     411          38 :       else if (strcmp (arg, "aranges") == 0)
     412           3 :         print_debug_sections |= section_aranges;
     413          35 :       else if (strcmp (arg, "decodedaranges") == 0)
     414             :         {
     415           1 :           print_debug_sections |= section_aranges;
     416           1 :           decodedaranges = true;
     417             :         }
     418          34 :       else if (strcmp (arg, "ranges") == 0)
     419             :         {
     420           5 :           print_debug_sections |= section_ranges;
     421           5 :           implicit_debug_sections |= section_info;
     422             :         }
     423          29 :       else if (strcmp (arg, "frame") == 0 || strcmp (arg, "frames") == 0)
     424           2 :         print_debug_sections |= section_frame;
     425          27 :       else if (strcmp (arg, "info") == 0)
     426          10 :         print_debug_sections |= section_info;
     427          17 :       else if (strcmp (arg, "loc") == 0)
     428             :         {
     429           8 :           print_debug_sections |= section_loc;
     430           8 :           implicit_debug_sections |= section_info;
     431             :         }
     432           9 :       else if (strcmp (arg, "line") == 0)
     433           3 :         print_debug_sections |= section_line;
     434           6 :       else if (strcmp (arg, "decodedline") == 0)
     435             :         {
     436           1 :           print_debug_sections |= section_line;
     437           1 :           decodedline = true;
     438             :         }
     439           5 :       else if (strcmp (arg, "pubnames") == 0)
     440           0 :         print_debug_sections |= section_pubnames;
     441           5 :       else if (strcmp (arg, "str") == 0)
     442           0 :         print_debug_sections |= section_str;
     443           5 :       else if (strcmp (arg, "macinfo") == 0)
     444           0 :         print_debug_sections |= section_macinfo;
     445           5 :       else if (strcmp (arg, "macro") == 0)
     446           3 :         print_debug_sections |= section_macro;
     447           2 :       else if (strcmp (arg, "exception") == 0)
     448           0 :         print_debug_sections |= section_exception;
     449           2 :       else if (strcmp (arg, "gdb_index") == 0)
     450           2 :         print_debug_sections |= section_gdb_index;
     451             :       else
     452             :         {
     453           0 :           fprintf (stderr, gettext ("Unknown DWARF debug section `%s'.\n"),
     454             :                    arg);
     455           0 :           argp_help (&argp, stderr, ARGP_HELP_SEE,
     456             :                      program_invocation_short_name);
     457           0 :           exit (1);
     458             :         }
     459          71 :       any_control_option = true;
     460          71 :       break;
     461           1 :     case 'p':
     462           1 :       any_control_option = true;
     463           1 :       if (arg == NULL)
     464             :         {
     465           0 :           print_string_sections = true;
     466           0 :           break;
     467             :         }
     468             :       /* Fall through.  */
     469             :     case 'x':
     470           6 :       add_dump_section (arg, false);
     471           6 :       any_control_option = true;
     472           6 :       break;
     473           1 :     case 'N':
     474           1 :       print_address_names = false;
     475           1 :       break;
     476          19 :     case 'U':
     477          19 :       print_unresolved_addresses = true;
     478          19 :       break;
     479           0 :     case ARGP_KEY_NO_ARGS:
     480           0 :       fputs (gettext ("Missing file name.\n"), stderr);
     481           0 :       goto do_argp_help;
     482         181 :     case ARGP_KEY_FINI:
     483         181 :       if (! any_control_option && ! print_archive_index)
     484             :         {
     485           0 :           fputs (gettext ("No operation specified.\n"), stderr);
     486           0 :         do_argp_help:
     487           0 :           argp_help (&argp, stderr, ARGP_HELP_SEE,
     488             :                      program_invocation_short_name);
     489           0 :           exit (EXIT_FAILURE);
     490             :         }
     491             :       break;
     492             :     case 'W':                   /* Ignored.  */
     493             :       break;
     494          13 :     case 'z':
     495          13 :       print_decompress = true;
     496          13 :       break;
     497           4 :     case ELF_INPUT_SECTION:
     498           4 :       if (arg == NULL)
     499           4 :         elf_input_section = ".gnu_debugdata";
     500             :       else
     501           0 :         elf_input_section = arg;
     502             :       break;
     503             :     default:
     504             :       return ARGP_ERR_UNKNOWN;
     505             :     }
     506             :   return 0;
     507             : }
     508             : 
     509             : 
     510             : /* Create a file descriptor to read the data from the
     511             :    elf_input_section given a file descriptor to an ELF file.  */
     512             : static int
     513           4 : open_input_section (int fd)
     514             : {
     515             :   size_t shnums;
     516             :   size_t cnt;
     517             :   size_t shstrndx;
     518           4 :   Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
     519           4 :   if (elf == NULL)
     520             :     {
     521           0 :       error (0, 0, gettext ("cannot generate Elf descriptor: %s"),
     522             :              elf_errmsg (-1));
     523           0 :       return -1;
     524             :     }
     525             : 
     526           4 :   if (elf_getshdrnum (elf, &shnums) < 0)
     527             :     {
     528           0 :       error (0, 0, gettext ("cannot determine number of sections: %s"),
     529             :              elf_errmsg (-1));
     530           0 :     open_error:
     531           0 :       elf_end (elf);
     532           0 :       return -1;
     533             :     }
     534             : 
     535           4 :   if (elf_getshdrstrndx (elf, &shstrndx) < 0)
     536             :     {
     537           0 :       error (0, 0, gettext ("cannot get section header string table index"));
     538             :       goto open_error;
     539             :     }
     540             : 
     541         178 :   for (cnt = 0; cnt < shnums; ++cnt)
     542             :     {
     543          91 :       Elf_Scn *scn = elf_getscn (elf, cnt);
     544          91 :       if (scn == NULL)
     545             :         {
     546           0 :           error (0, 0, gettext ("cannot get section: %s"),
     547             :                  elf_errmsg (-1));
     548           0 :           goto open_error;
     549             :         }
     550             : 
     551             :       GElf_Shdr shdr_mem;
     552          91 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     553          91 :       if (unlikely (shdr == NULL))
     554             :         {
     555           0 :           error (0, 0, gettext ("cannot get section header: %s"),
     556             :                  elf_errmsg (-1));
     557             :           goto open_error;
     558             :         }
     559             : 
     560          91 :       const char *sname = elf_strptr (elf, shstrndx, shdr->sh_name);
     561          91 :       if (sname == NULL)
     562             :         {
     563           0 :           error (0, 0, gettext ("cannot get section name"));
     564             :           goto open_error;
     565             :         }
     566             : 
     567          91 :       if (strcmp (sname, elf_input_section) == 0)
     568             :         {
     569           4 :           Elf_Data *data = elf_rawdata (scn, NULL);
     570           4 :           if (data == NULL)
     571             :             {
     572           0 :               error (0, 0, gettext ("cannot get %s content: %s"),
     573             :                      sname, elf_errmsg (-1));
     574             :               goto open_error;
     575             :             }
     576             : 
     577             :           /* Create (and immediately unlink) a temporary file to store
     578             :              section data in to create a file descriptor for it.  */
     579           4 :           const char *tmpdir = getenv ("TMPDIR") ?: P_tmpdir;
     580             :           static const char suffix[] = "/readelfXXXXXX";
     581           4 :           int tmplen = strlen (tmpdir) + sizeof (suffix);
     582           4 :           char *tempname = alloca (tmplen);
     583           4 :           sprintf (tempname, "%s%s", tmpdir, suffix);
     584             : 
     585           4 :           int sfd = mkstemp (tempname);
     586           4 :           if (sfd == -1)
     587             :             {
     588           0 :               error (0, 0, gettext ("cannot create temp file '%s'"),
     589             :                      tempname);
     590             :               goto open_error;
     591             :             }
     592           4 :           unlink (tempname);
     593             : 
     594           4 :           ssize_t size = data->d_size;
     595           4 :           if (write_retry (sfd, data->d_buf, size) != size)
     596             :             {
     597           0 :               error (0, 0, gettext ("cannot write section data"));
     598             :               goto open_error;
     599             :             }
     600             : 
     601           4 :           if (elf_end (elf) != 0)
     602             :             {
     603           0 :               error (0, 0, gettext ("error while closing Elf descriptor: %s"),
     604             :                      elf_errmsg (-1));
     605           0 :               return -1;
     606             :             }
     607             : 
     608           4 :           if (lseek (sfd, 0, SEEK_SET) == -1)
     609             :             {
     610           0 :               error (0, 0, gettext ("error while rewinding file descriptor"));
     611           0 :               return -1;
     612             :             }
     613             : 
     614             :           return sfd;
     615             :         }
     616             :     }
     617             : 
     618             :   /* Named section not found.  */
     619           0 :   if (elf_end (elf) != 0)
     620           0 :     error (0, 0, gettext ("error while closing Elf descriptor: %s"),
     621             :            elf_errmsg (-1));
     622             :   return -1;
     623             : }
     624             : 
     625             : /* Check if the file is an archive, and if so dump its index.  */
     626             : static void
     627           2 : check_archive_index (int fd, const char *fname, bool only_one)
     628             : {
     629             :   /* Create an `Elf' descriptor.  */
     630           2 :   Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
     631           2 :   if (elf == NULL)
     632           0 :     error (0, 0, gettext ("cannot generate Elf descriptor: %s"),
     633             :            elf_errmsg (-1));
     634             :   else
     635             :     {
     636           2 :       if (elf_kind (elf) == ELF_K_AR)
     637             :         {
     638           2 :           if (!only_one)
     639             :             printf ("\n%s:\n\n", fname);
     640           2 :           dump_archive_index (elf, fname);
     641             :         }
     642             :       else
     643             :         error (0, 0,
     644           0 :                gettext ("'%s' is not an archive, cannot print archive index"),
     645             :                fname);
     646             : 
     647             :       /* Now we can close the descriptor.  */
     648           2 :       if (elf_end (elf) != 0)
     649           0 :         error (0, 0, gettext ("error while closing Elf descriptor: %s"),
     650             :                elf_errmsg (-1));
     651             :     }
     652           2 : }
     653             : 
     654             : /* Trivial callback used for checking if we opened an archive.  */
     655             : static int
     656         178 : count_dwflmod (Dwfl_Module *dwflmod __attribute__ ((unused)),
     657             :                void **userdata __attribute__ ((unused)),
     658             :                const char *name __attribute__ ((unused)),
     659             :                Dwarf_Addr base __attribute__ ((unused)),
     660             :                void *arg)
     661             : {
     662         178 :   if (*(bool *) arg)
     663             :     return DWARF_CB_ABORT;
     664         178 :   *(bool *) arg = true;
     665         178 :   return DWARF_CB_OK;
     666             : }
     667             : 
     668             : struct process_dwflmod_args
     669             : {
     670             :   int fd;
     671             :   bool only_one;
     672             : };
     673             : 
     674             : static int
     675         180 : process_dwflmod (Dwfl_Module *dwflmod,
     676             :                  void **userdata __attribute__ ((unused)),
     677             :                  const char *name __attribute__ ((unused)),
     678             :                  Dwarf_Addr base __attribute__ ((unused)),
     679             :                  void *arg)
     680             : {
     681         180 :   const struct process_dwflmod_args *a = arg;
     682             : 
     683             :   /* Print the file name.  */
     684         180 :   if (!a->only_one)
     685             :     {
     686             :       const char *fname;
     687           2 :       dwfl_module_info (dwflmod, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
     688             : 
     689           4 :       printf ("\n%s:\n\n", fname);
     690             :     }
     691             : 
     692         180 :   process_elf_file (dwflmod, a->fd);
     693             : 
     694         180 :   return DWARF_CB_OK;
     695             : }
     696             : 
     697             : /* Stub libdwfl callback, only the ELF handle already open is ever used.
     698             :    Only used for finding the alternate debug file if the Dwarf comes from
     699             :    the main file.  We are not interested in separate debuginfo.  */
     700             : static int
     701          27 : find_no_debuginfo (Dwfl_Module *mod,
     702             :                    void **userdata,
     703             :                    const char *modname,
     704             :                    Dwarf_Addr base,
     705             :                    const char *file_name,
     706             :                    const char *debuglink_file,
     707             :                    GElf_Word debuglink_crc,
     708             :                    char **debuginfo_file_name)
     709             : {
     710             :   Dwarf_Addr dwbias;
     711          27 :   dwfl_module_info (mod, NULL, NULL, NULL, &dwbias, NULL, NULL, NULL);
     712             : 
     713             :   /* We are only interested if the Dwarf has been setup on the main
     714             :      elf file but is only missing the alternate debug link.  If dwbias
     715             :      hasn't even been setup, this is searching for separate debuginfo
     716             :      for the main elf.  We don't care in that case.  */
     717          27 :   if (dwbias == (Dwarf_Addr) -1)
     718             :     return -1;
     719             : 
     720           5 :   return dwfl_standard_find_debuginfo (mod, userdata, modname, base,
     721             :                                        file_name, debuglink_file,
     722             :                                        debuglink_crc, debuginfo_file_name);
     723             : }
     724             : 
     725             : /* Process one input file.  */
     726             : static void
     727         182 : process_file (int fd, const char *fname, bool only_one)
     728             : {
     729         182 :   if (print_archive_index)
     730           2 :     check_archive_index (fd, fname, only_one);
     731             : 
     732         182 :   if (!any_control_option)
     733             :     return;
     734             : 
     735         180 :   if (elf_input_section != NULL)
     736             :     {
     737             :       /* Replace fname and fd with section content. */
     738           4 :       char *fnname = alloca (strlen (fname) + strlen (elf_input_section) + 2);
     739           8 :       sprintf (fnname, "%s:%s", fname, elf_input_section);
     740           4 :       fd = open_input_section (fd);
     741           4 :       if (fd == -1)
     742             :         {
     743           0 :           error (0, 0, gettext ("No such section '%s' in '%s'"),
     744             :                  elf_input_section, fname);
     745             :           return;
     746             :         }
     747             :       fname = fnname;
     748             :     }
     749             : 
     750             :   /* Duplicate an fd for dwfl_report_offline to swallow.  */
     751         180 :   int dwfl_fd = dup (fd);
     752         180 :   if (unlikely (dwfl_fd < 0))
     753           0 :     error (EXIT_FAILURE, errno, "dup");
     754             : 
     755             :   /* Use libdwfl in a trivial way to open the libdw handle for us.
     756             :      This takes care of applying relocations to DWARF data in ET_REL files.  */
     757             :   static const Dwfl_Callbacks callbacks =
     758             :     {
     759             :       .section_address = dwfl_offline_section_address,
     760             :       .find_debuginfo = find_no_debuginfo
     761             :     };
     762         180 :   Dwfl *dwfl = dwfl_begin (&callbacks);
     763         180 :   if (likely (dwfl != NULL))
     764             :     /* Let 0 be the logical address of the file (or first in archive).  */
     765         180 :     dwfl->offline_next_address = 0;
     766         180 :   if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) == NULL)
     767             :     {
     768             :       struct stat st;
     769           0 :       if (fstat (dwfl_fd, &st) != 0)
     770           0 :         error (0, errno, gettext ("cannot stat input file"));
     771           0 :       else if (unlikely (st.st_size == 0))
     772           0 :         error (0, 0, gettext ("input file is empty"));
     773             :       else
     774           0 :         error (0, 0, gettext ("failed reading '%s': %s"),
     775             :                fname, dwfl_errmsg (-1));
     776           0 :       close (dwfl_fd);          /* Consumed on success, not on failure.  */
     777             :     }
     778             :   else
     779             :     {
     780         180 :       dwfl_report_end (dwfl, NULL, NULL);
     781             : 
     782         180 :       if (only_one)
     783             :         {
     784             :           /* Clear ONLY_ONE if we have multiple modules, from an archive.  */
     785         178 :           bool seen = false;
     786         178 :           only_one = dwfl_getmodules (dwfl, &count_dwflmod, &seen, 0) == 0;
     787             :         }
     788             : 
     789             :       /* Process the one or more modules gleaned from this file.  */
     790         180 :       struct process_dwflmod_args a = { .fd = fd, .only_one = only_one };
     791         180 :       dwfl_getmodules (dwfl, &process_dwflmod, &a, 0);
     792             :     }
     793         180 :   dwfl_end (dwfl);
     794             : 
     795             :   /* Need to close the replaced fd if we created it.  Caller takes
     796             :      care of original.  */
     797         180 :   if (elf_input_section != NULL)
     798           4 :     close (fd);
     799             : }
     800             : 
     801             : /* Check whether there are any compressed sections in the ELF file.  */
     802             : static bool
     803          75 : elf_contains_chdrs (Elf *elf)
     804             : {
     805          75 :   Elf_Scn *scn = NULL;
     806        1819 :   while ((scn = elf_nextscn (elf, scn)) != NULL)
     807             :     {
     808             :       GElf_Shdr shdr_mem;
     809        1675 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     810        1675 :       if (shdr != NULL && (shdr->sh_flags & SHF_COMPRESSED) != 0)
     811           6 :         return true;
     812             :     }
     813             :   return false;
     814             : }
     815             : 
     816             : /* Process one ELF file.  */
     817             : static void
     818         180 : process_elf_file (Dwfl_Module *dwflmod, int fd)
     819             : {
     820             :   GElf_Addr dwflbias;
     821         180 :   Elf *elf = dwfl_module_getelf (dwflmod, &dwflbias);
     822             : 
     823             :   GElf_Ehdr ehdr_mem;
     824         180 :   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
     825             : 
     826         180 :   if (ehdr == NULL)
     827             :     {
     828           0 :     elf_error:
     829           0 :       error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1));
     830           0 :       return;
     831             :     }
     832             : 
     833         180 :   Ebl *ebl = ebl_openbackend (elf);
     834         180 :   if (unlikely (ebl == NULL))
     835             :     {
     836           0 :     ebl_error:
     837           0 :       error (0, errno, gettext ("cannot create EBL handle"));
     838             :       return;
     839             :     }
     840             : 
     841             :   /* Determine the number of sections.  */
     842         180 :   if (unlikely (elf_getshdrnum (ebl->elf, &shnum) < 0))
     843           0 :     error (EXIT_FAILURE, 0,
     844           0 :            gettext ("cannot determine number of sections: %s"),
     845             :            elf_errmsg (-1));
     846             : 
     847             :   /* Determine the number of phdrs.  */
     848         180 :   if (unlikely (elf_getphdrnum (ebl->elf, &phnum) < 0))
     849           0 :     error (EXIT_FAILURE, 0,
     850           0 :            gettext ("cannot determine number of program headers: %s"),
     851             :            elf_errmsg (-1));
     852             : 
     853             :   /* For an ET_REL file, libdwfl has adjusted the in-core shdrs and
     854             :      may have applied relocation to some sections.  If there are any
     855             :      compressed sections, any pass (or libdw/libdwfl) might have
     856             :      uncompressed them.  So we need to get a fresh Elf handle on the
     857             :      file to display those.  */
     858         360 :   bool print_unchanged = ((print_section_header
     859          94 :                            || print_relocations
     860          93 :                            || dump_data_sections != NULL
     861          88 :                            || print_notes)
     862         282 :                           && (ehdr->e_type == ET_REL
     863          75 :                               || elf_contains_chdrs (ebl->elf)));
     864             : 
     865         180 :   Elf *pure_elf = NULL;
     866         180 :   Ebl *pure_ebl = ebl;
     867         180 :   if (print_unchanged)
     868             :     {
     869             :       /* Read the file afresh.  */
     870          33 :       off_t aroff = elf_getaroff (elf);
     871          33 :       pure_elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
     872          33 :       if (aroff > 0)
     873             :         {
     874             :           /* Archive member.  */
     875           0 :           (void) elf_rand (pure_elf, aroff);
     876           0 :           Elf *armem = elf_begin (-1, ELF_C_READ_MMAP, pure_elf);
     877           0 :           elf_end (pure_elf);
     878           0 :           pure_elf = armem;
     879             :         }
     880          33 :       if (pure_elf == NULL)
     881             :         goto elf_error;
     882          33 :       pure_ebl = ebl_openbackend (pure_elf);
     883          33 :       if (pure_ebl == NULL)
     884             :         goto ebl_error;
     885             :     }
     886             : 
     887         180 :   if (print_file_header)
     888          32 :     print_ehdr (ebl, ehdr);
     889         180 :   if (print_section_header)
     890          86 :     print_shdr (pure_ebl, ehdr);
     891         180 :   if (print_program_header)
     892          32 :     print_phdr (ebl, ehdr);
     893         180 :   if (print_section_groups)
     894          32 :     print_scngrp (ebl);
     895         180 :   if (print_dynamic_table)
     896          34 :     print_dynamic (ebl);
     897         180 :   if (print_relocations)
     898          33 :     print_relocs (pure_ebl, ehdr);
     899         180 :   if (print_histogram)
     900          32 :     handle_hash (ebl);
     901         180 :   if (print_symbol_table)
     902          46 :     print_symtab (ebl, SHT_DYNSYM);
     903         180 :   if (print_version_info)
     904          32 :     print_verinfo (ebl);
     905         180 :   if (print_symbol_table)
     906          46 :     print_symtab (ebl, SHT_SYMTAB);
     907         180 :   if (print_arch)
     908          36 :     print_liblist (ebl);
     909         180 :   if (print_arch)
     910          36 :     print_attributes (ebl, ehdr);
     911         180 :   if (dump_data_sections != NULL)
     912           5 :     dump_data (pure_ebl);
     913         180 :   if (string_sections != NULL)
     914          33 :     dump_strings (ebl);
     915         180 :   if ((print_debug_sections | implicit_debug_sections) != 0)
     916          89 :     print_debug (dwflmod, ebl, ehdr);
     917         180 :   if (print_notes)
     918          42 :     handle_notes (pure_ebl, ehdr);
     919         180 :   if (print_string_sections)
     920           0 :     print_strings (ebl);
     921             : 
     922         180 :   ebl_closebackend (ebl);
     923             : 
     924         180 :   if (pure_ebl != ebl)
     925             :     {
     926          33 :       ebl_closebackend (pure_ebl);
     927          33 :       elf_end (pure_elf);
     928             :     }
     929             : }
     930             : 
     931             : 
     932             : /* Print file type.  */
     933             : static void
     934          32 : print_file_type (unsigned short int e_type)
     935             : {
     936          32 :   if (likely (e_type <= ET_CORE))
     937             :     {
     938             :       static const char *const knowntypes[] =
     939             :       {
     940             :         N_("NONE (None)"),
     941             :         N_("REL (Relocatable file)"),
     942             :         N_("EXEC (Executable file)"),
     943             :         N_("DYN (Shared object file)"),
     944             :         N_("CORE (Core file)")
     945             :       };
     946          32 :       puts (gettext (knowntypes[e_type]));
     947             :     }
     948           0 :   else if (e_type >= ET_LOOS && e_type <= ET_HIOS)
     949           0 :     printf (gettext ("OS Specific: (%x)\n"),  e_type);
     950           0 :   else if (e_type >= ET_LOPROC /* && e_type <= ET_HIPROC always true */)
     951           0 :     printf (gettext ("Processor Specific: (%x)\n"),  e_type);
     952             :   else
     953           0 :     puts ("???");
     954          32 : }
     955             : 
     956             : 
     957             : /* Print ELF header.  */
     958             : static void
     959          32 : print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr)
     960             : {
     961          32 :   fputs_unlocked (gettext ("ELF Header:\n  Magic:  "), stdout);
     962         544 :   for (size_t cnt = 0; cnt < EI_NIDENT; ++cnt)
     963        1024 :     printf (" %02hhx", ehdr->e_ident[cnt]);
     964             : 
     965          96 :   printf (gettext ("\n  Class:                             %s\n"),
     966          32 :           ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? "ELF32"
     967             :           : ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? "ELF64"
     968          28 :           : "\?\?\?");
     969             : 
     970          96 :   printf (gettext ("  Data:                              %s\n"),
     971          32 :           ehdr->e_ident[EI_DATA] == ELFDATA2LSB
     972             :           ? "2's complement, little endian"
     973             :           : ehdr->e_ident[EI_DATA] == ELFDATA2MSB
     974           6 :           ? "2's complement, big endian" : "\?\?\?");
     975             : 
     976          96 :   printf (gettext ("  Ident Version:                     %hhd %s\n"),
     977          32 :           ehdr->e_ident[EI_VERSION],
     978          32 :           ehdr->e_ident[EI_VERSION] == EV_CURRENT ? gettext ("(current)")
     979             :           : "(\?\?\?)");
     980             : 
     981             :   char buf[512];
     982          64 :   printf (gettext ("  OS/ABI:                            %s\n"),
     983          32 :           ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf)));
     984             : 
     985          64 :   printf (gettext ("  ABI Version:                       %hhd\n"),
     986          32 :           ehdr->e_ident[EI_ABIVERSION]);
     987             : 
     988          32 :   fputs_unlocked (gettext ("  Type:                              "), stdout);
     989          32 :   print_file_type (ehdr->e_type);
     990             : 
     991          64 :   printf (gettext ("  Machine:                           %s\n"), ebl->name);
     992             : 
     993          64 :   printf (gettext ("  Version:                           %d %s\n"),
     994             :           ehdr->e_version,
     995          32 :           ehdr->e_version  == EV_CURRENT ? gettext ("(current)") : "(\?\?\?)");
     996             : 
     997          64 :   printf (gettext ("  Entry point address:               %#" PRIx64 "\n"),
     998             :           ehdr->e_entry);
     999             : 
    1000          64 :   printf (gettext ("  Start of program headers:          %" PRId64 " %s\n"),
    1001             :           ehdr->e_phoff, gettext ("(bytes into file)"));
    1002             : 
    1003          64 :   printf (gettext ("  Start of section headers:          %" PRId64 " %s\n"),
    1004             :           ehdr->e_shoff, gettext ("(bytes into file)"));
    1005             : 
    1006          64 :   printf (gettext ("  Flags:                             %s\n"),
    1007             :           ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf)));
    1008             : 
    1009          96 :   printf (gettext ("  Size of this header:               %" PRId16 " %s\n"),
    1010          32 :           ehdr->e_ehsize, gettext ("(bytes)"));
    1011             : 
    1012          96 :   printf (gettext ("  Size of program header entries:    %" PRId16 " %s\n"),
    1013          32 :           ehdr->e_phentsize, gettext ("(bytes)"));
    1014             : 
    1015          64 :   printf (gettext ("  Number of program headers entries: %" PRId16),
    1016          32 :           ehdr->e_phnum);
    1017          32 :   if (ehdr->e_phnum == PN_XNUM)
    1018             :     {
    1019             :       GElf_Shdr shdr_mem;
    1020           0 :       GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
    1021           0 :       if (shdr != NULL)
    1022           0 :         printf (gettext (" (%" PRIu32 " in [0].sh_info)"),
    1023           0 :                 (uint32_t) shdr->sh_info);
    1024             :       else
    1025           0 :         fputs_unlocked (gettext (" ([0] not available)"), stdout);
    1026             :     }
    1027          64 :   fputc_unlocked ('\n', stdout);
    1028             : 
    1029          96 :   printf (gettext ("  Size of section header entries:    %" PRId16 " %s\n"),
    1030          32 :           ehdr->e_shentsize, gettext ("(bytes)"));
    1031             : 
    1032          64 :   printf (gettext ("  Number of section headers entries: %" PRId16),
    1033          32 :           ehdr->e_shnum);
    1034          32 :   if (ehdr->e_shnum == 0)
    1035             :     {
    1036             :       GElf_Shdr shdr_mem;
    1037           0 :       GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
    1038           0 :       if (shdr != NULL)
    1039           0 :         printf (gettext (" (%" PRIu32 " in [0].sh_size)"),
    1040           0 :                 (uint32_t) shdr->sh_size);
    1041             :       else
    1042           0 :         fputs_unlocked (gettext (" ([0] not available)"), stdout);
    1043             :     }
    1044          64 :   fputc_unlocked ('\n', stdout);
    1045             : 
    1046          32 :   if (unlikely (ehdr->e_shstrndx == SHN_XINDEX))
    1047             :     {
    1048             :       GElf_Shdr shdr_mem;
    1049           0 :       GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
    1050           0 :       if (shdr != NULL)
    1051             :         /* We managed to get the zeroth section.  */
    1052           0 :         snprintf (buf, sizeof (buf), gettext (" (%" PRIu32 " in [0].sh_link)"),
    1053           0 :                   (uint32_t) shdr->sh_link);
    1054             :       else
    1055             :         {
    1056           0 :           strncpy (buf, gettext (" ([0] not available)"), sizeof (buf));
    1057           0 :           buf[sizeof (buf) - 1] = '\0';
    1058             :         }
    1059             : 
    1060           0 :       printf (gettext ("  Section header string table index: XINDEX%s\n\n"),
    1061             :               buf);
    1062             :     }
    1063             :   else
    1064          32 :     printf (gettext ("  Section header string table index: %" PRId16 "\n\n"),
    1065             :             ehdr->e_shstrndx);
    1066          32 : }
    1067             : 
    1068             : 
    1069             : static const char *
    1070             : get_visibility_type (int value)
    1071             : {
    1072             :   switch (value)
    1073             :     {
    1074             :     case STV_DEFAULT:
    1075             :       return "DEFAULT";
    1076             :     case STV_INTERNAL:
    1077             :       return "INTERNAL";
    1078             :     case STV_HIDDEN:
    1079             :       return "HIDDEN";
    1080             :     case STV_PROTECTED:
    1081             :       return "PROTECTED";
    1082             :     default:
    1083             :       return "???";
    1084             :     }
    1085             : }
    1086             : 
    1087             : static const char *
    1088             : elf_ch_type_name (unsigned int code)
    1089             : {
    1090          12 :   if (code == 0)
    1091             :     return "NONE";
    1092             : 
    1093          12 :   if (code == ELFCOMPRESS_ZLIB)
    1094             :     return "ZLIB";
    1095             : 
    1096             :   return "UNKNOWN";
    1097             : }
    1098             : 
    1099             : /* Print the section headers.  */
    1100             : static void
    1101          86 : print_shdr (Ebl *ebl, GElf_Ehdr *ehdr)
    1102             : {
    1103             :   size_t cnt;
    1104             :   size_t shstrndx;
    1105             : 
    1106          86 :   if (! print_file_header)
    1107         108 :     printf (gettext ("\
    1108             : There are %d section headers, starting at offset %#" PRIx64 ":\n\
    1109             : \n"),
    1110          54 :             ehdr->e_shnum, ehdr->e_shoff);
    1111             : 
    1112             :   /* Get the section header string table index.  */
    1113          86 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    1114             :     error (EXIT_FAILURE, 0,
    1115           0 :            gettext ("cannot get section header string table index"));
    1116             : 
    1117          86 :   puts (gettext ("Section Headers:"));
    1118             : 
    1119          86 :   if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
    1120          34 :     puts (gettext ("[Nr] Name                 Type         Addr     Off    Size   ES Flags Lk Inf Al"));
    1121             :   else
    1122          52 :     puts (gettext ("[Nr] Name                 Type         Addr             Off      Size     ES Flags Lk Inf Al"));
    1123             : 
    1124          86 :   if (print_decompress)
    1125             :     {
    1126           8 :       if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
    1127           4 :         puts (gettext ("     [Compression  Size   Al]"));
    1128             :       else
    1129           4 :         puts (gettext ("     [Compression  Size     Al]"));
    1130             :     }
    1131             : 
    1132        2221 :   for (cnt = 0; cnt < shnum; ++cnt)
    1133             :     {
    1134        2221 :       Elf_Scn *scn = elf_getscn (ebl->elf, cnt);
    1135             : 
    1136        2221 :       if (unlikely (scn == NULL))
    1137           0 :         error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
    1138             :                elf_errmsg (-1));
    1139             : 
    1140             :       /* Get the section header.  */
    1141             :       GElf_Shdr shdr_mem;
    1142        2221 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1143        2221 :       if (unlikely (shdr == NULL))
    1144           0 :         error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
    1145             :                elf_errmsg (-1));
    1146             : 
    1147             :       char flagbuf[20];
    1148        2221 :       char *cp = flagbuf;
    1149        2221 :       if (shdr->sh_flags & SHF_WRITE)
    1150         492 :         *cp++ = 'W';
    1151        2221 :       if (shdr->sh_flags & SHF_ALLOC)
    1152        1457 :         *cp++ = 'A';
    1153        2221 :       if (shdr->sh_flags & SHF_EXECINSTR)
    1154         271 :         *cp++ = 'X';
    1155        2221 :       if (shdr->sh_flags & SHF_MERGE)
    1156         102 :         *cp++ = 'M';
    1157        2221 :       if (shdr->sh_flags & SHF_STRINGS)
    1158         102 :         *cp++ = 'S';
    1159        2221 :       if (shdr->sh_flags & SHF_INFO_LINK)
    1160         105 :         *cp++ = 'I';
    1161        2221 :       if (shdr->sh_flags & SHF_LINK_ORDER)
    1162           2 :         *cp++ = 'L';
    1163        2221 :       if (shdr->sh_flags & SHF_OS_NONCONFORMING)
    1164           0 :         *cp++ = 'N';
    1165        2221 :       if (shdr->sh_flags & SHF_GROUP)
    1166           0 :         *cp++ = 'G';
    1167        2221 :       if (shdr->sh_flags & SHF_TLS)
    1168          10 :         *cp++ = 'T';
    1169        2221 :       if (shdr->sh_flags & SHF_COMPRESSED)
    1170          12 :         *cp++ = 'C';
    1171        2221 :       if (shdr->sh_flags & SHF_ORDERED)
    1172           0 :         *cp++ = 'O';
    1173        2221 :       if (shdr->sh_flags & SHF_EXCLUDE)
    1174           0 :         *cp++ = 'E';
    1175        2221 :       *cp = '\0';
    1176             : 
    1177             :       const char *sname;
    1178             :       char buf[128];
    1179        2221 :       sname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name) ?: "<corrupt>";
    1180        8884 :       printf ("[%2zu] %-20s %-12s %0*" PRIx64 " %0*" PRIx64 " %0*" PRIx64
    1181             :               " %2" PRId64 " %-5s %2" PRId32 " %3" PRId32
    1182             :               " %2" PRId64 "\n",
    1183             :               cnt, sname,
    1184        2221 :               ebl_section_type_name (ebl, shdr->sh_type, buf, sizeof (buf)),
    1185             :               ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, shdr->sh_addr,
    1186             :               ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_offset,
    1187        2221 :               ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, shdr->sh_size,
    1188             :               shdr->sh_entsize, flagbuf, shdr->sh_link, shdr->sh_info,
    1189             :               shdr->sh_addralign);
    1190             : 
    1191        2221 :       if (print_decompress)
    1192             :         {
    1193          76 :           if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1194             :             {
    1195             :               GElf_Chdr chdr;
    1196          12 :               if (gelf_getchdr (scn, &chdr) != NULL)
    1197          36 :                 printf ("     [ELF %s (%" PRId32 ") %0*" PRIx64
    1198             :                         " %2" PRId64 "]\n",
    1199             :                         elf_ch_type_name (chdr.ch_type),
    1200             :                         chdr.ch_type,
    1201          12 :                         ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8,
    1202             :                         chdr.ch_size, chdr.ch_addralign);
    1203             :               else
    1204           0 :                 error (0, 0,
    1205           0 :                        gettext ("bad compression header for section %zd: %s"),
    1206             :                        elf_ndxscn (scn), elf_errmsg (-1));
    1207             :             }
    1208          64 :           else if (strncmp(".zdebug", sname, strlen (".zdebug")) == 0)
    1209             :             {
    1210             :               ssize_t size;
    1211          12 :               if ((size = dwelf_scn_gnu_compressed_size (scn)) >= 0)
    1212          12 :                 printf ("     [GNU ZLIB     %0*zx   ]\n",
    1213          12 :                         ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 6 : 8, size);
    1214             :               else
    1215           0 :                 error (0, 0,
    1216           0 :                        gettext ("bad gnu compressed size for section %zd: %s"),
    1217             :                        elf_ndxscn (scn), elf_errmsg (-1));
    1218             :             }
    1219             :         }
    1220             :     }
    1221             : 
    1222         172 :   fputc_unlocked ('\n', stdout);
    1223          86 : }
    1224             : 
    1225             : 
    1226             : /* Print the program header.  */
    1227             : static void
    1228          32 : print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
    1229             : {
    1230          32 :   if (phnum == 0)
    1231             :     /* No program header, this is OK in relocatable objects.  */
    1232          20 :     return;
    1233             : 
    1234          12 :   puts (gettext ("Program Headers:"));
    1235          12 :   if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
    1236           0 :     puts (gettext ("\
    1237             :   Type           Offset   VirtAddr   PhysAddr   FileSiz  MemSiz   Flg Align"));
    1238             :   else
    1239          12 :     puts (gettext ("\
    1240             :   Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align"));
    1241             : 
    1242             :   /* Process all program headers.  */
    1243             :   bool has_relro = false;
    1244             :   GElf_Addr relro_from = 0;
    1245             :   GElf_Addr relro_to = 0;
    1246         110 :   for (size_t cnt = 0; cnt < phnum; ++cnt)
    1247             :     {
    1248             :       char buf[128];
    1249             :       GElf_Phdr mem;
    1250         110 :       GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
    1251             : 
    1252             :       /* If for some reason the header cannot be returned show this.  */
    1253         110 :       if (unlikely (phdr == NULL))
    1254             :         {
    1255           0 :           puts ("  ???");
    1256           0 :           continue;
    1257             :         }
    1258             : 
    1259         770 :       printf ("  %-14s 0x%06" PRIx64 " 0x%0*" PRIx64 " 0x%0*" PRIx64
    1260             :               " 0x%06" PRIx64 " 0x%06" PRIx64 " %c%c%c 0x%" PRIx64 "\n",
    1261         110 :               ebl_segment_type_name (ebl, phdr->p_type, buf, sizeof (buf)),
    1262             :               phdr->p_offset,
    1263             :               ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_vaddr,
    1264         110 :               ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16, phdr->p_paddr,
    1265             :               phdr->p_filesz,
    1266             :               phdr->p_memsz,
    1267         110 :               phdr->p_flags & PF_R ? 'R' : ' ',
    1268         110 :               phdr->p_flags & PF_W ? 'W' : ' ',
    1269         110 :               phdr->p_flags & PF_X ? 'E' : ' ',
    1270             :               phdr->p_align);
    1271             : 
    1272         110 :       if (phdr->p_type == PT_INTERP)
    1273             :         {
    1274             :           /* If we are sure the file offset is valid then we can show
    1275             :              the user the name of the interpreter.  We check whether
    1276             :              there is a section at the file offset.  Normally there
    1277             :              would be a section called ".interp".  But in separate
    1278             :              .debug files it is a NOBITS section (and so doesn't match
    1279             :              with gelf_offscn).  Which probably means the offset is
    1280             :              not valid another reason could be because the ELF file
    1281             :              just doesn't contain any section headers, in that case
    1282             :              just play it safe and don't display anything.  */
    1283             : 
    1284           8 :           Elf_Scn *scn = gelf_offscn (ebl->elf, phdr->p_offset);
    1285             :           GElf_Shdr shdr_mem;
    1286           8 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1287             : 
    1288             :           size_t maxsize;
    1289           8 :           char *filedata = elf_rawfile (ebl->elf, &maxsize);
    1290             : 
    1291           8 :           if (shdr != NULL && shdr->sh_type == SHT_PROGBITS
    1292           8 :               && filedata != NULL && phdr->p_offset < maxsize
    1293           8 :               && phdr->p_filesz <= maxsize - phdr->p_offset
    1294           8 :               && memchr (filedata + phdr->p_offset, '\0',
    1295             :                          phdr->p_filesz) != NULL)
    1296           8 :             printf (gettext ("\t[Requesting program interpreter: %s]\n"),
    1297             :                     filedata + phdr->p_offset);
    1298             :         }
    1299         102 :       else if (phdr->p_type == PT_GNU_RELRO)
    1300             :         {
    1301          12 :           has_relro = true;
    1302          12 :           relro_from = phdr->p_vaddr;
    1303          12 :           relro_to = relro_from + phdr->p_memsz;
    1304             :         }
    1305             :     }
    1306             : 
    1307          12 :   if (ehdr->e_shnum == 0)
    1308             :     /* No sections in the file.  Punt.  */
    1309             :     return;
    1310             : 
    1311             :   /* Get the section header string table index.  */
    1312             :   size_t shstrndx;
    1313          12 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    1314             :     error (EXIT_FAILURE, 0,
    1315           0 :            gettext ("cannot get section header string table index"));
    1316             : 
    1317          12 :   puts (gettext ("\n Section to Segment mapping:\n  Segment Sections..."));
    1318             : 
    1319         122 :   for (size_t cnt = 0; cnt < phnum; ++cnt)
    1320             :     {
    1321             :       /* Print the segment number.  */
    1322         110 :       printf ("   %2.2zu     ", cnt);
    1323             : 
    1324             :       GElf_Phdr phdr_mem;
    1325         110 :       GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem);
    1326             :       /* This must not happen.  */
    1327         110 :       if (unlikely (phdr == NULL))
    1328           0 :         error (EXIT_FAILURE, 0, gettext ("cannot get program header: %s"),
    1329             :                elf_errmsg (-1));
    1330             : 
    1331             :       /* Iterate over the sections.  */
    1332             :       bool in_relro = false;
    1333             :       bool in_ro = false;
    1334        3916 :       for (size_t inner = 1; inner < shnum; ++inner)
    1335             :         {
    1336        3916 :           Elf_Scn *scn = elf_getscn (ebl->elf, inner);
    1337             :           /* This should not happen.  */
    1338        3916 :           if (unlikely (scn == NULL))
    1339           0 :             error (EXIT_FAILURE, 0, gettext ("cannot get section: %s"),
    1340             :                    elf_errmsg (-1));
    1341             : 
    1342             :           /* Get the section header.  */
    1343             :           GElf_Shdr shdr_mem;
    1344        3916 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1345        3916 :           if (unlikely (shdr == NULL))
    1346           0 :             error (EXIT_FAILURE, 0,
    1347           0 :                    gettext ("cannot get section header: %s"),
    1348             :                    elf_errmsg (-1));
    1349             : 
    1350        3916 :           if (shdr->sh_size > 0
    1351             :               /* Compare allocated sections by VMA, unallocated
    1352             :                  sections by file offset.  */
    1353        7832 :               && (shdr->sh_flags & SHF_ALLOC
    1354        2866 :                   ? (shdr->sh_addr >= phdr->p_vaddr
    1355        4706 :                      && (shdr->sh_addr + shdr->sh_size
    1356        1840 :                          <= phdr->p_vaddr + phdr->p_memsz))
    1357        1050 :                   : (shdr->sh_offset >= phdr->p_offset
    1358        2100 :                      && (shdr->sh_offset + shdr->sh_size
    1359        1050 :                          <= phdr->p_offset + phdr->p_filesz))))
    1360             :             {
    1361         444 :               if (has_relro && !in_relro
    1362         316 :                   && shdr->sh_addr >= relro_from
    1363          70 :                   && shdr->sh_addr + shdr->sh_size <= relro_to)
    1364             :                 {
    1365          46 :                   fputs_unlocked (" [RELRO:", stdout);
    1366          46 :                   in_relro = true;
    1367             :                 }
    1368         398 :               else if (has_relro && in_relro && shdr->sh_addr >= relro_to)
    1369             :                 {
    1370          12 :                   fputs_unlocked ("]", stdout);
    1371          12 :                   in_relro =  false;
    1372             :                 }
    1373         386 :               else if (has_relro && in_relro
    1374         116 :                        && shdr->sh_addr + shdr->sh_size > relro_to)
    1375           0 :                 fputs_unlocked ("] <RELRO:", stdout);
    1376         386 :               else if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W) == 0)
    1377             :                 {
    1378         206 :                   if (!in_ro)
    1379             :                     {
    1380          12 :                       fputs_unlocked (" [RO:", stdout);
    1381          12 :                       in_ro = true;
    1382             :                     }
    1383             :                 }
    1384             :               else
    1385             :                 {
    1386             :                   /* Determine the segment this section is part of.  */
    1387             :                   size_t cnt2;
    1388             :                   GElf_Phdr phdr2_mem;
    1389             :                   GElf_Phdr *phdr2 = NULL;
    1390         396 :                   for (cnt2 = 0; cnt2 < phnum; ++cnt2)
    1391             :                     {
    1392         576 :                       phdr2 = gelf_getphdr (ebl->elf, cnt2, &phdr2_mem);
    1393             : 
    1394         576 :                       if (phdr2 != NULL && phdr2->p_type == PT_LOAD
    1395         320 :                           && shdr->sh_addr >= phdr2->p_vaddr
    1396         640 :                           && (shdr->sh_addr + shdr->sh_size
    1397         320 :                               <= phdr2->p_vaddr + phdr2->p_memsz))
    1398             :                         break;
    1399             :                     }
    1400             : 
    1401         180 :                   if (cnt2 < phnum)
    1402             :                     {
    1403         180 :                       if ((phdr2->p_flags & PF_W) == 0 && !in_ro)
    1404             :                         {
    1405          32 :                           fputs_unlocked (" [RO:", stdout);
    1406          32 :                           in_ro = true;
    1407             :                         }
    1408         148 :                       else if ((phdr2->p_flags & PF_W) != 0 && in_ro)
    1409             :                         {
    1410           0 :                           fputs_unlocked ("]", stdout);
    1411           0 :                           in_ro = false;
    1412             :                         }
    1413             :                     }
    1414             :                 }
    1415             : 
    1416         888 :               printf (" %s",
    1417         444 :                       elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
    1418             : 
    1419             :               /* Signal that this sectin is only partially covered.  */
    1420         444 :               if (has_relro && in_relro
    1421         162 :                        && shdr->sh_addr + shdr->sh_size > relro_to)
    1422             :                 {
    1423           0 :                   fputs_unlocked (">", stdout);
    1424           0 :                   in_relro =  false;
    1425             :                 }
    1426             :             }
    1427             :         }
    1428         110 :       if (in_relro || in_ro)
    1429          78 :         fputs_unlocked ("]", stdout);
    1430             : 
    1431             :       /* Finish the line.  */
    1432         220 :       fputc_unlocked ('\n', stdout);
    1433             :     }
    1434             : }
    1435             : 
    1436             : 
    1437             : static const char *
    1438             : section_name (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr)
    1439             : {
    1440         266 :   return elf_strptr (ebl->elf, ehdr->e_shstrndx, shdr->sh_name) ?: "???";
    1441             : }
    1442             : 
    1443             : 
    1444             : static void
    1445           0 : handle_scngrp (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
    1446             : {
    1447             :   /* Get the data of the section.  */
    1448           0 :   Elf_Data *data = elf_getdata (scn, NULL);
    1449             : 
    1450           0 :   Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
    1451             :   GElf_Shdr symshdr_mem;
    1452           0 :   GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
    1453           0 :   Elf_Data *symdata = elf_getdata (symscn, NULL);
    1454             : 
    1455           0 :   if (data == NULL || data->d_size < sizeof (Elf32_Word) || symshdr == NULL
    1456           0 :       || symdata == NULL)
    1457           0 :     return;
    1458             : 
    1459             :   /* Get the section header string table index.  */
    1460             :   size_t shstrndx;
    1461           0 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    1462             :     error (EXIT_FAILURE, 0,
    1463           0 :            gettext ("cannot get section header string table index"));
    1464             : 
    1465           0 :   Elf32_Word *grpref = (Elf32_Word *) data->d_buf;
    1466             : 
    1467             :   GElf_Sym sym_mem;
    1468           0 :   GElf_Sym *sym = gelf_getsym (symdata, shdr->sh_info, &sym_mem);
    1469             : 
    1470           0 :   printf ((grpref[0] & GRP_COMDAT)
    1471           0 :           ? ngettext ("\
    1472             : \nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entry:\n",
    1473             :                       "\
    1474             : \nCOMDAT section group [%2zu] '%s' with signature '%s' contains %zu entries:\n",
    1475             :                       data->d_size / sizeof (Elf32_Word) - 1)
    1476           0 :           : ngettext ("\
    1477             : \nSection group [%2zu] '%s' with signature '%s' contains %zu entry:\n", "\
    1478             : \nSection group [%2zu] '%s' with signature '%s' contains %zu entries:\n",
    1479             :                       data->d_size / sizeof (Elf32_Word) - 1),
    1480             :           elf_ndxscn (scn),
    1481           0 :           elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    1482             :           (sym == NULL ? NULL
    1483           0 :            : elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name))
    1484             :           ?: gettext ("<INVALID SYMBOL>"),
    1485           0 :           data->d_size / sizeof (Elf32_Word) - 1);
    1486             : 
    1487           0 :   for (size_t cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt)
    1488             :     {
    1489             :       GElf_Shdr grpshdr_mem;
    1490           0 :       GElf_Shdr *grpshdr = gelf_getshdr (elf_getscn (ebl->elf, grpref[cnt]),
    1491             :                                          &grpshdr_mem);
    1492             : 
    1493             :       const char *str;
    1494           0 :       printf ("  [%2u] %s\n",
    1495             :               grpref[cnt],
    1496             :               grpshdr != NULL
    1497           0 :               && (str = elf_strptr (ebl->elf, shstrndx, grpshdr->sh_name))
    1498             :               ? str : gettext ("<INVALID SECTION>"));
    1499             :     }
    1500             : }
    1501             : 
    1502             : 
    1503             : static void
    1504          32 : print_scngrp (Ebl *ebl)
    1505             : {
    1506             :   /* Find all relocation sections and handle them.  */
    1507          32 :   Elf_Scn *scn = NULL;
    1508             : 
    1509         930 :   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    1510             :     {
    1511             :        /* Handle the section if it is a symbol table.  */
    1512             :       GElf_Shdr shdr_mem;
    1513         866 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1514             : 
    1515         866 :       if (shdr != NULL && shdr->sh_type == SHT_GROUP)
    1516             :         {
    1517           0 :           if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1518             :             {
    1519           0 :               if (elf_compress (scn, 0, 0) < 0)
    1520           0 :                 printf ("WARNING: %s [%zd]\n",
    1521             :                         gettext ("Couldn't uncompress section"),
    1522             :                         elf_ndxscn (scn));
    1523           0 :               shdr = gelf_getshdr (scn, &shdr_mem);
    1524           0 :               if (unlikely (shdr == NULL))
    1525           0 :                 error (EXIT_FAILURE, 0,
    1526           0 :                        gettext ("cannot get section [%zd] header: %s"),
    1527             :                        elf_ndxscn (scn),
    1528             :                        elf_errmsg (-1));
    1529             :             }
    1530           0 :           handle_scngrp (ebl, scn, shdr);
    1531             :         }
    1532             :     }
    1533          32 : }
    1534             : 
    1535             : 
    1536             : static const struct flags
    1537             : {
    1538             :   int mask;
    1539             :   const char *str;
    1540             : } dt_flags[] =
    1541             :   {
    1542             :     { DF_ORIGIN, "ORIGIN" },
    1543             :     { DF_SYMBOLIC, "SYMBOLIC" },
    1544             :     { DF_TEXTREL, "TEXTREL" },
    1545             :     { DF_BIND_NOW, "BIND_NOW" },
    1546             :     { DF_STATIC_TLS, "STATIC_TLS" }
    1547             :   };
    1548             : static const int ndt_flags = sizeof (dt_flags) / sizeof (dt_flags[0]);
    1549             : 
    1550             : static const struct flags dt_flags_1[] =
    1551             :   {
    1552             :     { DF_1_NOW, "NOW" },
    1553             :     { DF_1_GLOBAL, "GLOBAL" },
    1554             :     { DF_1_GROUP, "GROUP" },
    1555             :     { DF_1_NODELETE, "NODELETE" },
    1556             :     { DF_1_LOADFLTR, "LOADFLTR" },
    1557             :     { DF_1_INITFIRST, "INITFIRST" },
    1558             :     { DF_1_NOOPEN, "NOOPEN" },
    1559             :     { DF_1_ORIGIN, "ORIGIN" },
    1560             :     { DF_1_DIRECT, "DIRECT" },
    1561             :     { DF_1_TRANS, "TRANS" },
    1562             :     { DF_1_INTERPOSE, "INTERPOSE" },
    1563             :     { DF_1_NODEFLIB, "NODEFLIB" },
    1564             :     { DF_1_NODUMP, "NODUMP" },
    1565             :     { DF_1_CONFALT, "CONFALT" },
    1566             :     { DF_1_ENDFILTEE, "ENDFILTEE" },
    1567             :     { DF_1_DISPRELDNE, "DISPRELDNE" },
    1568             :     { DF_1_DISPRELPND, "DISPRELPND" },
    1569             :   };
    1570             : static const int ndt_flags_1 = sizeof (dt_flags_1) / sizeof (dt_flags_1[0]);
    1571             : 
    1572             : static const struct flags dt_feature_1[] =
    1573             :   {
    1574             :     { DTF_1_PARINIT, "PARINIT" },
    1575             :     { DTF_1_CONFEXP, "CONFEXP" }
    1576             :   };
    1577             : static const int ndt_feature_1 = (sizeof (dt_feature_1)
    1578             :                                   / sizeof (dt_feature_1[0]));
    1579             : 
    1580             : static const struct flags dt_posflag_1[] =
    1581             :   {
    1582             :     { DF_P1_LAZYLOAD, "LAZYLOAD" },
    1583             :     { DF_P1_GROUPPERM, "GROUPPERM" }
    1584             :   };
    1585             : static const int ndt_posflag_1 = (sizeof (dt_posflag_1)
    1586             :                                   / sizeof (dt_posflag_1[0]));
    1587             : 
    1588             : 
    1589             : static void
    1590           4 : print_flags (int class, GElf_Xword d_val, const struct flags *flags,
    1591             :                 int nflags)
    1592             : {
    1593           4 :   bool first = true;
    1594             :   int cnt;
    1595             : 
    1596          30 :   for (cnt = 0; cnt < nflags; ++cnt)
    1597          26 :     if (d_val & flags[cnt].mask)
    1598             :       {
    1599          22 :         if (!first)
    1600             :           putchar_unlocked (' ');
    1601          22 :         fputs_unlocked (flags[cnt].str, stdout);
    1602          22 :         d_val &= ~flags[cnt].mask;
    1603          22 :         first = false;
    1604             :       }
    1605             : 
    1606           4 :   if (d_val != 0)
    1607             :     {
    1608           4 :       if (!first)
    1609             :         putchar_unlocked (' ');
    1610           4 :       printf ("%#0*" PRIx64, class == ELFCLASS32 ? 10 : 18, d_val);
    1611             :     }
    1612             : 
    1613           4 :   putchar_unlocked ('\n');
    1614           4 : }
    1615             : 
    1616             : 
    1617             : static void
    1618             : print_dt_flags (int class, GElf_Xword d_val)
    1619             : {
    1620           1 :   print_flags (class, d_val, dt_flags, ndt_flags);
    1621             : }
    1622             : 
    1623             : 
    1624             : static void
    1625             : print_dt_flags_1 (int class, GElf_Xword d_val)
    1626             : {
    1627           1 :   print_flags (class, d_val, dt_flags_1, ndt_flags_1);
    1628             : }
    1629             : 
    1630             : 
    1631             : static void
    1632             : print_dt_feature_1 (int class, GElf_Xword d_val)
    1633             : {
    1634           1 :   print_flags (class, d_val, dt_feature_1, ndt_feature_1);
    1635             : }
    1636             : 
    1637             : 
    1638             : static void
    1639             : print_dt_posflag_1 (int class, GElf_Xword d_val)
    1640             : {
    1641           1 :   print_flags (class, d_val, dt_posflag_1, ndt_posflag_1);
    1642             : }
    1643             : 
    1644             : 
    1645             : static void
    1646          14 : handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
    1647             : {
    1648          14 :   int class = gelf_getclass (ebl->elf);
    1649             :   GElf_Shdr glink_mem;
    1650             :   GElf_Shdr *glink;
    1651             :   Elf_Data *data;
    1652             :   size_t cnt;
    1653             :   size_t shstrndx;
    1654             :   size_t sh_entsize;
    1655             : 
    1656             :   /* Get the data of the section.  */
    1657          14 :   data = elf_getdata (scn, NULL);
    1658          14 :   if (data == NULL)
    1659           0 :     return;
    1660             : 
    1661             :   /* Get the section header string table index.  */
    1662          14 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    1663             :     error (EXIT_FAILURE, 0,
    1664           0 :            gettext ("cannot get section header string table index"));
    1665             : 
    1666          14 :   sh_entsize = gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT);
    1667             : 
    1668          14 :   glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink_mem);
    1669          14 :   if (glink == NULL)
    1670           0 :     error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %zu"),
    1671             :            elf_ndxscn (scn));
    1672             : 
    1673          56 :   printf (ngettext ("\
    1674             : \nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 "  Offset: %#08" PRIx64 "  Link to section: [%2u] '%s'\n",
    1675             :                     "\
    1676             : \nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 "  Offset: %#08" PRIx64 "  Link to section: [%2u] '%s'\n",
    1677             :                     shdr->sh_size / sh_entsize),
    1678          14 :           (unsigned long int) (shdr->sh_size / sh_entsize),
    1679             :           class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
    1680             :           shdr->sh_offset,
    1681          14 :           (int) shdr->sh_link,
    1682          14 :           elf_strptr (ebl->elf, shstrndx, glink->sh_name));
    1683          14 :   fputs_unlocked (gettext ("  Type              Value\n"), stdout);
    1684             : 
    1685         511 :   for (cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt)
    1686             :     {
    1687             :       GElf_Dyn dynmem;
    1688         497 :       GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dynmem);
    1689         497 :       if (dyn == NULL)
    1690             :         break;
    1691             : 
    1692             :       char buf[64];
    1693         994 :       printf ("  %-17s ",
    1694             :               ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, sizeof (buf)));
    1695             : 
    1696         497 :       switch (dyn->d_tag)
    1697             :         {
    1698          86 :         case DT_NULL:
    1699             :         case DT_DEBUG:
    1700             :         case DT_BIND_NOW:
    1701             :         case DT_TEXTREL:
    1702             :           /* No further output.  */
    1703          86 :           fputc_unlocked ('\n', stdout);
    1704             :           break;
    1705             : 
    1706          63 :         case DT_NEEDED:
    1707         126 :           printf (gettext ("Shared library: [%s]\n"),
    1708          63 :                   elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
    1709             :           break;
    1710             : 
    1711           3 :         case DT_SONAME:
    1712           6 :           printf (gettext ("Library soname: [%s]\n"),
    1713           3 :                   elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
    1714             :           break;
    1715             : 
    1716           1 :         case DT_RPATH:
    1717           2 :           printf (gettext ("Library rpath: [%s]\n"),
    1718           1 :                   elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
    1719             :           break;
    1720             : 
    1721           2 :         case DT_RUNPATH:
    1722           4 :           printf (gettext ("Library runpath: [%s]\n"),
    1723           2 :                   elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val));
    1724             :           break;
    1725             : 
    1726         105 :         case DT_PLTRELSZ:
    1727             :         case DT_RELASZ:
    1728             :         case DT_STRSZ:
    1729             :         case DT_RELSZ:
    1730             :         case DT_RELAENT:
    1731             :         case DT_SYMENT:
    1732             :         case DT_RELENT:
    1733             :         case DT_PLTPADSZ:
    1734             :         case DT_MOVEENT:
    1735             :         case DT_MOVESZ:
    1736             :         case DT_INIT_ARRAYSZ:
    1737             :         case DT_FINI_ARRAYSZ:
    1738             :         case DT_SYMINSZ:
    1739             :         case DT_SYMINENT:
    1740             :         case DT_GNU_CONFLICTSZ:
    1741             :         case DT_GNU_LIBLISTSZ:
    1742         105 :           printf (gettext ("%" PRId64 " (bytes)\n"), dyn->d_un.d_val);
    1743             :           break;
    1744             : 
    1745          27 :         case DT_VERDEFNUM:
    1746             :         case DT_VERNEEDNUM:
    1747             :         case DT_RELACOUNT:
    1748             :         case DT_RELCOUNT:
    1749          27 :           printf ("%" PRId64 "\n", dyn->d_un.d_val);
    1750             :           break;
    1751             : 
    1752          14 :         case DT_PLTREL:;
    1753          14 :           const char *tagname = ebl_dynamic_tag_name (ebl, dyn->d_un.d_val,
    1754             :                                                       NULL, 0);
    1755          14 :           puts (tagname ?: "???");
    1756          14 :           break;
    1757             : 
    1758           1 :         case DT_FLAGS:
    1759           1 :           print_dt_flags (class, dyn->d_un.d_val);
    1760             :           break;
    1761             : 
    1762           1 :         case DT_FLAGS_1:
    1763           1 :           print_dt_flags_1 (class, dyn->d_un.d_val);
    1764             :           break;
    1765             : 
    1766           1 :         case DT_FEATURE_1:
    1767           1 :           print_dt_feature_1 (class, dyn->d_un.d_val);
    1768             :           break;
    1769             : 
    1770           1 :         case DT_POSFLAG_1:
    1771           1 :           print_dt_posflag_1 (class, dyn->d_un.d_val);
    1772             :           break;
    1773             : 
    1774         192 :         default:
    1775         192 :           printf ("%#0*" PRIx64 "\n",
    1776             :                   class == ELFCLASS32 ? 10 : 18, dyn->d_un.d_val);
    1777             :           break;
    1778             :         }
    1779             :     }
    1780             : }
    1781             : 
    1782             : 
    1783             : /* Print the dynamic segment.  */
    1784             : static void
    1785          34 : print_dynamic (Ebl *ebl)
    1786             : {
    1787          78 :   for (size_t i = 0; i < phnum; ++i)
    1788             :     {
    1789             :       GElf_Phdr phdr_mem;
    1790          58 :       GElf_Phdr *phdr = gelf_getphdr (ebl->elf, i, &phdr_mem);
    1791             : 
    1792          58 :       if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
    1793             :         {
    1794          14 :           Elf_Scn *scn = gelf_offscn (ebl->elf, phdr->p_offset);
    1795             :           GElf_Shdr shdr_mem;
    1796          14 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1797          14 :           if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC)
    1798          14 :             handle_dynamic (ebl, scn, shdr);
    1799             :           break;
    1800             :         }
    1801             :     }
    1802          34 : }
    1803             : 
    1804             : 
    1805             : /* Print relocations.  */
    1806             : static void
    1807          33 : print_relocs (Ebl *ebl, GElf_Ehdr *ehdr)
    1808             : {
    1809             :   /* Find all relocation sections and handle them.  */
    1810          33 :   Elf_Scn *scn = NULL;
    1811             : 
    1812         966 :   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    1813             :     {
    1814             :        /* Handle the section if it is a symbol table.  */
    1815             :       GElf_Shdr shdr_mem;
    1816         900 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1817             : 
    1818         900 :       if (likely (shdr != NULL))
    1819             :         {
    1820         900 :           if (shdr->sh_type == SHT_REL)
    1821           8 :             handle_relocs_rel (ebl, ehdr, scn, shdr);
    1822         892 :           else if (shdr->sh_type == SHT_RELA)
    1823         139 :             handle_relocs_rela (ebl, ehdr, scn, shdr);
    1824             :         }
    1825             :     }
    1826          33 : }
    1827             : 
    1828             : 
    1829             : /* Handle a relocation section.  */
    1830             : static void
    1831           8 : handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
    1832             : {
    1833           8 :   int class = gelf_getclass (ebl->elf);
    1834           8 :   size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_REL, 1, EV_CURRENT);
    1835           8 :   int nentries = shdr->sh_size / sh_entsize;
    1836             : 
    1837             :   /* Get the data of the section.  */
    1838           8 :   Elf_Data *data = elf_getdata (scn, NULL);
    1839           8 :   if (data == NULL)
    1840           0 :     return;
    1841             : 
    1842             :   /* Get the symbol table information.  */
    1843           8 :   Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
    1844             :   GElf_Shdr symshdr_mem;
    1845           8 :   GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
    1846           8 :   Elf_Data *symdata = elf_getdata (symscn, NULL);
    1847             : 
    1848             :   /* Get the section header of the section the relocations are for.  */
    1849             :   GElf_Shdr destshdr_mem;
    1850           8 :   GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
    1851             :                                       &destshdr_mem);
    1852             : 
    1853           8 :   if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
    1854             :     {
    1855           0 :       printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
    1856             :               shdr->sh_offset);
    1857             :       return;
    1858             :     }
    1859             : 
    1860             :   /* Search for the optional extended section index table.  */
    1861           8 :   Elf_Data *xndxdata = NULL;
    1862           8 :   int xndxscnidx = elf_scnshndx (scn);
    1863           8 :   if (unlikely (xndxscnidx > 0))
    1864           0 :     xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
    1865             : 
    1866             :   /* Get the section header string table index.  */
    1867             :   size_t shstrndx;
    1868           8 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    1869             :     error (EXIT_FAILURE, 0,
    1870           0 :            gettext ("cannot get section header string table index"));
    1871             : 
    1872           8 :   if (shdr->sh_info != 0)
    1873          24 :     printf (ngettext ("\
    1874             : \nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
    1875             :                     "\
    1876             : \nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
    1877             :                       nentries),
    1878             :             elf_ndxscn (scn),
    1879           8 :             elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    1880           8 :             (unsigned int) shdr->sh_info,
    1881           8 :             elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
    1882             :             shdr->sh_offset,
    1883             :             nentries);
    1884             :   else
    1885             :     /* The .rel.dyn section does not refer to a specific section but
    1886             :        instead of section index zero.  Do not try to print a section
    1887             :        name.  */
    1888           0 :     printf (ngettext ("\
    1889             : \nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
    1890             :                     "\
    1891             : \nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
    1892             :                       nentries),
    1893           0 :             (unsigned int) elf_ndxscn (scn),
    1894           0 :             elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    1895             :             shdr->sh_offset,
    1896             :             nentries);
    1897           8 :   fputs_unlocked (class == ELFCLASS32
    1898             :                   ? gettext ("\
    1899             :   Offset      Type                 Value       Name\n")
    1900             :                   : gettext ("\
    1901             :   Offset              Type                 Value               Name\n"),
    1902             :          stdout);
    1903             : 
    1904           8 :   int is_statically_linked = 0;
    1905          33 :   for (int cnt = 0; cnt < nentries; ++cnt)
    1906             :     {
    1907             :       GElf_Rel relmem;
    1908          25 :       GElf_Rel *rel = gelf_getrel (data, cnt, &relmem);
    1909          25 :       if (likely (rel != NULL))
    1910             :         {
    1911             :           char buf[128];
    1912             :           GElf_Sym symmem;
    1913             :           Elf32_Word xndx;
    1914          25 :           GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
    1915          25 :                                             GELF_R_SYM (rel->r_info),
    1916             :                                             &symmem, &xndx);
    1917          25 :           if (unlikely (sym == NULL))
    1918             :             {
    1919             :               /* As a special case we have to handle relocations in static
    1920             :                  executables.  This only happens for IRELATIVE relocations
    1921             :                  (so far).  There is no symbol table.  */
    1922           0 :               if (is_statically_linked == 0)
    1923             :                 {
    1924             :                   /* Find the program header and look for a PT_INTERP entry. */
    1925           0 :                   is_statically_linked = -1;
    1926           0 :                   if (ehdr->e_type == ET_EXEC)
    1927             :                     {
    1928             :                       is_statically_linked = 1;
    1929             : 
    1930           0 :                       for (size_t inner = 0; inner < phnum; ++inner)
    1931             :                         {
    1932             :                           GElf_Phdr phdr_mem;
    1933           0 :                           GElf_Phdr *phdr = gelf_getphdr (ebl->elf, inner,
    1934             :                                                           &phdr_mem);
    1935           0 :                           if (phdr != NULL && phdr->p_type == PT_INTERP)
    1936             :                             {
    1937           0 :                               is_statically_linked = -1;
    1938           0 :                               break;
    1939             :                             }
    1940             :                         }
    1941             :                     }
    1942             :                 }
    1943             : 
    1944           0 :               if (is_statically_linked > 0 && shdr->sh_link == 0)
    1945           0 :                 printf ("\
    1946             :   %#0*" PRIx64 "  %-20s %*s  %s\n",
    1947             :                         class == ELFCLASS32 ? 10 : 18, rel->r_offset,
    1948           0 :                         ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    1949             :                         /* Avoid the leading R_ which isn't carrying any
    1950             :                            information.  */
    1951           0 :                         ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    1952             :                                                buf, sizeof (buf)) + 2
    1953             :                         : gettext ("<INVALID RELOC>"),
    1954             :                         class == ELFCLASS32 ? 10 : 18, "",
    1955           0 :                         elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
    1956             :               else
    1957           0 :                 printf ("  %#0*" PRIx64 "  %-20s <%s %ld>\n",
    1958             :                         class == ELFCLASS32 ? 10 : 18, rel->r_offset,
    1959           0 :                         ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    1960             :                         /* Avoid the leading R_ which isn't carrying any
    1961             :                            information.  */
    1962           0 :                         ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    1963             :                                                buf, sizeof (buf)) + 2
    1964             :                         : gettext ("<INVALID RELOC>"),
    1965             :                         gettext ("INVALID SYMBOL"),
    1966           0 :                         (long int) GELF_R_SYM (rel->r_info));
    1967             :             }
    1968          25 :           else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
    1969          68 :             printf ("  %#0*" PRIx64 "  %-20s %#0*" PRIx64 "  %s\n",
    1970             :                     class == ELFCLASS32 ? 10 : 18, rel->r_offset,
    1971          17 :                     likely (ebl_reloc_type_check (ebl,
    1972             :                                                   GELF_R_TYPE (rel->r_info)))
    1973             :                     /* Avoid the leading R_ which isn't carrying any
    1974             :                        information.  */
    1975          17 :                     ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    1976             :                                            buf, sizeof (buf)) + 2
    1977             :                     : gettext ("<INVALID RELOC>"),
    1978             :                     class == ELFCLASS32 ? 10 : 18, sym->st_value,
    1979          34 :                     elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name));
    1980             :           else
    1981             :             {
    1982             :               /* This is a relocation against a STT_SECTION symbol.  */
    1983             :               GElf_Shdr secshdr_mem;
    1984             :               GElf_Shdr *secshdr;
    1985           8 :               secshdr = gelf_getshdr (elf_getscn (ebl->elf,
    1986           8 :                                                   sym->st_shndx == SHN_XINDEX
    1987           0 :                                                   ? xndx : sym->st_shndx),
    1988             :                                       &secshdr_mem);
    1989             : 
    1990           8 :               if (unlikely (secshdr == NULL))
    1991           0 :                 printf ("  %#0*" PRIx64 "  %-20s <%s %ld>\n",
    1992             :                         class == ELFCLASS32 ? 10 : 18, rel->r_offset,
    1993           0 :                         ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    1994             :                         /* Avoid the leading R_ which isn't carrying any
    1995             :                            information.  */
    1996           0 :                         ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    1997             :                                                buf, sizeof (buf)) + 2
    1998             :                         : gettext ("<INVALID RELOC>"),
    1999             :                         gettext ("INVALID SECTION"),
    2000           0 :                         (long int) (sym->st_shndx == SHN_XINDEX
    2001           0 :                                     ? xndx : sym->st_shndx));
    2002             :               else
    2003          24 :                 printf ("  %#0*" PRIx64 "  %-20s %#0*" PRIx64 "  %s\n",
    2004             :                         class == ELFCLASS32 ? 10 : 18, rel->r_offset,
    2005           8 :                         ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    2006             :                         /* Avoid the leading R_ which isn't carrying any
    2007             :                            information.  */
    2008           8 :                         ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    2009             :                                                buf, sizeof (buf)) + 2
    2010             :                         : gettext ("<INVALID RELOC>"),
    2011             :                         class == ELFCLASS32 ? 10 : 18, sym->st_value,
    2012           8 :                         elf_strptr (ebl->elf, shstrndx, secshdr->sh_name));
    2013             :             }
    2014             :         }
    2015             :     }
    2016             : }
    2017             : 
    2018             : 
    2019             : /* Handle a relocation section.  */
    2020             : static void
    2021         139 : handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
    2022             : {
    2023         139 :   int class = gelf_getclass (ebl->elf);
    2024         139 :   size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_RELA, 1, EV_CURRENT);
    2025         139 :   int nentries = shdr->sh_size / sh_entsize;
    2026             : 
    2027             :   /* Get the data of the section.  */
    2028         139 :   Elf_Data *data = elf_getdata (scn, NULL);
    2029         139 :   if (data == NULL)
    2030           0 :     return;
    2031             : 
    2032             :   /* Get the symbol table information.  */
    2033         139 :   Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
    2034             :   GElf_Shdr symshdr_mem;
    2035         139 :   GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
    2036         139 :   Elf_Data *symdata = elf_getdata (symscn, NULL);
    2037             : 
    2038             :   /* Get the section header of the section the relocations are for.  */
    2039             :   GElf_Shdr destshdr_mem;
    2040         139 :   GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
    2041             :                                       &destshdr_mem);
    2042             : 
    2043         139 :   if (unlikely (symshdr == NULL || symdata == NULL || destshdr == NULL))
    2044             :     {
    2045           0 :       printf (gettext ("\nInvalid symbol table at offset %#0" PRIx64 "\n"),
    2046             :               shdr->sh_offset);
    2047             :       return;
    2048             :     }
    2049             : 
    2050             :   /* Search for the optional extended section index table.  */
    2051         139 :   Elf_Data *xndxdata = NULL;
    2052         139 :   int xndxscnidx = elf_scnshndx (scn);
    2053         139 :   if (unlikely (xndxscnidx > 0))
    2054           0 :     xndxdata = elf_getdata (elf_getscn (ebl->elf, xndxscnidx), NULL);
    2055             : 
    2056             :   /* Get the section header string table index.  */
    2057             :   size_t shstrndx;
    2058         139 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    2059             :     error (EXIT_FAILURE, 0,
    2060           0 :            gettext ("cannot get section header string table index"));
    2061             : 
    2062         139 :   if (shdr->sh_info != 0)
    2063         381 :     printf (ngettext ("\
    2064             : \nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
    2065             :                     "\
    2066             : \nRelocation section [%2zu] '%s' for section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
    2067             :                     nentries),
    2068             :           elf_ndxscn (scn),
    2069         127 :           elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    2070         127 :           (unsigned int) shdr->sh_info,
    2071         127 :           elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
    2072             :           shdr->sh_offset,
    2073             :           nentries);
    2074             :   else
    2075             :     /* The .rela.dyn section does not refer to a specific section but
    2076             :        instead of section index zero.  Do not try to print a section
    2077             :        name.  */
    2078          36 :     printf (ngettext ("\
    2079             : \nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
    2080             :                     "\
    2081             : \nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
    2082             :                       nentries),
    2083          12 :             (unsigned int) elf_ndxscn (scn),
    2084          12 :             elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    2085             :             shdr->sh_offset,
    2086             :             nentries);
    2087         139 :   fputs_unlocked (class == ELFCLASS32
    2088             :                   ? gettext ("\
    2089             :   Offset      Type            Value       Addend Name\n")
    2090             :                   : gettext ("\
    2091             :   Offset              Type            Value               Addend Name\n"),
    2092             :                   stdout);
    2093             : 
    2094         139 :   int is_statically_linked = 0;
    2095       21824 :   for (int cnt = 0; cnt < nentries; ++cnt)
    2096             :     {
    2097             :       GElf_Rela relmem;
    2098       21685 :       GElf_Rela *rel = gelf_getrela (data, cnt, &relmem);
    2099       21685 :       if (likely (rel != NULL))
    2100             :         {
    2101             :           char buf[64];
    2102             :           GElf_Sym symmem;
    2103             :           Elf32_Word xndx;
    2104       21685 :           GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
    2105       21685 :                                             GELF_R_SYM (rel->r_info),
    2106             :                                             &symmem, &xndx);
    2107             : 
    2108       21685 :           if (unlikely (sym == NULL))
    2109             :             {
    2110             :               /* As a special case we have to handle relocations in static
    2111             :                  executables.  This only happens for IRELATIVE relocations
    2112             :                  (so far).  There is no symbol table.  */
    2113           0 :               if (is_statically_linked == 0)
    2114             :                 {
    2115             :                   /* Find the program header and look for a PT_INTERP entry. */
    2116           0 :                   is_statically_linked = -1;
    2117           0 :                   if (ehdr->e_type == ET_EXEC)
    2118             :                     {
    2119             :                       is_statically_linked = 1;
    2120             : 
    2121           0 :                       for (size_t inner = 0; inner < phnum; ++inner)
    2122             :                         {
    2123             :                           GElf_Phdr phdr_mem;
    2124           0 :                           GElf_Phdr *phdr = gelf_getphdr (ebl->elf, inner,
    2125             :                                                           &phdr_mem);
    2126           0 :                           if (phdr != NULL && phdr->p_type == PT_INTERP)
    2127             :                             {
    2128           0 :                               is_statically_linked = -1;
    2129           0 :                               break;
    2130             :                             }
    2131             :                         }
    2132             :                     }
    2133             :                 }
    2134             : 
    2135           0 :               if (is_statically_linked > 0 && shdr->sh_link == 0)
    2136           0 :                 printf ("\
    2137             :   %#0*" PRIx64 "  %-15s %*s  %#6" PRIx64 " %s\n",
    2138             :                         class == ELFCLASS32 ? 10 : 18, rel->r_offset,
    2139           0 :                         ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    2140             :                         /* Avoid the leading R_ which isn't carrying any
    2141             :                            information.  */
    2142           0 :                         ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    2143             :                                                buf, sizeof (buf)) + 2
    2144             :                         : gettext ("<INVALID RELOC>"),
    2145             :                         class == ELFCLASS32 ? 10 : 18, "",
    2146             :                         rel->r_addend,
    2147           0 :                         elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
    2148             :               else
    2149           0 :                 printf ("  %#0*" PRIx64 "  %-15s <%s %ld>\n",
    2150             :                         class == ELFCLASS32 ? 10 : 18, rel->r_offset,
    2151           0 :                         ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    2152             :                         /* Avoid the leading R_ which isn't carrying any
    2153             :                            information.  */
    2154           0 :                         ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    2155             :                                                buf, sizeof (buf)) + 2
    2156             :                         : gettext ("<INVALID RELOC>"),
    2157             :                         gettext ("INVALID SYMBOL"),
    2158           0 :                         (long int) GELF_R_SYM (rel->r_info));
    2159             :             }
    2160       21685 :           else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
    2161       23092 :             printf ("\
    2162             :   %#0*" PRIx64 "  %-15s %#0*" PRIx64 "  %+6" PRId64 " %s\n",
    2163             :                     class == ELFCLASS32 ? 10 : 18, rel->r_offset,
    2164        5773 :                     likely (ebl_reloc_type_check (ebl,
    2165             :                                                   GELF_R_TYPE (rel->r_info)))
    2166             :                     /* Avoid the leading R_ which isn't carrying any
    2167             :                        information.  */
    2168        5773 :                     ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    2169             :                                            buf, sizeof (buf)) + 2
    2170             :                     : gettext ("<INVALID RELOC>"),
    2171             :                     class == ELFCLASS32 ? 10 : 18, sym->st_value,
    2172             :                     rel->r_addend,
    2173       11546 :                     elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name));
    2174             :           else
    2175             :             {
    2176             :               /* This is a relocation against a STT_SECTION symbol.  */
    2177             :               GElf_Shdr secshdr_mem;
    2178             :               GElf_Shdr *secshdr;
    2179       15912 :               secshdr = gelf_getshdr (elf_getscn (ebl->elf,
    2180       15912 :                                                   sym->st_shndx == SHN_XINDEX
    2181           0 :                                                   ? xndx : sym->st_shndx),
    2182             :                                       &secshdr_mem);
    2183             : 
    2184       15912 :               if (unlikely (secshdr == NULL))
    2185           0 :                 printf ("  %#0*" PRIx64 "  %-15s <%s %ld>\n",
    2186             :                         class == ELFCLASS32 ? 10 : 18, rel->r_offset,
    2187           0 :                         ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    2188             :                         /* Avoid the leading R_ which isn't carrying any
    2189             :                            information.  */
    2190           0 :                         ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    2191             :                                                buf, sizeof (buf)) + 2
    2192             :                         : gettext ("<INVALID RELOC>"),
    2193             :                         gettext ("INVALID SECTION"),
    2194           0 :                         (long int) (sym->st_shndx == SHN_XINDEX
    2195           0 :                                     ? xndx : sym->st_shndx));
    2196             :               else
    2197       47736 :                 printf ("\
    2198             :   %#0*" PRIx64 "  %-15s %#0*" PRIx64 "  %+6" PRId64 " %s\n",
    2199             :                         class == ELFCLASS32 ? 10 : 18, rel->r_offset,
    2200       15912 :                         ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    2201             :                         /* Avoid the leading R_ which isn't carrying any
    2202             :                            information.  */
    2203       15912 :                         ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    2204             :                                                buf, sizeof (buf)) + 2
    2205             :                         : gettext ("<INVALID RELOC>"),
    2206             :                         class == ELFCLASS32 ? 10 : 18, sym->st_value,
    2207             :                         rel->r_addend,
    2208       15912 :                         elf_strptr (ebl->elf, shstrndx, secshdr->sh_name));
    2209             :             }
    2210             :         }
    2211             :     }
    2212             : }
    2213             : 
    2214             : 
    2215             : /* Print the program header.  */
    2216             : static void
    2217          92 : print_symtab (Ebl *ebl, int type)
    2218             : {
    2219             :   /* Find the symbol table(s).  For this we have to search through the
    2220             :      section table.  */
    2221          92 :   Elf_Scn *scn = NULL;
    2222             : 
    2223        2674 :   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    2224             :     {
    2225             :       /* Handle the section if it is a symbol table.  */
    2226             :       GElf_Shdr shdr_mem;
    2227        2490 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    2228             : 
    2229        2490 :       if (shdr != NULL && shdr->sh_type == (GElf_Word) type)
    2230             :         {
    2231          58 :           if (symbol_table_section != NULL)
    2232             :             {
    2233             :               /* Get the section header string table index.  */
    2234             :               size_t shstrndx;
    2235             :               const char *sname;
    2236           4 :               if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    2237             :                 error (EXIT_FAILURE, 0,
    2238           0 :                        gettext ("cannot get section header string table index"));
    2239           4 :               sname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
    2240           4 :               if (sname == NULL || strcmp (sname, symbol_table_section) != 0)
    2241           2 :                 continue;
    2242             :             }
    2243             : 
    2244          56 :           if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    2245             :             {
    2246           0 :               if (elf_compress (scn, 0, 0) < 0)
    2247           0 :                 printf ("WARNING: %s [%zd]\n",
    2248             :                         gettext ("Couldn't uncompress section"),
    2249             :                         elf_ndxscn (scn));
    2250           0 :               shdr = gelf_getshdr (scn, &shdr_mem);
    2251           0 :               if (unlikely (shdr == NULL))
    2252           0 :                 error (EXIT_FAILURE, 0,
    2253           0 :                        gettext ("cannot get section [%zd] header: %s"),
    2254             :                        elf_ndxscn (scn), elf_errmsg (-1));
    2255             :             }
    2256          56 :           handle_symtab (ebl, scn, shdr);
    2257             :         }
    2258             :     }
    2259          92 : }
    2260             : 
    2261             : 
    2262             : static void
    2263          56 : handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
    2264             : {
    2265          56 :   Elf_Data *versym_data = NULL;
    2266          56 :   Elf_Data *verneed_data = NULL;
    2267          56 :   Elf_Data *verdef_data = NULL;
    2268          56 :   Elf_Data *xndx_data = NULL;
    2269          56 :   int class = gelf_getclass (ebl->elf);
    2270          56 :   Elf32_Word verneed_stridx = 0;
    2271          56 :   Elf32_Word verdef_stridx = 0;
    2272             : 
    2273             :   /* Get the data of the section.  */
    2274          56 :   Elf_Data *data = elf_getdata (scn, NULL);
    2275          56 :   if (data == NULL)
    2276           0 :     return;
    2277             : 
    2278             :   /* Find out whether we have other sections we might need.  */
    2279             :   Elf_Scn *runscn = NULL;
    2280        1699 :   while ((runscn = elf_nextscn (ebl->elf, runscn)) != NULL)
    2281             :     {
    2282             :       GElf_Shdr runshdr_mem;
    2283        1643 :       GElf_Shdr *runshdr = gelf_getshdr (runscn, &runshdr_mem);
    2284             : 
    2285        1643 :       if (likely (runshdr != NULL))
    2286             :         {
    2287        1643 :           if (runshdr->sh_type == SHT_GNU_versym
    2288          31 :               && runshdr->sh_link == elf_ndxscn (scn))
    2289             :             /* Bingo, found the version information.  Now get the data.  */
    2290          19 :             versym_data = elf_getdata (runscn, NULL);
    2291        1624 :           else if (runshdr->sh_type == SHT_GNU_verneed)
    2292             :             {
    2293             :               /* This is the information about the needed versions.  */
    2294          31 :               verneed_data = elf_getdata (runscn, NULL);
    2295          31 :               verneed_stridx = runshdr->sh_link;
    2296             :             }
    2297        1593 :           else if (runshdr->sh_type == SHT_GNU_verdef)
    2298             :             {
    2299             :               /* This is the information about the defined versions.  */
    2300           8 :               verdef_data = elf_getdata (runscn, NULL);
    2301           8 :               verdef_stridx = runshdr->sh_link;
    2302             :             }
    2303        1585 :           else if (runshdr->sh_type == SHT_SYMTAB_SHNDX
    2304           0 :               && runshdr->sh_link == elf_ndxscn (scn))
    2305             :             /* Extended section index.  */
    2306           0 :             xndx_data = elf_getdata (runscn, NULL);
    2307             :         }
    2308             :     }
    2309             : 
    2310             :   /* Get the section header string table index.  */
    2311             :   size_t shstrndx;
    2312          56 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    2313             :     error (EXIT_FAILURE, 0,
    2314           0 :            gettext ("cannot get section header string table index"));
    2315             : 
    2316             :   GElf_Shdr glink_mem;
    2317          56 :   GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
    2318             :                                    &glink_mem);
    2319          56 :   if (glink == NULL)
    2320           0 :     error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %zu"),
    2321             :            elf_ndxscn (scn));
    2322             : 
    2323             :   /* Now we can compute the number of entries in the section.  */
    2324         112 :   unsigned int nsyms = data->d_size / (class == ELFCLASS32
    2325             :                                        ? sizeof (Elf32_Sym)
    2326          56 :                                        : sizeof (Elf64_Sym));
    2327             : 
    2328         168 :   printf (ngettext ("\nSymbol table [%2u] '%s' contains %u entry:\n",
    2329             :                     "\nSymbol table [%2u] '%s' contains %u entries:\n",
    2330             :                     nsyms),
    2331          56 :           (unsigned int) elf_ndxscn (scn),
    2332          56 :           elf_strptr (ebl->elf, shstrndx, shdr->sh_name), nsyms);
    2333         168 :   printf (ngettext (" %lu local symbol  String table: [%2u] '%s'\n",
    2334             :                     " %lu local symbols  String table: [%2u] '%s'\n",
    2335             :                     shdr->sh_info),
    2336          56 :           (unsigned long int) shdr->sh_info,
    2337          56 :           (unsigned int) shdr->sh_link,
    2338          56 :           elf_strptr (ebl->elf, shstrndx, glink->sh_name));
    2339             : 
    2340          56 :   fputs_unlocked (class == ELFCLASS32
    2341             :                   ? gettext ("\
    2342             :   Num:    Value   Size Type    Bind   Vis          Ndx Name\n")
    2343             :                   : gettext ("\
    2344             :   Num:            Value   Size Type    Bind   Vis          Ndx Name\n"),
    2345             :                   stdout);
    2346             : 
    2347       17150 :   for (unsigned int cnt = 0; cnt < nsyms; ++cnt)
    2348             :     {
    2349             :       char typebuf[64];
    2350             :       char bindbuf[64];
    2351             :       char scnbuf[64];
    2352             :       Elf32_Word xndx;
    2353             :       GElf_Sym sym_mem;
    2354       17094 :       GElf_Sym *sym = gelf_getsymshndx (data, xndx_data, cnt, &sym_mem, &xndx);
    2355             : 
    2356       17094 :       if (unlikely (sym == NULL))
    2357           0 :         continue;
    2358             : 
    2359             :       /* Determine the real section index.  */
    2360       17094 :       if (likely (sym->st_shndx != SHN_XINDEX))
    2361       17094 :         xndx = sym->st_shndx;
    2362             : 
    2363      119658 :       printf (gettext ("\
    2364             : %5u: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"),
    2365             :               cnt,
    2366             :               class == ELFCLASS32 ? 8 : 16,
    2367             :               sym->st_value,
    2368             :               sym->st_size,
    2369       17094 :               ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info),
    2370             :                                     typebuf, sizeof (typebuf)),
    2371       17094 :               ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info),
    2372             :                                        bindbuf, sizeof (bindbuf)),
    2373       17094 :               get_visibility_type (GELF_ST_VISIBILITY (sym->st_other)),
    2374       17094 :               ebl_section_name (ebl, sym->st_shndx, xndx, scnbuf,
    2375             :                                 sizeof (scnbuf), NULL, shnum),
    2376       34188 :               elf_strptr (ebl->elf, shdr->sh_link, sym->st_name));
    2377             : 
    2378       17094 :       if (versym_data != NULL)
    2379             :         {
    2380             :           /* Get the version information.  */
    2381             :           GElf_Versym versym_mem;
    2382        1562 :           GElf_Versym *versym = gelf_getversym (versym_data, cnt, &versym_mem);
    2383             : 
    2384        1562 :           if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1))
    2385             :             {
    2386        1322 :               bool is_nobits = false;
    2387        1322 :               bool check_def = xndx != SHN_UNDEF;
    2388             : 
    2389        1322 :               if (xndx < SHN_LORESERVE || sym->st_shndx == SHN_XINDEX)
    2390             :                 {
    2391             :                   GElf_Shdr symshdr_mem;
    2392        1289 :                   GElf_Shdr *symshdr =
    2393        1289 :                     gelf_getshdr (elf_getscn (ebl->elf, xndx), &symshdr_mem);
    2394             : 
    2395        1289 :                   is_nobits = (symshdr != NULL
    2396        1289 :                                && symshdr->sh_type == SHT_NOBITS);
    2397             :                 }
    2398             : 
    2399        1322 :               if (is_nobits || ! check_def)
    2400             :                 {
    2401             :                   /* We must test both.  */
    2402             :                   GElf_Vernaux vernaux_mem;
    2403         955 :                   GElf_Vernaux *vernaux = NULL;
    2404         955 :                   size_t vn_offset = 0;
    2405             : 
    2406             :                   GElf_Verneed verneed_mem;
    2407         955 :                   GElf_Verneed *verneed = gelf_getverneed (verneed_data, 0,
    2408             :                                                            &verneed_mem);
    2409        4860 :                   while (verneed != NULL)
    2410             :                     {
    2411        3905 :                       size_t vna_offset = vn_offset;
    2412             : 
    2413        3905 :                       vernaux = gelf_getvernaux (verneed_data,
    2414        3905 :                                                  vna_offset += verneed->vn_aux,
    2415             :                                                  &vernaux_mem);
    2416       11220 :                       while (vernaux != NULL
    2417        7315 :                              && vernaux->vna_other != *versym
    2418        6360 :                              && vernaux->vna_next != 0)
    2419             :                         {
    2420             :                           /* Update the offset.  */
    2421        3410 :                           vna_offset += vernaux->vna_next;
    2422             : 
    2423        3410 :                           vernaux = (vernaux->vna_next == 0
    2424             :                                      ? NULL
    2425        3410 :                                      : gelf_getvernaux (verneed_data,
    2426             :                                                         vna_offset,
    2427             :                                                         &vernaux_mem));
    2428             :                         }
    2429             : 
    2430             :                       /* Check whether we found the version.  */
    2431        3905 :                       if (vernaux != NULL && vernaux->vna_other == *versym)
    2432             :                         /* Found it.  */
    2433             :                         break;
    2434             : 
    2435        2950 :                       vn_offset += verneed->vn_next;
    2436             :                       verneed = (verneed->vn_next == 0
    2437             :                                  ? NULL
    2438        2950 :                                  : gelf_getverneed (verneed_data, vn_offset,
    2439             :                                                     &verneed_mem));
    2440             :                     }
    2441             : 
    2442         955 :                   if (vernaux != NULL && vernaux->vna_other == *versym)
    2443             :                     {
    2444        2865 :                       printf ("@%s (%u)",
    2445             :                               elf_strptr (ebl->elf, verneed_stridx,
    2446         955 :                                           vernaux->vna_name),
    2447             :                               (unsigned int) vernaux->vna_other);
    2448         955 :                       check_def = 0;
    2449             :                     }
    2450           0 :                   else if (unlikely (! is_nobits))
    2451           0 :                     error (0, 0, gettext ("bad dynamic symbol"));
    2452             :                   else
    2453             :                     check_def = 1;
    2454             :                 }
    2455             : 
    2456         367 :               if (check_def && *versym != 0x8001)
    2457             :                 {
    2458             :                   /* We must test both.  */
    2459         367 :                   size_t vd_offset = 0;
    2460             : 
    2461             :                   GElf_Verdef verdef_mem;
    2462         367 :                   GElf_Verdef *verdef = gelf_getverdef (verdef_data, 0,
    2463             :                                                         &verdef_mem);
    2464        2617 :                   while (verdef != NULL)
    2465             :                     {
    2466        2250 :                       if (verdef->vd_ndx == (*versym & 0x7fff))
    2467             :                         /* Found the definition.  */
    2468             :                         break;
    2469             : 
    2470        1883 :                       vd_offset += verdef->vd_next;
    2471             :                       verdef = (verdef->vd_next == 0
    2472             :                                 ? NULL
    2473        1883 :                                 : gelf_getverdef (verdef_data, vd_offset,
    2474             :                                                   &verdef_mem));
    2475             :                     }
    2476             : 
    2477         367 :                   if (verdef != NULL)
    2478             :                     {
    2479             :                       GElf_Verdaux verdaux_mem;
    2480         367 :                       GElf_Verdaux *verdaux
    2481         367 :                         = gelf_getverdaux (verdef_data,
    2482         367 :                                            vd_offset + verdef->vd_aux,
    2483             :                                            &verdaux_mem);
    2484             : 
    2485         367 :                       if (verdaux != NULL)
    2486         367 :                         printf ((*versym & 0x8000) ? "@%s" : "@@%s",
    2487             :                                 elf_strptr (ebl->elf, verdef_stridx,
    2488         367 :                                             verdaux->vda_name));
    2489             :                     }
    2490             :                 }
    2491             :             }
    2492             :         }
    2493             : 
    2494       17094 :       putchar_unlocked ('\n');
    2495             :     }
    2496             : }
    2497             : 
    2498             : 
    2499             : /* Print version information.  */
    2500             : static void
    2501          32 : print_verinfo (Ebl *ebl)
    2502             : {
    2503             :   /* Find the version information sections.  For this we have to
    2504             :      search through the section table.  */
    2505          32 :   Elf_Scn *scn = NULL;
    2506             : 
    2507         930 :   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    2508             :     {
    2509             :       /* Handle the section if it is part of the versioning handling.  */
    2510             :       GElf_Shdr shdr_mem;
    2511         866 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    2512             : 
    2513         866 :       if (likely (shdr != NULL))
    2514             :         {
    2515         866 :           if (shdr->sh_type == SHT_GNU_verneed)
    2516          12 :             handle_verneed (ebl, scn, shdr);
    2517         854 :           else if (shdr->sh_type == SHT_GNU_verdef)
    2518           4 :             handle_verdef (ebl, scn, shdr);
    2519         850 :           else if (shdr->sh_type == SHT_GNU_versym)
    2520          12 :             handle_versym (ebl, scn, shdr);
    2521             :         }
    2522             :     }
    2523          32 : }
    2524             : 
    2525             : 
    2526             : static const char *
    2527         132 : get_ver_flags (unsigned int flags)
    2528             : {
    2529             :   static char buf[32];
    2530             :   char *endp;
    2531             : 
    2532         132 :   if (flags == 0)
    2533         127 :     return gettext ("none");
    2534             : 
    2535           5 :   if (flags & VER_FLG_BASE)
    2536           4 :     endp = stpcpy (buf, "BASE ");
    2537             :   else
    2538             :     endp = buf;
    2539             : 
    2540           5 :   if (flags & VER_FLG_WEAK)
    2541             :     {
    2542           1 :       if (endp != buf)
    2543           0 :         endp = stpcpy (endp, "| ");
    2544             : 
    2545           1 :       endp = stpcpy (endp, "WEAK ");
    2546             :     }
    2547             : 
    2548           5 :   if (unlikely (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)))
    2549             :     {
    2550           0 :       strncpy (endp, gettext ("| <unknown>"), buf + sizeof (buf) - endp);
    2551           0 :       buf[sizeof (buf) - 1] = '\0';
    2552             :     }
    2553             : 
    2554             :   return buf;
    2555             : }
    2556             : 
    2557             : 
    2558             : static void
    2559          12 : handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
    2560             : {
    2561          12 :   int class = gelf_getclass (ebl->elf);
    2562             : 
    2563             :   /* Get the data of the section.  */
    2564          12 :   Elf_Data *data = elf_getdata (scn, NULL);
    2565          12 :   if (data == NULL)
    2566           0 :     return;
    2567             : 
    2568             :   /* Get the section header string table index.  */
    2569             :   size_t shstrndx;
    2570          12 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    2571             :     error (EXIT_FAILURE, 0,
    2572           0 :            gettext ("cannot get section header string table index"));
    2573             : 
    2574             :   GElf_Shdr glink_mem;
    2575          12 :   GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
    2576             :                                    &glink_mem);
    2577          12 :   if (glink == NULL)
    2578           0 :     error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %zu"),
    2579             :            elf_ndxscn (scn));
    2580             : 
    2581          60 :   printf (ngettext ("\
    2582             : \nVersion needs section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 "  Offset: %#08" PRIx64 "  Link to section: [%2u] '%s'\n",
    2583             :                     "\
    2584             : \nVersion needs section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 "  Offset: %#08" PRIx64 "  Link to section: [%2u] '%s'\n",
    2585             :                     shdr->sh_info),
    2586          12 :           (unsigned int) elf_ndxscn (scn),
    2587          12 :           elf_strptr (ebl->elf, shstrndx, shdr->sh_name), shdr->sh_info,
    2588             :           class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
    2589             :           shdr->sh_offset,
    2590          12 :           (unsigned int) shdr->sh_link,
    2591          12 :           elf_strptr (ebl->elf, shstrndx, glink->sh_name));
    2592             : 
    2593          12 :   unsigned int offset = 0;
    2594          58 :   for (int cnt = shdr->sh_info; --cnt >= 0; )
    2595             :     {
    2596             :       /* Get the data at the next offset.  */
    2597             :       GElf_Verneed needmem;
    2598          46 :       GElf_Verneed *need = gelf_getverneed (data, offset, &needmem);
    2599          46 :       if (unlikely (need == NULL))
    2600             :         break;
    2601             : 
    2602         230 :       printf (gettext ("  %#06x: Version: %hu  File: %s  Cnt: %hu\n"),
    2603          46 :               offset, (unsigned short int) need->vn_version,
    2604          92 :               elf_strptr (ebl->elf, shdr->sh_link, need->vn_file),
    2605          46 :               (unsigned short int) need->vn_cnt);
    2606             : 
    2607          46 :       unsigned int auxoffset = offset + need->vn_aux;
    2608         141 :       for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
    2609             :         {
    2610             :           GElf_Vernaux auxmem;
    2611          95 :           GElf_Vernaux *aux = gelf_getvernaux (data, auxoffset, &auxmem);
    2612          95 :           if (unlikely (aux == NULL))
    2613             :             break;
    2614             : 
    2615         475 :           printf (gettext ("  %#06x: Name: %s  Flags: %s  Version: %hu\n"),
    2616             :                   auxoffset,
    2617         190 :                   elf_strptr (ebl->elf, shdr->sh_link, aux->vna_name),
    2618          95 :                   get_ver_flags (aux->vna_flags),
    2619          95 :                   (unsigned short int) aux->vna_other);
    2620             : 
    2621          95 :           if (aux->vna_next == 0)
    2622             :             break;
    2623             : 
    2624          49 :           auxoffset += aux->vna_next;
    2625             :         }
    2626             : 
    2627             :       /* Find the next offset.  */
    2628          46 :       if (need->vn_next == 0)
    2629             :         break;
    2630             : 
    2631          34 :       offset += need->vn_next;
    2632             :     }
    2633             : }
    2634             : 
    2635             : 
    2636             : static void
    2637           4 : handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
    2638             : {
    2639             :   /* Get the data of the section.  */
    2640           4 :   Elf_Data *data = elf_getdata (scn, NULL);
    2641           4 :   if (data == NULL)
    2642           0 :     return;
    2643             : 
    2644             :   /* Get the section header string table index.  */
    2645             :   size_t shstrndx;
    2646           4 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    2647             :     error (EXIT_FAILURE, 0,
    2648           0 :            gettext ("cannot get section header string table index"));
    2649             : 
    2650             :   GElf_Shdr glink_mem;
    2651           4 :   GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
    2652             :                                    &glink_mem);
    2653           4 :   if (glink == NULL)
    2654           0 :     error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %zu"),
    2655             :            elf_ndxscn (scn));
    2656             : 
    2657           4 :   int class = gelf_getclass (ebl->elf);
    2658          20 :   printf (ngettext ("\
    2659             : \nVersion definition section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 "  Offset: %#08" PRIx64 "  Link to section: [%2u] '%s'\n",
    2660             :                     "\
    2661             : \nVersion definition section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 "  Offset: %#08" PRIx64 "  Link to section: [%2u] '%s'\n",
    2662             :                     shdr->sh_info),
    2663           4 :           (unsigned int) elf_ndxscn (scn),
    2664           4 :           elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    2665             :           shdr->sh_info,
    2666             :           class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
    2667             :           shdr->sh_offset,
    2668           4 :           (unsigned int) shdr->sh_link,
    2669           4 :           elf_strptr (ebl->elf, shstrndx, glink->sh_name));
    2670             : 
    2671           4 :   unsigned int offset = 0;
    2672          41 :   for (int cnt = shdr->sh_info; --cnt >= 0; )
    2673             :     {
    2674             :       /* Get the data at the next offset.  */
    2675             :       GElf_Verdef defmem;
    2676          37 :       GElf_Verdef *def = gelf_getverdef (data, offset, &defmem);
    2677          37 :       if (unlikely (def == NULL))
    2678             :         break;
    2679             : 
    2680          37 :       unsigned int auxoffset = offset + def->vd_aux;
    2681             :       GElf_Verdaux auxmem;
    2682          37 :       GElf_Verdaux *aux = gelf_getverdaux (data, auxoffset, &auxmem);
    2683          37 :       if (unlikely (aux == NULL))
    2684             :         break;
    2685             : 
    2686         259 :       printf (gettext ("\
    2687             :   %#06x: Version: %hd  Flags: %s  Index: %hd  Cnt: %hd  Name: %s\n"),
    2688          37 :               offset, def->vd_version,
    2689          37 :               get_ver_flags (def->vd_flags),
    2690          37 :               def->vd_ndx,
    2691          37 :               def->vd_cnt,
    2692          74 :               elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name));
    2693             : 
    2694          37 :       auxoffset += aux->vda_next;
    2695          37 :       for (int cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2)
    2696             :         {
    2697          29 :           aux = gelf_getverdaux (data, auxoffset, &auxmem);
    2698          29 :           if (unlikely (aux == NULL))
    2699             :             break;
    2700             : 
    2701          87 :           printf (gettext ("  %#06x: Parent %d: %s\n"),
    2702             :                   auxoffset, cnt2,
    2703          58 :                   elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name));
    2704             : 
    2705          29 :           if (aux->vda_next == 0)
    2706             :             break;
    2707             : 
    2708           0 :           auxoffset += aux->vda_next;
    2709             :         }
    2710             : 
    2711             :       /* Find the next offset.  */
    2712          37 :       if (def->vd_next == 0)
    2713             :         break;
    2714          33 :       offset += def->vd_next;
    2715             :     }
    2716             : }
    2717             : 
    2718             : 
    2719             : static void
    2720          12 : handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
    2721             : {
    2722          12 :   int class = gelf_getclass (ebl->elf);
    2723             :   const char **vername;
    2724             :   const char **filename;
    2725             : 
    2726             :   /* Get the data of the section.  */
    2727          12 :   Elf_Data *data = elf_getdata (scn, NULL);
    2728          12 :   if (data == NULL)
    2729           0 :     return;
    2730             : 
    2731             :   /* Get the section header string table index.  */
    2732             :   size_t shstrndx;
    2733          12 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    2734             :     error (EXIT_FAILURE, 0,
    2735           0 :            gettext ("cannot get section header string table index"));
    2736             : 
    2737             :   /* We have to find the version definition section and extract the
    2738             :      version names.  */
    2739             :   Elf_Scn *defscn = NULL;
    2740             :   Elf_Scn *needscn = NULL;
    2741             : 
    2742             :   Elf_Scn *verscn = NULL;
    2743         440 :   while ((verscn = elf_nextscn (ebl->elf, verscn)) != NULL)
    2744             :     {
    2745             :       GElf_Shdr vershdr_mem;
    2746         428 :       GElf_Shdr *vershdr = gelf_getshdr (verscn, &vershdr_mem);
    2747             : 
    2748         428 :       if (likely (vershdr != NULL))
    2749             :         {
    2750         428 :           if (vershdr->sh_type == SHT_GNU_verdef)
    2751             :             defscn = verscn;
    2752         424 :           else if (vershdr->sh_type == SHT_GNU_verneed)
    2753          12 :             needscn = verscn;
    2754             :         }
    2755             :     }
    2756             : 
    2757             :   size_t nvername;
    2758          12 :   if (defscn != NULL || needscn != NULL)
    2759             :     {
    2760             :       /* We have a version information (better should have).  Now get
    2761             :          the version names.  First find the maximum version number.  */
    2762          12 :       nvername = 0;
    2763          12 :       if (defscn != NULL)
    2764             :         {
    2765             :           /* Run through the version definitions and find the highest
    2766             :              index.  */
    2767           4 :           unsigned int offset = 0;
    2768             :           Elf_Data *defdata;
    2769             :           GElf_Shdr defshdrmem;
    2770             :           GElf_Shdr *defshdr;
    2771             : 
    2772           4 :           defdata = elf_getdata (defscn, NULL);
    2773           4 :           if (unlikely (defdata == NULL))
    2774           0 :             return;
    2775             : 
    2776           4 :           defshdr = gelf_getshdr (defscn, &defshdrmem);
    2777           4 :           if (unlikely (defshdr == NULL))
    2778             :             return;
    2779             : 
    2780          33 :           for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
    2781             :             {
    2782             :               GElf_Verdef defmem;
    2783             :               GElf_Verdef *def;
    2784             : 
    2785             :               /* Get the data at the next offset.  */
    2786          37 :               def = gelf_getverdef (defdata, offset, &defmem);
    2787          37 :               if (unlikely (def == NULL))
    2788             :                 break;
    2789             : 
    2790          37 :               nvername = MAX (nvername, (size_t) (def->vd_ndx & 0x7fff));
    2791             : 
    2792          37 :               if (def->vd_next == 0)
    2793             :                 break;
    2794          33 :               offset += def->vd_next;
    2795             :             }
    2796             :         }
    2797          12 :       if (needscn != NULL)
    2798             :         {
    2799          12 :           unsigned int offset = 0;
    2800             :           Elf_Data *needdata;
    2801             :           GElf_Shdr needshdrmem;
    2802             :           GElf_Shdr *needshdr;
    2803             : 
    2804          12 :           needdata = elf_getdata (needscn, NULL);
    2805          12 :           if (unlikely (needdata == NULL))
    2806           0 :             return;
    2807             : 
    2808          12 :           needshdr = gelf_getshdr (needscn, &needshdrmem);
    2809          12 :           if (unlikely (needshdr == NULL))
    2810             :             return;
    2811             : 
    2812          34 :           for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
    2813             :             {
    2814             :               GElf_Verneed needmem;
    2815             :               GElf_Verneed *need;
    2816             :               unsigned int auxoffset;
    2817             :               int cnt2;
    2818             : 
    2819             :               /* Get the data at the next offset.  */
    2820          46 :               need = gelf_getverneed (needdata, offset, &needmem);
    2821          46 :               if (unlikely (need == NULL))
    2822             :                 break;
    2823             : 
    2824             :               /* Run through the auxiliary entries.  */
    2825          46 :               auxoffset = offset + need->vn_aux;
    2826         141 :               for (cnt2 = need->vn_cnt; --cnt2 >= 0; )
    2827             :                 {
    2828             :                   GElf_Vernaux auxmem;
    2829             :                   GElf_Vernaux *aux;
    2830             : 
    2831          95 :                   aux = gelf_getvernaux (needdata, auxoffset, &auxmem);
    2832          95 :                   if (unlikely (aux == NULL))
    2833             :                     break;
    2834             : 
    2835          95 :                   nvername = MAX (nvername,
    2836             :                                   (size_t) (aux->vna_other & 0x7fff));
    2837             : 
    2838          95 :                   if (aux->vna_next == 0)
    2839             :                     break;
    2840          49 :                   auxoffset += aux->vna_next;
    2841             :                 }
    2842             : 
    2843          46 :               if (need->vn_next == 0)
    2844             :                 break;
    2845          34 :               offset += need->vn_next;
    2846             :             }
    2847             :         }
    2848             : 
    2849             :       /* This is the number of versions we know about.  */
    2850          12 :       ++nvername;
    2851             : 
    2852             :       /* Allocate the array.  */
    2853          12 :       vername = (const char **) alloca (nvername * sizeof (const char *));
    2854          24 :       memset(vername, 0, nvername * sizeof (const char *));
    2855          12 :       filename = (const char **) alloca (nvername * sizeof (const char *));
    2856          24 :       memset(filename, 0, nvername * sizeof (const char *));
    2857             : 
    2858             :       /* Run through the data structures again and collect the strings.  */
    2859          12 :       if (defscn != NULL)
    2860             :         {
    2861             :           /* Run through the version definitions and find the highest
    2862             :              index.  */
    2863           4 :           unsigned int offset = 0;
    2864             :           Elf_Data *defdata;
    2865             :           GElf_Shdr defshdrmem;
    2866             :           GElf_Shdr *defshdr;
    2867             : 
    2868           4 :           defdata = elf_getdata (defscn, NULL);
    2869           4 :           if (unlikely (defdata == NULL))
    2870           0 :             return;
    2871             : 
    2872           4 :           defshdr = gelf_getshdr (defscn, &defshdrmem);
    2873           4 :           if (unlikely (defshdr == NULL))
    2874             :             return;
    2875             : 
    2876          33 :           for (unsigned int cnt = 0; cnt < defshdr->sh_info; ++cnt)
    2877             :             {
    2878             : 
    2879             :               /* Get the data at the next offset.  */
    2880             :               GElf_Verdef defmem;
    2881          37 :               GElf_Verdef *def = gelf_getverdef (defdata, offset, &defmem);
    2882          37 :               if (unlikely (def == NULL))
    2883             :                 break;
    2884             : 
    2885             :               GElf_Verdaux auxmem;
    2886          37 :               GElf_Verdaux *aux = gelf_getverdaux (defdata,
    2887          37 :                                                    offset + def->vd_aux,
    2888             :                                                    &auxmem);
    2889          37 :               if (unlikely (aux == NULL))
    2890             :                 break;
    2891             : 
    2892          37 :               vername[def->vd_ndx & 0x7fff]
    2893          74 :                 = elf_strptr (ebl->elf, defshdr->sh_link, aux->vda_name);
    2894          37 :               filename[def->vd_ndx & 0x7fff] = NULL;
    2895             : 
    2896          37 :               if (def->vd_next == 0)
    2897             :                 break;
    2898          33 :               offset += def->vd_next;
    2899             :             }
    2900             :         }
    2901          12 :       if (needscn != NULL)
    2902             :         {
    2903          12 :           unsigned int offset = 0;
    2904             : 
    2905          12 :           Elf_Data *needdata = elf_getdata (needscn, NULL);
    2906             :           GElf_Shdr needshdrmem;
    2907          12 :           GElf_Shdr *needshdr = gelf_getshdr (needscn, &needshdrmem);
    2908          12 :           if (unlikely (needdata == NULL || needshdr == NULL))
    2909           0 :             return;
    2910             : 
    2911          34 :           for (unsigned int cnt = 0; cnt < needshdr->sh_info; ++cnt)
    2912             :             {
    2913             :               /* Get the data at the next offset.  */
    2914             :               GElf_Verneed needmem;
    2915          46 :               GElf_Verneed *need = gelf_getverneed (needdata, offset,
    2916             :                                                     &needmem);
    2917          46 :               if (unlikely (need == NULL))
    2918             :                 break;
    2919             : 
    2920             :               /* Run through the auxiliary entries.  */
    2921          46 :               unsigned int auxoffset = offset + need->vn_aux;
    2922         141 :               for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
    2923             :                 {
    2924             :                   GElf_Vernaux auxmem;
    2925          95 :                   GElf_Vernaux *aux = gelf_getvernaux (needdata, auxoffset,
    2926             :                                                        &auxmem);
    2927          95 :                   if (unlikely (aux == NULL))
    2928             :                     break;
    2929             : 
    2930          95 :                   vername[aux->vna_other & 0x7fff]
    2931         190 :                     = elf_strptr (ebl->elf, needshdr->sh_link, aux->vna_name);
    2932          95 :                   filename[aux->vna_other & 0x7fff]
    2933         190 :                     = elf_strptr (ebl->elf, needshdr->sh_link, need->vn_file);
    2934             : 
    2935          95 :                   if (aux->vna_next == 0)
    2936             :                     break;
    2937          49 :                   auxoffset += aux->vna_next;
    2938             :                 }
    2939             : 
    2940          46 :               if (need->vn_next == 0)
    2941             :                 break;
    2942          34 :               offset += need->vn_next;
    2943             :             }
    2944             :         }
    2945             :     }
    2946             :   else
    2947             :     {
    2948             :       vername = NULL;
    2949             :       nvername = 1;
    2950             :       filename = NULL;
    2951             :     }
    2952             : 
    2953             :   GElf_Shdr glink_mem;
    2954          12 :   GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
    2955             :                                    &glink_mem);
    2956          12 :   size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_HALF, 1, EV_CURRENT);
    2957          12 :   if (glink == NULL)
    2958           0 :     error (EXIT_FAILURE, 0, gettext ("invalid sh_link value in section %zu"),
    2959             :            elf_ndxscn (scn));
    2960             : 
    2961             :   /* Print the header.  */
    2962          72 :   printf (ngettext ("\
    2963             : \nVersion symbols section [%2u] '%s' contains %d entry:\n Addr: %#0*" PRIx64 "  Offset: %#08" PRIx64 "  Link to section: [%2u] '%s'",
    2964             :                     "\
    2965             : \nVersion symbols section [%2u] '%s' contains %d entries:\n Addr: %#0*" PRIx64 "  Offset: %#08" PRIx64 "  Link to section: [%2u] '%s'",
    2966             :                     shdr->sh_size / sh_entsize),
    2967          12 :           (unsigned int) elf_ndxscn (scn),
    2968          12 :           elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    2969          12 :           (int) (shdr->sh_size / sh_entsize),
    2970             :           class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
    2971             :           shdr->sh_offset,
    2972          12 :           (unsigned int) shdr->sh_link,
    2973          12 :           elf_strptr (ebl->elf, shstrndx, glink->sh_name));
    2974             : 
    2975             :   /* Now we can finally look at the actual contents of this section.  */
    2976        1487 :   for (unsigned int cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt)
    2977             :     {
    2978        1475 :       if (cnt % 2 == 0)
    2979             :         printf ("\n %4d:", cnt);
    2980             : 
    2981             :       GElf_Versym symmem;
    2982        1475 :       GElf_Versym *sym = gelf_getversym (data, cnt, &symmem);
    2983        1475 :       if (sym == NULL)
    2984             :         break;
    2985             : 
    2986        1475 :       switch (*sym)
    2987             :         {
    2988             :           ssize_t n;
    2989         125 :         case 0:
    2990         125 :           fputs_unlocked (gettext ("   0 *local*                     "),
    2991             :                           stdout);
    2992             :           break;
    2993             : 
    2994          41 :         case 1:
    2995          41 :           fputs_unlocked (gettext ("   1 *global*                    "),
    2996             :                           stdout);
    2997             :           break;
    2998             : 
    2999        1309 :         default:
    3000        5236 :           n = printf ("%4d%c%s",
    3001        1309 :                       *sym & 0x7fff, *sym & 0x8000 ? 'h' : ' ',
    3002             :                       (vername != NULL
    3003        1309 :                        && (unsigned int) (*sym & 0x7fff) < nvername)
    3004        1309 :                       ? vername[*sym & 0x7fff] : "???");
    3005        1309 :           if ((unsigned int) (*sym & 0x7fff) < nvername
    3006        1309 :               && filename != NULL && filename[*sym & 0x7fff] != NULL)
    3007        1884 :             n += printf ("(%s)", filename[*sym & 0x7fff]);
    3008        1309 :           printf ("%*s", MAX (0, 33 - (int) n), " ");
    3009             :           break;
    3010             :         }
    3011             :     }
    3012          12 :   putchar_unlocked ('\n');
    3013             : }
    3014             : 
    3015             : 
    3016             : static void
    3017          12 : print_hash_info (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx,
    3018             :                  uint_fast32_t maxlength, Elf32_Word nbucket,
    3019             :                  uint_fast32_t nsyms, uint32_t *lengths, const char *extrastr)
    3020             : {
    3021          12 :   uint32_t *counts = (uint32_t *) xcalloc (maxlength + 1, sizeof (uint32_t));
    3022             : 
    3023         334 :   for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
    3024         322 :     ++counts[lengths[cnt]];
    3025             : 
    3026             :   GElf_Shdr glink_mem;
    3027          12 :   GElf_Shdr *glink = gelf_getshdr (elf_getscn (ebl->elf,
    3028          12 :                                                shdr->sh_link),
    3029             :                                    &glink_mem);
    3030          12 :   if (glink == NULL)
    3031             :     {
    3032           0 :       error (0, 0, gettext ("invalid sh_link value in section %zu"),
    3033             :              elf_ndxscn (scn));
    3034           0 :       return;
    3035             :     }
    3036             : 
    3037          72 :   printf (ngettext ("\
    3038             : \nHistogram for bucket list length in section [%2u] '%s' (total of %d bucket):\n Addr: %#0*" PRIx64 "  Offset: %#08" PRIx64 "  Link to section: [%2u] '%s'\n",
    3039             :                     "\
    3040             : \nHistogram for bucket list length in section [%2u] '%s' (total of %d buckets):\n Addr: %#0*" PRIx64 "  Offset: %#08" PRIx64 "  Link to section: [%2u] '%s'\n",
    3041             :                     nbucket),
    3042          12 :           (unsigned int) elf_ndxscn (scn),
    3043          12 :           elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    3044             :           (int) nbucket,
    3045          12 :           gelf_getclass (ebl->elf) == ELFCLASS32 ? 10 : 18,
    3046             :           shdr->sh_addr,
    3047             :           shdr->sh_offset,
    3048          12 :           (unsigned int) shdr->sh_link,
    3049          12 :           elf_strptr (ebl->elf, shstrndx, glink->sh_name));
    3050             : 
    3051          12 :   if (extrastr != NULL)
    3052          12 :     fputs (extrastr, stdout);
    3053             : 
    3054          12 :   if (likely (nbucket > 0))
    3055             :     {
    3056          12 :       uint64_t success = 0;
    3057             : 
    3058             :       /* xgettext:no-c-format */
    3059          12 :       fputs_unlocked (gettext ("\
    3060             :  Length  Number  % of total  Coverage\n"), stdout);
    3061          24 :       printf (gettext ("      0  %6" PRIu32 "      %5.1f%%\n"),
    3062          12 :               counts[0], (counts[0] * 100.0) / nbucket);
    3063             : 
    3064          12 :       uint64_t nzero_counts = 0;
    3065          67 :       for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
    3066             :         {
    3067          55 :           nzero_counts += counts[cnt] * cnt;
    3068         165 :           printf (gettext ("\
    3069             : %7d  %6" PRIu32 "      %5.1f%%    %5.1f%%\n"),
    3070          55 :                   (int) cnt, counts[cnt], (counts[cnt] * 100.0) / nbucket,
    3071          55 :                   (nzero_counts * 100.0) / nsyms);
    3072             :         }
    3073             : 
    3074             :       Elf32_Word acc = 0;
    3075          55 :       for (Elf32_Word cnt = 1; cnt <= maxlength; ++cnt)
    3076             :         {
    3077          55 :           acc += cnt;
    3078          55 :           success += counts[cnt] * acc;
    3079             :         }
    3080             : 
    3081          24 :       printf (gettext ("\
    3082             :  Average number of tests:   successful lookup: %f\n\
    3083             :                           unsuccessful lookup: %f\n"),
    3084          12 :               (double) success / (double) nzero_counts,
    3085          12 :               (double) nzero_counts / (double) nbucket);
    3086             :     }
    3087             : 
    3088          12 :   free (counts);
    3089             : }
    3090             : 
    3091             : 
    3092             : /* This function handles the traditional System V-style hash table format.  */
    3093             : static void
    3094           0 : handle_sysv_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
    3095             : {
    3096           0 :   Elf_Data *data = elf_getdata (scn, NULL);
    3097           0 :   if (unlikely (data == NULL))
    3098             :     {
    3099           0 :       error (0, 0, gettext ("cannot get data for section %d: %s"),
    3100           0 :              (int) elf_ndxscn (scn), elf_errmsg (-1));
    3101             :       return;
    3102             :     }
    3103             : 
    3104           0 :   if (unlikely (data->d_size < 2 * sizeof (Elf32_Word)))
    3105             :     {
    3106           0 :     invalid_data:
    3107           0 :       error (0, 0, gettext ("invalid data in sysv.hash section %d"),
    3108           0 :              (int) elf_ndxscn (scn));
    3109             :       return;
    3110             :     }
    3111             : 
    3112           0 :   Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
    3113           0 :   Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
    3114             : 
    3115           0 :   uint64_t used_buf = (2ULL + nchain + nbucket) * sizeof (Elf32_Word);
    3116           0 :   if (used_buf > data->d_size)
    3117             :     goto invalid_data;
    3118             : 
    3119           0 :   Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[2];
    3120           0 :   Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[2 + nbucket];
    3121             : 
    3122           0 :   uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
    3123             : 
    3124           0 :   uint_fast32_t maxlength = 0;
    3125           0 :   uint_fast32_t nsyms = 0;
    3126           0 :   for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
    3127             :     {
    3128           0 :       Elf32_Word inner = bucket[cnt];
    3129           0 :       while (inner > 0 && inner < nchain)
    3130             :         {
    3131           0 :           ++nsyms;
    3132           0 :           if (maxlength < ++lengths[cnt])
    3133           0 :             ++maxlength;
    3134             : 
    3135           0 :           inner = chain[inner];
    3136             :         }
    3137             :     }
    3138             : 
    3139           0 :   print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
    3140             :                    lengths, NULL);
    3141             : 
    3142           0 :   free (lengths);
    3143             : }
    3144             : 
    3145             : 
    3146             : /* This function handles the incorrect, System V-style hash table
    3147             :    format some 64-bit architectures use.  */
    3148             : static void
    3149           0 : handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
    3150             : {
    3151           0 :   Elf_Data *data = elf_getdata (scn, NULL);
    3152           0 :   if (unlikely (data == NULL))
    3153             :     {
    3154           0 :       error (0, 0, gettext ("cannot get data for section %d: %s"),
    3155           0 :              (int) elf_ndxscn (scn), elf_errmsg (-1));
    3156             :       return;
    3157             :     }
    3158             : 
    3159           0 :   if (unlikely (data->d_size < 2 * sizeof (Elf64_Xword)))
    3160             :     {
    3161           0 :     invalid_data:
    3162           0 :       error (0, 0, gettext ("invalid data in sysv.hash64 section %d"),
    3163           0 :              (int) elf_ndxscn (scn));
    3164             :       return;
    3165             :     }
    3166             : 
    3167           0 :   Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
    3168           0 :   Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
    3169             : 
    3170           0 :   uint64_t maxwords = data->d_size / sizeof (Elf64_Xword);
    3171           0 :   if (maxwords < 2
    3172           0 :       || maxwords - 2 < nbucket
    3173           0 :       || maxwords - 2 - nbucket < nchain)
    3174             :     goto invalid_data;
    3175             : 
    3176           0 :   Elf64_Xword *bucket = &((Elf64_Xword *) data->d_buf)[2];
    3177           0 :   Elf64_Xword *chain = &((Elf64_Xword *) data->d_buf)[2 + nbucket];
    3178             : 
    3179           0 :   uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
    3180             : 
    3181           0 :   uint_fast32_t maxlength = 0;
    3182           0 :   uint_fast32_t nsyms = 0;
    3183           0 :   for (Elf64_Xword cnt = 0; cnt < nbucket; ++cnt)
    3184             :     {
    3185           0 :       Elf64_Xword inner = bucket[cnt];
    3186           0 :       while (inner > 0 && inner < nchain)
    3187             :         {
    3188           0 :           ++nsyms;
    3189           0 :           if (maxlength < ++lengths[cnt])
    3190           0 :             ++maxlength;
    3191             : 
    3192           0 :           inner = chain[inner];
    3193             :         }
    3194             :     }
    3195             : 
    3196           0 :   print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
    3197             :                    lengths, NULL);
    3198             : 
    3199           0 :   free (lengths);
    3200             : }
    3201             : 
    3202             : 
    3203             : /* This function handles the GNU-style hash table format.  */
    3204             : static void
    3205          12 : handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
    3206             : {
    3207          12 :   uint32_t *lengths = NULL;
    3208          12 :   Elf_Data *data = elf_getdata (scn, NULL);
    3209          12 :   if (unlikely (data == NULL))
    3210             :     {
    3211           0 :       error (0, 0, gettext ("cannot get data for section %d: %s"),
    3212           0 :              (int) elf_ndxscn (scn), elf_errmsg (-1));
    3213           0 :       return;
    3214             :     }
    3215             : 
    3216          12 :   if (unlikely (data->d_size < 4 * sizeof (Elf32_Word)))
    3217             :     {
    3218           0 :     invalid_data:
    3219           0 :       free (lengths);
    3220           0 :       error (0, 0, gettext ("invalid data in gnu.hash section %d"),
    3221           0 :              (int) elf_ndxscn (scn));
    3222             :       return;
    3223             :     }
    3224             : 
    3225          12 :   Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
    3226          12 :   Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
    3227             : 
    3228             :   /* Next comes the size of the bitmap.  It's measured in words for
    3229             :      the architecture.  It's 32 bits for 32 bit archs, and 64 bits for
    3230             :      64 bit archs.  There is always a bloom filter present, so zero is
    3231             :      an invalid value.  */
    3232          12 :   Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2];
    3233          12 :   if (gelf_getclass (ebl->elf) == ELFCLASS64)
    3234          12 :     bitmask_words *= 2;
    3235             : 
    3236          12 :   if (bitmask_words == 0)
    3237             :     goto invalid_data;
    3238             : 
    3239          12 :   Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3];
    3240             : 
    3241             :   /* Is there still room for the sym chain?
    3242             :      Use uint64_t calculation to prevent 32bit overlow.  */
    3243          12 :   uint64_t used_buf = (4ULL + bitmask_words + nbucket) * sizeof (Elf32_Word);
    3244          12 :   uint32_t max_nsyms = (data->d_size - used_buf) / sizeof (Elf32_Word);
    3245          12 :   if (used_buf > data->d_size)
    3246             :     goto invalid_data;
    3247             : 
    3248          12 :   lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
    3249             : 
    3250          12 :   Elf32_Word *bitmask = &((Elf32_Word *) data->d_buf)[4];
    3251          12 :   Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[4 + bitmask_words];
    3252          12 :   Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[4 + bitmask_words
    3253          12 :                                                     + nbucket];
    3254             : 
    3255             :   /* Compute distribution of chain lengths.  */
    3256          12 :   uint_fast32_t maxlength = 0;
    3257          12 :   uint_fast32_t nsyms = 0;
    3258         334 :   for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
    3259         322 :     if (bucket[cnt] != 0)
    3260             :       {
    3261         226 :         Elf32_Word inner = bucket[cnt] - symbias;
    3262             :         do
    3263             :           {
    3264         438 :             ++nsyms;
    3265         438 :             if (maxlength < ++lengths[cnt])
    3266          55 :               ++maxlength;
    3267         438 :             if (inner >= max_nsyms)
    3268             :               goto invalid_data;
    3269             :           }
    3270         438 :         while ((chain[inner++] & 1) == 0);
    3271             :       }
    3272             : 
    3273             :   /* Count bits in bitmask.  */
    3274             :   uint_fast32_t nbits = 0;
    3275         118 :   for (Elf32_Word cnt = 0; cnt < bitmask_words; ++cnt)
    3276             :     {
    3277         118 :       uint_fast32_t word = bitmask[cnt];
    3278             : 
    3279         118 :       word = (word & 0x55555555) + ((word >> 1) & 0x55555555);
    3280         118 :       word = (word & 0x33333333) + ((word >> 2) & 0x33333333);
    3281         118 :       word = (word & 0x0f0f0f0f) + ((word >> 4) & 0x0f0f0f0f);
    3282         118 :       word = (word & 0x00ff00ff) + ((word >> 8) & 0x00ff00ff);
    3283         118 :       nbits += (word & 0x0000ffff) + ((word >> 16) & 0x0000ffff);
    3284             :     }
    3285             : 
    3286             :   char *str;
    3287          24 :   if (unlikely (asprintf (&str, gettext ("\
    3288             :  Symbol Bias: %u\n\
    3289             :  Bitmask Size: %zu bytes  %" PRIuFAST32 "%% bits set  2nd hash shift: %u\n"),
    3290             :                           (unsigned int) symbias,
    3291             :                           bitmask_words * sizeof (Elf32_Word),
    3292             :                           ((nbits * 100 + 50)
    3293             :                            / (uint_fast32_t) (bitmask_words
    3294             :                                               * sizeof (Elf32_Word) * 8)),
    3295             :                           (unsigned int) shift) == -1))
    3296           0 :     error (EXIT_FAILURE, 0, gettext ("memory exhausted"));
    3297             : 
    3298          12 :   print_hash_info (ebl, scn, shdr, shstrndx, maxlength, nbucket, nsyms,
    3299             :                    lengths, str);
    3300             : 
    3301          12 :   free (str);
    3302          12 :   free (lengths);
    3303             : }
    3304             : 
    3305             : 
    3306             : /* Find the symbol table(s).  For this we have to search through the
    3307             :    section table.  */
    3308             : static void
    3309          32 : handle_hash (Ebl *ebl)
    3310             : {
    3311             :   /* Get the section header string table index.  */
    3312             :   size_t shstrndx;
    3313          32 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    3314             :     error (EXIT_FAILURE, 0,
    3315           0 :            gettext ("cannot get section header string table index"));
    3316             : 
    3317             :   Elf_Scn *scn = NULL;
    3318         898 :   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    3319             :     {
    3320             :       /* Handle the section if it is a symbol table.  */
    3321             :       GElf_Shdr shdr_mem;
    3322         866 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    3323             : 
    3324         866 :       if (likely (shdr != NULL))
    3325             :         {
    3326         866 :           if ((shdr->sh_type == SHT_HASH || shdr->sh_type == SHT_GNU_HASH)
    3327          12 :               && (shdr->sh_flags & SHF_COMPRESSED) != 0)
    3328             :             {
    3329           0 :               if (elf_compress (scn, 0, 0) < 0)
    3330           0 :                 printf ("WARNING: %s [%zd]\n",
    3331             :                         gettext ("Couldn't uncompress section"),
    3332             :                         elf_ndxscn (scn));
    3333           0 :               shdr = gelf_getshdr (scn, &shdr_mem);
    3334           0 :               if (unlikely (shdr == NULL))
    3335           0 :                 error (EXIT_FAILURE, 0,
    3336           0 :                        gettext ("cannot get section [%zd] header: %s"),
    3337             :                        elf_ndxscn (scn), elf_errmsg (-1));
    3338             :             }
    3339             : 
    3340         866 :           if (shdr->sh_type == SHT_HASH)
    3341             :             {
    3342           0 :               if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword))
    3343           0 :                 handle_sysv_hash64 (ebl, scn, shdr, shstrndx);
    3344             :               else
    3345           0 :                 handle_sysv_hash (ebl, scn, shdr, shstrndx);
    3346             :             }
    3347         866 :           else if (shdr->sh_type == SHT_GNU_HASH)
    3348          12 :             handle_gnu_hash (ebl, scn, shdr, shstrndx);
    3349             :         }
    3350             :     }
    3351          32 : }
    3352             : 
    3353             : 
    3354             : static void
    3355          36 : print_liblist (Ebl *ebl)
    3356             : {
    3357             :   /* Find the library list sections.  For this we have to search
    3358             :      through the section table.  */
    3359          36 :   Elf_Scn *scn = NULL;
    3360             : 
    3361             :   /* Get the section header string table index.  */
    3362             :   size_t shstrndx;
    3363          36 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    3364             :     error (EXIT_FAILURE, 0,
    3365           0 :            gettext ("cannot get section header string table index"));
    3366             : 
    3367         961 :   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    3368             :     {
    3369             :       GElf_Shdr shdr_mem;
    3370         925 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    3371             : 
    3372         925 :       if (shdr != NULL && shdr->sh_type == SHT_GNU_LIBLIST)
    3373             :         {
    3374           0 :           size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_LIB, 1, EV_CURRENT);
    3375           0 :           int nentries = shdr->sh_size / sh_entsize;
    3376           0 :           printf (ngettext ("\
    3377             : \nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entry:\n",
    3378             :                             "\
    3379             : \nLibrary list section [%2zu] '%s' at offset %#0" PRIx64 " contains %d entries:\n",
    3380             :                             nentries),
    3381             :                   elf_ndxscn (scn),
    3382           0 :                   elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    3383             :                   shdr->sh_offset,
    3384             :                   nentries);
    3385             : 
    3386           0 :           Elf_Data *data = elf_getdata (scn, NULL);
    3387           0 :           if (data == NULL)
    3388           0 :             return;
    3389             : 
    3390           0 :           puts (gettext ("\
    3391             :        Library                       Time Stamp          Checksum Version Flags"));
    3392             : 
    3393           0 :           for (int cnt = 0; cnt < nentries; ++cnt)
    3394             :             {
    3395             :               GElf_Lib lib_mem;
    3396           0 :               GElf_Lib *lib = gelf_getlib (data, cnt, &lib_mem);
    3397           0 :               if (unlikely (lib == NULL))
    3398           0 :                 continue;
    3399             : 
    3400           0 :               time_t t = (time_t) lib->l_time_stamp;
    3401           0 :               struct tm *tm = gmtime (&t);
    3402           0 :               if (unlikely (tm == NULL))
    3403           0 :                 continue;
    3404             : 
    3405           0 :               printf ("  [%2d] %-29s %04u-%02u-%02uT%02u:%02u:%02u %08x %-7u %u\n",
    3406           0 :                       cnt, elf_strptr (ebl->elf, shdr->sh_link, lib->l_name),
    3407           0 :                       tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
    3408             :                       tm->tm_hour, tm->tm_min, tm->tm_sec,
    3409           0 :                       (unsigned int) lib->l_checksum,
    3410           0 :                       (unsigned int) lib->l_version,
    3411           0 :                       (unsigned int) lib->l_flags);
    3412             :             }
    3413             :         }
    3414             :     }
    3415             : }
    3416             : 
    3417             : static void
    3418          36 : print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr)
    3419             : {
    3420             :   /* Find the object attributes sections.  For this we have to search
    3421             :      through the section table.  */
    3422          36 :   Elf_Scn *scn = NULL;
    3423             : 
    3424             :   /* Get the section header string table index.  */
    3425             :   size_t shstrndx;
    3426          36 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    3427             :     error (EXIT_FAILURE, 0,
    3428           0 :            gettext ("cannot get section header string table index"));
    3429             : 
    3430         961 :   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    3431             :     {
    3432             :       GElf_Shdr shdr_mem;
    3433         925 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    3434             : 
    3435         925 :       if (shdr == NULL || (shdr->sh_type != SHT_GNU_ATTRIBUTES
    3436         922 :                            && (shdr->sh_type != SHT_ARM_ATTRIBUTES
    3437           1 :                                || ehdr->e_machine != EM_ARM)))
    3438         921 :         continue;
    3439             : 
    3440          12 :       printf (gettext ("\
    3441             : \nObject attributes section [%2zu] '%s' of %" PRIu64
    3442             :                        " bytes at offset %#0" PRIx64 ":\n"),
    3443             :               elf_ndxscn (scn),
    3444           4 :               elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    3445             :               shdr->sh_size, shdr->sh_offset);
    3446             : 
    3447           4 :       Elf_Data *data = elf_rawdata (scn, NULL);
    3448           4 :       if (unlikely (data == NULL || data->d_size == 0))
    3449           0 :         return;
    3450             : 
    3451           4 :       const unsigned char *p = data->d_buf;
    3452             : 
    3453             :       /* There is only one 'version', A.  */
    3454           4 :       if (unlikely (*p++ != 'A'))
    3455             :         return;
    3456             : 
    3457           4 :       fputs_unlocked (gettext ("  Owner          Size\n"), stdout);
    3458             : 
    3459             :       inline size_t left (void)
    3460             :       {
    3461           8 :         return (const unsigned char *) data->d_buf + data->d_size - p;
    3462             :       }
    3463             : 
    3464             :       /* Loop over the sections.  */
    3465           8 :       while (left () >= 4)
    3466             :         {
    3467             :           /* Section length.  */
    3468             :           uint32_t len;
    3469           4 :           memcpy (&len, p, sizeof len);
    3470             : 
    3471           4 :           if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
    3472           4 :             CONVERT (len);
    3473             : 
    3474           4 :           if (unlikely (len > left ()))
    3475             :             break;
    3476             : 
    3477             :           /* Section vendor name.  */
    3478           4 :           const unsigned char *name = p + sizeof len;
    3479           4 :           p += len;
    3480             : 
    3481           4 :           unsigned const char *q = memchr (name, '\0', len);
    3482           4 :           if (unlikely (q == NULL))
    3483             :             break;
    3484           4 :           ++q;
    3485             : 
    3486           8 :           printf (gettext ("  %-13s  %4" PRIu32 "\n"), name, len);
    3487             : 
    3488           8 :           bool gnu_vendor = (q - name == sizeof "gnu"
    3489           4 :                              && !memcmp (name, "gnu", sizeof "gnu"));
    3490             : 
    3491             :           /* Loop over subsections.  */
    3492           4 :           if (shdr->sh_type != SHT_GNU_ATTRIBUTES
    3493           3 :               || gnu_vendor)
    3494           8 :             while (q < p)
    3495             :               {
    3496           4 :                 const unsigned char *const sub = q;
    3497             : 
    3498             :                 unsigned int subsection_tag;
    3499           4 :                 get_uleb128 (subsection_tag, q, p);
    3500           4 :                 if (unlikely (q >= p))
    3501             :                   break;
    3502             : 
    3503             :                 uint32_t subsection_len;
    3504           4 :                 if (unlikely (p - sub < (ptrdiff_t) sizeof subsection_len))
    3505             :                   break;
    3506             : 
    3507           4 :                 memcpy (&subsection_len, q, sizeof subsection_len);
    3508             : 
    3509           4 :                 if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
    3510           4 :                   CONVERT (subsection_len);
    3511             : 
    3512             :                 /* Don't overflow, ptrdiff_t might be 32bits, but signed.  */
    3513           4 :                 if (unlikely (subsection_len == 0
    3514             :                               || subsection_len >= (uint32_t) PTRDIFF_MAX
    3515             :                               || p - sub < (ptrdiff_t) subsection_len))
    3516             :                   break;
    3517             : 
    3518           4 :                 const unsigned char *r = q + sizeof subsection_len;
    3519           4 :                 q = sub + subsection_len;
    3520             : 
    3521           4 :                 switch (subsection_tag)
    3522             :                   {
    3523           0 :                   default:
    3524             :                     /* Unknown subsection, print and skip.  */
    3525           0 :                     printf (gettext ("    %-4u %12" PRIu32 "\n"),
    3526             :                             subsection_tag, subsection_len);
    3527             :                     break;
    3528             : 
    3529           4 :                   case 1:       /* Tag_File */
    3530           4 :                     printf (gettext ("    File: %11" PRIu32 "\n"),
    3531             :                             subsection_len);
    3532             : 
    3533          26 :                     while (r < q)
    3534          22 :                       {
    3535             :                         unsigned int tag;
    3536          22 :                         get_uleb128 (tag, r, q);
    3537          22 :                         if (unlikely (r >= q))
    3538             :                           break;
    3539             : 
    3540             :                         /* GNU style tags have either a uleb128 value,
    3541             :                            when lowest bit is not set, or a string
    3542             :                            when the lowest bit is set.
    3543             :                            "compatibility" (32) is special.  It has
    3544             :                            both a string and a uleb128 value.  For
    3545             :                            non-gnu we assume 6 till 31 only take ints.
    3546             :                            XXX see arm backend, do we need a separate
    3547             :                            hook?  */
    3548          22 :                         uint64_t value = 0;
    3549          22 :                         const char *string = NULL;
    3550          22 :                         if (tag == 32 || (tag & 1) == 0
    3551           8 :                             || (! gnu_vendor && (tag > 5 && tag < 32)))
    3552             :                           {
    3553          21 :                             get_uleb128 (value, r, q);
    3554          21 :                             if (r > q)
    3555             :                               break;
    3556             :                           }
    3557          22 :                         if (tag == 32
    3558          22 :                             || ((tag & 1) != 0
    3559           8 :                                 && (gnu_vendor
    3560           8 :                                     || (! gnu_vendor && tag > 32)))
    3561          22 :                             || (! gnu_vendor && tag > 3 && tag < 6))
    3562             :                           {
    3563           1 :                             string = (const char *) r;
    3564           1 :                             r = memchr (r, '\0', q - r);
    3565           1 :                             if (r == NULL)
    3566             :                               break;
    3567           1 :                             ++r;
    3568             :                           }
    3569             : 
    3570          22 :                         const char *tag_name = NULL;
    3571          22 :                         const char *value_name = NULL;
    3572          22 :                         ebl_check_object_attribute (ebl, (const char *) name,
    3573             :                                                     tag, value,
    3574             :                                                     &tag_name, &value_name);
    3575             : 
    3576          22 :                         if (tag_name != NULL)
    3577             :                           {
    3578          22 :                             if (tag == 32)
    3579           0 :                               printf (gettext ("      %s: %" PRId64 ", %s\n"),
    3580             :                                       tag_name, value, string);
    3581          22 :                             else if (string == NULL && value_name == NULL)
    3582           1 :                               printf (gettext ("      %s: %" PRId64 "\n"),
    3583             :                                       tag_name, value);
    3584             :                             else
    3585          21 :                               printf (gettext ("      %s: %s\n"),
    3586             :                                       tag_name, string ?: value_name);
    3587             :                           }
    3588             :                         else
    3589             :                           {
    3590             :                             /* For "gnu" vendor 32 "compatibility" has
    3591             :                                already been handled above.  */
    3592           0 :                             assert (tag != 32
    3593             :                                     || strcmp ((const char *) name, "gnu"));
    3594           0 :                             if (string == NULL)
    3595           0 :                               printf (gettext ("      %u: %" PRId64 "\n"),
    3596             :                                       tag, value);
    3597             :                             else
    3598           0 :                               printf (gettext ("      %u: %s\n"),
    3599             :                                       tag, string);
    3600             :                           }
    3601             :                       }
    3602             :                   }
    3603             :               }
    3604             :         }
    3605             :     }
    3606             : }
    3607             : 
    3608             : 
    3609             : static char *
    3610      626734 : format_dwarf_addr (Dwfl_Module *dwflmod,
    3611             :                    int address_size, Dwarf_Addr address, Dwarf_Addr raw)
    3612             : {
    3613             :   /* See if there is a name we can give for this address.  */
    3614             :   GElf_Sym sym;
    3615      626734 :   GElf_Off off = 0;
    3616     1880188 :   const char *name = (print_address_names && ! print_unresolved_addresses)
    3617      626628 :     ? dwfl_module_addrinfo (dwflmod, address, &off, &sym, NULL, NULL, NULL)
    3618     1253362 :     : NULL;
    3619             : 
    3620             :   const char *scn;
    3621      626734 :   if (print_unresolved_addresses)
    3622             :     {
    3623          92 :       address = raw;
    3624          92 :       scn = NULL;
    3625             :     }
    3626             :   else
    3627             :     {
    3628             :       /* Relativize the address.  */
    3629      626642 :       int n = dwfl_module_relocations (dwflmod);
    3630      626642 :       int i = n < 1 ? -1 : dwfl_module_relocate_address (dwflmod, &address);
    3631             : 
    3632             :       /* In an ET_REL file there is a section name to refer to.  */
    3633             :       scn = (i < 0 ? NULL
    3634      166214 :              : dwfl_module_relocation_info (dwflmod, i, NULL));
    3635             :     }
    3636             : 
    3637             :   char *result;
    3638      626734 :   if ((name != NULL
    3639      603043 :        ? (off != 0
    3640             :           ? (scn != NULL
    3641             :              ? (address_size == 0
    3642       90530 :                 ? asprintf (&result,
    3643       45265 :                             gettext ("%s+%#" PRIx64 " <%s+%#" PRIx64 ">"),
    3644             :                             scn, address, name, off)
    3645      319281 :                 : asprintf (&result,
    3646      106427 :                             gettext ("%s+%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
    3647      106427 :                             scn, 2 + address_size * 2, address,
    3648             :                             name, off))
    3649             :              : (address_size == 0
    3650      225712 :                 ? asprintf (&result,
    3651      112856 :                             gettext ("%#" PRIx64 " <%s+%#" PRIx64 ">"),
    3652             :                             address, name, off)
    3653      936441 :                 : asprintf (&result,
    3654      312147 :                             gettext ("%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
    3655      312147 :                             2 + address_size * 2, address,
    3656             :                             name, off)))
    3657             :           : (scn != NULL
    3658             :              ? (address_size == 0
    3659        4354 :                 ? asprintf (&result,
    3660        2177 :                             gettext ("%s+%#" PRIx64 " <%s>"),
    3661             :                             scn, address, name)
    3662       16410 :                 : asprintf (&result,
    3663        5470 :                             gettext ("%s+%#0*" PRIx64 " <%s>"),
    3664        5470 :                             scn, 2 + address_size * 2, address, name))
    3665             :              : (address_size == 0
    3666        8072 :                 ? asprintf (&result,
    3667        4036 :                             gettext ("%#" PRIx64 " <%s>"),
    3668             :                             address, name)
    3669       43995 :                 : asprintf (&result,
    3670       14665 :                             gettext ("%#0*" PRIx64 " <%s>"),
    3671       14665 :                             2 + address_size * 2, address, name))))
    3672             :        : (scn != NULL
    3673             :           ? (address_size == 0
    3674        4120 :              ? asprintf (&result,
    3675        2060 :                          gettext ("%s+%#" PRIx64),
    3676             :                          scn, address)
    3677       14445 :              : asprintf (&result,
    3678        4815 :                          gettext ("%s+%#0*" PRIx64),
    3679        4815 :                          scn, 2 + address_size * 2, address))
    3680             :           : (address_size == 0
    3681        4588 :              ? asprintf (&result,
    3682             :                          "%#" PRIx64,
    3683             :                          address)
    3684       43566 :              : asprintf (&result,
    3685             :                          "%#0*" PRIx64,
    3686     1871033 :                          2 + address_size * 2, address)))) < 0)
    3687           0 :     error (EXIT_FAILURE, 0, _("memory exhausted"));
    3688             : 
    3689      626734 :   return result;
    3690             : }
    3691             : 
    3692             : static const char *
    3693      860146 : dwarf_tag_string (unsigned int tag)
    3694             : {
    3695      860146 :   switch (tag)
    3696             :     {
    3697             : #define DWARF_ONE_KNOWN_DW_TAG(NAME, CODE) case CODE: return #NAME;
    3698           0 :       DWARF_ALL_KNOWN_DW_TAG
    3699             : #undef DWARF_ONE_KNOWN_DW_TAG
    3700           0 :     default:
    3701           0 :       return NULL;
    3702             :     }
    3703             : }
    3704             : 
    3705             : 
    3706             : static const char *
    3707     3034732 : dwarf_attr_string (unsigned int attrnum)
    3708             : {
    3709     3034732 :   switch (attrnum)
    3710             :     {
    3711             : #define DWARF_ONE_KNOWN_DW_AT(NAME, CODE) case CODE: return #NAME;
    3712           0 :       DWARF_ALL_KNOWN_DW_AT
    3713             : #undef DWARF_ONE_KNOWN_DW_AT
    3714           0 :     default:
    3715           0 :       return NULL;
    3716             :     }
    3717             : }
    3718             : 
    3719             : 
    3720             : static const char *
    3721     3034732 : dwarf_form_string (unsigned int form)
    3722             : {
    3723     3034732 :   switch (form)
    3724             :     {
    3725             : #define DWARF_ONE_KNOWN_DW_FORM(NAME, CODE) case CODE: return #NAME;
    3726          10 :       DWARF_ALL_KNOWN_DW_FORM
    3727             : #undef DWARF_ONE_KNOWN_DW_FORM
    3728           0 :     default:
    3729           0 :       return NULL;
    3730             :     }
    3731             : }
    3732             : 
    3733             : 
    3734             : static const char *
    3735        1294 : dwarf_lang_string (unsigned int lang)
    3736             : {
    3737        1294 :   switch (lang)
    3738             :     {
    3739             : #define DWARF_ONE_KNOWN_DW_LANG(NAME, CODE) case CODE: return #NAME;
    3740           0 :       DWARF_ALL_KNOWN_DW_LANG
    3741             : #undef DWARF_ONE_KNOWN_DW_LANG
    3742           0 :     default:
    3743           0 :       return NULL;
    3744             :     }
    3745             : }
    3746             : 
    3747             : 
    3748             : static const char *
    3749             : dwarf_inline_string (unsigned int code)
    3750             : {
    3751             :   static const char *const known[] =
    3752             :     {
    3753             : #define DWARF_ONE_KNOWN_DW_INL(NAME, CODE) [CODE] = #NAME,
    3754             :       DWARF_ALL_KNOWN_DW_INL
    3755             : #undef DWARF_ONE_KNOWN_DW_INL
    3756             :     };
    3757             : 
    3758        2943 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3759        2943 :     return known[code];
    3760             : 
    3761             :   return NULL;
    3762             : }
    3763             : 
    3764             : 
    3765             : static const char *
    3766             : dwarf_encoding_string (unsigned int code)
    3767             : {
    3768             :   static const char *const known[] =
    3769             :     {
    3770             : #define DWARF_ONE_KNOWN_DW_ATE(NAME, CODE) [CODE] = #NAME,
    3771             :       DWARF_ALL_KNOWN_DW_ATE
    3772             : #undef DWARF_ONE_KNOWN_DW_ATE
    3773             :     };
    3774             : 
    3775       18838 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3776       18838 :     return known[code];
    3777             : 
    3778             :   return NULL;
    3779             : }
    3780             : 
    3781             : 
    3782             : static const char *
    3783             : dwarf_access_string (unsigned int code)
    3784             : {
    3785             :   static const char *const known[] =
    3786             :     {
    3787             : #define DWARF_ONE_KNOWN_DW_ACCESS(NAME, CODE) [CODE] = #NAME,
    3788             :       DWARF_ALL_KNOWN_DW_ACCESS
    3789             : #undef DWARF_ONE_KNOWN_DW_ACCESS
    3790             :     };
    3791             : 
    3792           0 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3793           0 :     return known[code];
    3794             : 
    3795             :   return NULL;
    3796             : }
    3797             : 
    3798             : 
    3799             : static const char *
    3800             : dwarf_defaulted_string (unsigned int code)
    3801             : {
    3802             :   static const char *const known[] =
    3803             :     {
    3804             : #define DWARF_ONE_KNOWN_DW_DEFAULTED(NAME, CODE) [CODE] = #NAME,
    3805             :       DWARF_ALL_KNOWN_DW_DEFAULTED
    3806             : #undef DWARF_ONE_KNOWN_DW_DEFAULTED
    3807             :     };
    3808             : 
    3809           0 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3810           0 :     return known[code];
    3811             : 
    3812             :   return NULL;
    3813             : }
    3814             : 
    3815             : 
    3816             : static const char *
    3817             : dwarf_visibility_string (unsigned int code)
    3818             : {
    3819             :   static const char *const known[] =
    3820             :     {
    3821             : #define DWARF_ONE_KNOWN_DW_VIS(NAME, CODE) [CODE] = #NAME,
    3822             :       DWARF_ALL_KNOWN_DW_VIS
    3823             : #undef DWARF_ONE_KNOWN_DW_VIS
    3824             :     };
    3825             : 
    3826           0 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3827           0 :     return known[code];
    3828             : 
    3829             :   return NULL;
    3830             : }
    3831             : 
    3832             : 
    3833             : static const char *
    3834             : dwarf_virtuality_string (unsigned int code)
    3835             : {
    3836             :   static const char *const known[] =
    3837             :     {
    3838             : #define DWARF_ONE_KNOWN_DW_VIRTUALITY(NAME, CODE) [CODE] = #NAME,
    3839             :       DWARF_ALL_KNOWN_DW_VIRTUALITY
    3840             : #undef DWARF_ONE_KNOWN_DW_VIRTUALITY
    3841             :     };
    3842             : 
    3843           0 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3844           0 :     return known[code];
    3845             : 
    3846             :   return NULL;
    3847             : }
    3848             : 
    3849             : 
    3850             : static const char *
    3851             : dwarf_identifier_case_string (unsigned int code)
    3852             : {
    3853             :   static const char *const known[] =
    3854             :     {
    3855             : #define DWARF_ONE_KNOWN_DW_ID(NAME, CODE) [CODE] = #NAME,
    3856             :       DWARF_ALL_KNOWN_DW_ID
    3857             : #undef DWARF_ONE_KNOWN_DW_ID
    3858             :     };
    3859             : 
    3860           0 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3861           0 :     return known[code];
    3862             : 
    3863             :   return NULL;
    3864             : }
    3865             : 
    3866             : 
    3867             : static const char *
    3868             : dwarf_calling_convention_string (unsigned int code)
    3869             : {
    3870             :   static const char *const known[] =
    3871             :     {
    3872             : #define DWARF_ONE_KNOWN_DW_CC(NAME, CODE) [CODE] = #NAME,
    3873             :       DWARF_ALL_KNOWN_DW_CC
    3874             : #undef DWARF_ONE_KNOWN_DW_CC
    3875             :     };
    3876             : 
    3877           0 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3878           0 :     return known[code];
    3879             : 
    3880             :   return NULL;
    3881             : }
    3882             : 
    3883             : 
    3884             : static const char *
    3885             : dwarf_ordering_string (unsigned int code)
    3886             : {
    3887             :   static const char *const known[] =
    3888             :     {
    3889             : #define DWARF_ONE_KNOWN_DW_ORD(NAME, CODE) [CODE] = #NAME,
    3890             :       DWARF_ALL_KNOWN_DW_ORD
    3891             : #undef DWARF_ONE_KNOWN_DW_ORD
    3892             :     };
    3893             : 
    3894           0 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3895           0 :     return known[code];
    3896             : 
    3897             :   return NULL;
    3898             : }
    3899             : 
    3900             : 
    3901             : static const char *
    3902             : dwarf_discr_list_string (unsigned int code)
    3903             : {
    3904             :   static const char *const known[] =
    3905             :     {
    3906             : #define DWARF_ONE_KNOWN_DW_DSC(NAME, CODE) [CODE] = #NAME,
    3907             :       DWARF_ALL_KNOWN_DW_DSC
    3908             : #undef DWARF_ONE_KNOWN_DW_DSC
    3909             :     };
    3910             : 
    3911           0 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3912           0 :     return known[code];
    3913             : 
    3914             :   return NULL;
    3915             : }
    3916             : 
    3917             : 
    3918             : static const char *
    3919             : dwarf_locexpr_opcode_string (unsigned int code)
    3920             : {
    3921             :   static const char *const known[] =
    3922             :     {
    3923             :       /* Normally we can't affort building huge table of 64K entries,
    3924             :          most of them zero, just because there are a couple defined
    3925             :          values at the far end.  In case of opcodes, it's OK.  */
    3926             : #define DWARF_ONE_KNOWN_DW_OP(NAME, CODE) [CODE] = #NAME,
    3927             :       DWARF_ALL_KNOWN_DW_OP
    3928             : #undef DWARF_ONE_KNOWN_DW_OP
    3929             :     };
    3930             : 
    3931      401094 :   if (likely (code < sizeof (known) / sizeof (known[0])))
    3932      401094 :     return known[code];
    3933             : 
    3934             :   return NULL;
    3935             : }
    3936             : 
    3937             : 
    3938             : /* Used by all dwarf_foo_name functions.  */
    3939             : static const char *
    3940     6952685 : string_or_unknown (const char *known, unsigned int code,
    3941             :                    unsigned int lo_user, unsigned int hi_user,
    3942             :                    bool print_unknown_num)
    3943             : {
    3944             :   static char unknown_buf[20];
    3945             : 
    3946     6952685 :   if (likely (known != NULL))
    3947             :     return known;
    3948             : 
    3949           0 :   if (lo_user != 0 && code >= lo_user && code <= hi_user)
    3950             :     {
    3951           0 :       snprintf (unknown_buf, sizeof unknown_buf, "lo_user+%#x",
    3952             :                 code - lo_user);
    3953           0 :       return unknown_buf;
    3954             :     }
    3955             : 
    3956           0 :   if (print_unknown_num)
    3957             :     {
    3958           0 :       snprintf (unknown_buf, sizeof unknown_buf, "??? (%#x)", code);
    3959           0 :       return unknown_buf;
    3960             :     }
    3961             : 
    3962             :   return "???";
    3963             : }
    3964             : 
    3965             : 
    3966             : static const char *
    3967      860146 : dwarf_tag_name (unsigned int tag)
    3968             : {
    3969      860146 :   const char *ret = dwarf_tag_string (tag);
    3970      860146 :   return string_or_unknown (ret, tag, DW_TAG_lo_user, DW_TAG_hi_user, true);
    3971             : }
    3972             : 
    3973             : static const char *
    3974     3034732 : dwarf_attr_name (unsigned int attr)
    3975             : {
    3976     3034732 :   const char *ret = dwarf_attr_string (attr);
    3977     3034732 :   return string_or_unknown (ret, attr, DW_AT_lo_user, DW_AT_hi_user, true);
    3978             : }
    3979             : 
    3980             : 
    3981             : static const char *
    3982     3034732 : dwarf_form_name (unsigned int form)
    3983             : {
    3984     3034732 :   const char *ret = dwarf_form_string (form);
    3985     3034732 :   return string_or_unknown (ret, form, 0, 0, true);
    3986             : }
    3987             : 
    3988             : 
    3989             : static const char *
    3990        1294 : dwarf_lang_name (unsigned int lang)
    3991             : {
    3992        1294 :   const char *ret = dwarf_lang_string (lang);
    3993        1294 :   return string_or_unknown (ret, lang, DW_LANG_lo_user, DW_LANG_hi_user, false);
    3994             : }
    3995             : 
    3996             : 
    3997             : static const char *
    3998             : dwarf_inline_name (unsigned int code)
    3999             : {
    4000        2943 :   const char *ret = dwarf_inline_string (code);
    4001        2943 :   return string_or_unknown (ret, code, 0, 0, false);
    4002             : }
    4003             : 
    4004             : 
    4005             : static const char *
    4006             : dwarf_encoding_name (unsigned int code)
    4007             : {
    4008       18838 :   const char *ret = dwarf_encoding_string (code);
    4009       18838 :   return string_or_unknown (ret, code, DW_ATE_lo_user, DW_ATE_hi_user, false);
    4010             : }
    4011             : 
    4012             : 
    4013             : static const char *
    4014             : dwarf_access_name (unsigned int code)
    4015             : {
    4016           0 :   const char *ret = dwarf_access_string (code);
    4017           0 :   return string_or_unknown (ret, code, 0, 0, false);
    4018             : }
    4019             : 
    4020             : 
    4021             : static const char *
    4022             : dwarf_defaulted_name (unsigned int code)
    4023             : {
    4024           0 :   const char *ret = dwarf_defaulted_string (code);
    4025           0 :   return string_or_unknown (ret, code, 0, 0, false);
    4026             : }
    4027             : 
    4028             : 
    4029             : static const char *
    4030             : dwarf_visibility_name (unsigned int code)
    4031             : {
    4032           0 :   const char *ret = dwarf_visibility_string (code);
    4033           0 :   return string_or_unknown (ret, code, 0, 0, false);
    4034             : }
    4035             : 
    4036             : 
    4037             : static const char *
    4038             : dwarf_virtuality_name (unsigned int code)
    4039             : {
    4040           0 :   const char *ret = dwarf_virtuality_string (code);
    4041           0 :   return string_or_unknown (ret, code, 0, 0, false);
    4042             : }
    4043             : 
    4044             : 
    4045             : static const char *
    4046             : dwarf_identifier_case_name (unsigned int code)
    4047             : {
    4048           0 :   const char *ret = dwarf_identifier_case_string (code);
    4049           0 :   return string_or_unknown (ret, code, 0, 0, false);
    4050             : }
    4051             : 
    4052             : 
    4053             : static const char *
    4054             : dwarf_calling_convention_name (unsigned int code)
    4055             : {
    4056           0 :   const char *ret = dwarf_calling_convention_string (code);
    4057           0 :   return string_or_unknown (ret, code, DW_CC_lo_user, DW_CC_hi_user, false);
    4058             : }
    4059             : 
    4060             : 
    4061             : static const char *
    4062             : dwarf_ordering_name (unsigned int code)
    4063             : {
    4064           0 :   const char *ret = dwarf_ordering_string (code);
    4065           0 :   return string_or_unknown (ret, code, 0, 0, false);
    4066             : }
    4067             : 
    4068             : 
    4069             : static const char *
    4070             : dwarf_discr_list_name (unsigned int code)
    4071             : {
    4072           0 :   const char *ret = dwarf_discr_list_string (code);
    4073           0 :   return string_or_unknown (ret, code, 0, 0, false);
    4074             : }
    4075             : 
    4076             : 
    4077             : static void
    4078         144 : print_block (size_t n, const void *block)
    4079             : {
    4080         144 :   if (n == 0)
    4081           0 :     puts (_("empty block"));
    4082             :   else
    4083             :     {
    4084         288 :       printf (_("%zu byte block:"), n);
    4085         144 :       const unsigned char *data = block;
    4086             :       do
    4087        4804 :         printf (" %02x", *data++);
    4088        2402 :       while (--n > 0);
    4089             :       putchar ('\n');
    4090             :     }
    4091         144 : }
    4092             : 
    4093             : static void
    4094      281119 : print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
    4095             :            unsigned int vers, unsigned int addrsize, unsigned int offset_size,
    4096             :            struct Dwarf_CU *cu, Dwarf_Word len, const unsigned char *data)
    4097             : {
    4098      281119 :   const unsigned int ref_size = vers < 3 ? addrsize : offset_size;
    4099             : 
    4100      281119 :   if (len == 0)
    4101             :     {
    4102             :       printf ("%*s(empty)\n", indent, "");
    4103             :       return;
    4104             :     }
    4105             : 
    4106             : #define NEED(n)         if (len < (Dwarf_Word) (n)) goto invalid
    4107             : #define CONSUME(n)      NEED (n); else len -= (n)
    4108             : 
    4109             :   Dwarf_Word offset = 0;
    4110      682213 :   while (len-- > 0)
    4111             :     {
    4112      401094 :       uint_fast8_t op = *data++;
    4113             : 
    4114      802188 :       const char *op_name = dwarf_locexpr_opcode_string (op);
    4115      401094 :       if (unlikely (op_name == NULL))
    4116             :         {
    4117             :           static char buf[20];
    4118           0 :           if (op >= DW_OP_lo_user)
    4119           0 :             snprintf (buf, sizeof buf, "lo_user+%#x", op - DW_OP_lo_user);
    4120             :           else
    4121           0 :             snprintf (buf, sizeof buf, "??? (%#x)", op);
    4122             :           op_name = buf;
    4123             :         }
    4124             : 
    4125      401094 :       switch (op)
    4126             :         {
    4127        7579 :         case DW_OP_addr:;
    4128             :           /* Address operand.  */
    4129             :           Dwarf_Word addr;
    4130        7579 :           NEED (addrsize);
    4131        7579 :           if (addrsize == 4)
    4132          28 :             addr = read_4ubyte_unaligned (dbg, data);
    4133        7561 :           else if (addrsize == 8)
    4134        7579 :             addr = read_8ubyte_unaligned (dbg, data);
    4135             :           else
    4136             :             goto invalid;
    4137        7579 :           data += addrsize;
    4138        7579 :           CONSUME (addrsize);
    4139             : 
    4140        7579 :           char *a = format_dwarf_addr (dwflmod, 0, addr, addr);
    4141        7579 :           printf ("%*s[%4" PRIuMAX "] %s %s\n",
    4142             :                   indent, "", (uintmax_t) offset, op_name, a);
    4143        7579 :           free (a);
    4144             : 
    4145        7579 :           offset += 1 + addrsize;
    4146        7579 :           break;
    4147             : 
    4148           0 :         case DW_OP_call_ref:
    4149             :           /* Offset operand.  */
    4150           0 :           if (ref_size != 4 && ref_size != 8)
    4151             :             goto invalid; /* Cannot be used in CFA.  */
    4152           0 :           NEED (ref_size);
    4153           0 :           if (ref_size == 4)
    4154           0 :             addr = read_4ubyte_unaligned (dbg, data);
    4155             :           else
    4156           0 :             addr = read_8ubyte_unaligned (dbg, data);
    4157           0 :           data += ref_size;
    4158           0 :           CONSUME (ref_size);
    4159             : 
    4160           0 :           printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n",
    4161             :                   indent, "", (uintmax_t) offset,
    4162             :                   op_name, (uintmax_t) addr);
    4163           0 :           offset += 1 + ref_size;
    4164           0 :           break;
    4165             : 
    4166       10604 :         case DW_OP_deref_size:
    4167             :         case DW_OP_xderef_size:
    4168             :         case DW_OP_pick:
    4169             :         case DW_OP_const1u:
    4170             :           // XXX value might be modified by relocation
    4171       10604 :           NEED (1);
    4172       21208 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 "\n",
    4173             :                   indent, "", (uintmax_t) offset,
    4174       10604 :                   op_name, *((uint8_t *) data));
    4175       10604 :           ++data;
    4176       10604 :           --len;
    4177       10604 :           offset += 2;
    4178       10604 :           break;
    4179             : 
    4180        1016 :         case DW_OP_const2u:
    4181        1016 :           NEED (2);
    4182             :           // XXX value might be modified by relocation
    4183        3048 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
    4184             :                   indent, "", (uintmax_t) offset,
    4185        2032 :                   op_name, read_2ubyte_unaligned (dbg, data));
    4186        1016 :           CONSUME (2);
    4187        1016 :           data += 2;
    4188        1016 :           offset += 3;
    4189        1016 :           break;
    4190             : 
    4191         582 :         case DW_OP_const4u:
    4192         582 :           NEED (4);
    4193             :           // XXX value might be modified by relocation
    4194        1746 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
    4195             :                   indent, "", (uintmax_t) offset,
    4196        1164 :                   op_name, read_4ubyte_unaligned (dbg, data));
    4197         582 :           CONSUME (4);
    4198         582 :           data += 4;
    4199         582 :           offset += 5;
    4200         582 :           break;
    4201             : 
    4202          59 :         case DW_OP_const8u:
    4203          59 :           NEED (8);
    4204             :           // XXX value might be modified by relocation
    4205         177 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n",
    4206             :                   indent, "", (uintmax_t) offset,
    4207         118 :                   op_name, (uint64_t) read_8ubyte_unaligned (dbg, data));
    4208          59 :           CONSUME (8);
    4209          59 :           data += 8;
    4210          59 :           offset += 9;
    4211          59 :           break;
    4212             : 
    4213        1835 :         case DW_OP_const1s:
    4214        1835 :           NEED (1);
    4215             :           // XXX value might be modified by relocation
    4216        3670 :           printf ("%*s[%4" PRIuMAX "] %s %" PRId8 "\n",
    4217             :                   indent, "", (uintmax_t) offset,
    4218        1835 :                   op_name, *((int8_t *) data));
    4219        1835 :           ++data;
    4220        1835 :           --len;
    4221        1835 :           offset += 2;
    4222        1835 :           break;
    4223             : 
    4224           5 :         case DW_OP_const2s:
    4225           5 :           NEED (2);
    4226             :           // XXX value might be modified by relocation
    4227          15 :           printf ("%*s[%4" PRIuMAX "] %s %" PRId16 "\n",
    4228             :                   indent, "", (uintmax_t) offset,
    4229          10 :                   op_name, read_2sbyte_unaligned (dbg, data));
    4230           5 :           CONSUME (2);
    4231           5 :           data += 2;
    4232           5 :           offset += 3;
    4233           5 :           break;
    4234             : 
    4235           0 :         case DW_OP_const4s:
    4236           0 :           NEED (4);
    4237             :           // XXX value might be modified by relocation
    4238           0 :           printf ("%*s[%4" PRIuMAX "] %s %" PRId32 "\n",
    4239             :                   indent, "", (uintmax_t) offset,
    4240           0 :                   op_name, read_4sbyte_unaligned (dbg, data));
    4241           0 :           CONSUME (4);
    4242           0 :           data += 4;
    4243           0 :           offset += 5;
    4244           0 :           break;
    4245             : 
    4246           0 :         case DW_OP_const8s:
    4247           0 :           NEED (8);
    4248             :           // XXX value might be modified by relocation
    4249           0 :           printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n",
    4250             :                   indent, "", (uintmax_t) offset,
    4251           0 :                   op_name, read_8sbyte_unaligned (dbg, data));
    4252           0 :           CONSUME (8);
    4253           0 :           data += 8;
    4254           0 :           offset += 9;
    4255           0 :           break;
    4256             : 
    4257        8473 :         case DW_OP_piece:
    4258             :         case DW_OP_regx:
    4259             :         case DW_OP_plus_uconst:
    4260             :         case DW_OP_constu:;
    4261        8473 :           const unsigned char *start = data;
    4262             :           uint64_t uleb;
    4263        8473 :           NEED (1);
    4264        8473 :           get_uleb128 (uleb, data, data + len);
    4265        8473 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 "\n",
    4266             :                   indent, "", (uintmax_t) offset, op_name, uleb);
    4267       16946 :           CONSUME (data - start);
    4268        8473 :           offset += 1 + (data - start);
    4269        8473 :           break;
    4270             : 
    4271           0 :         case DW_OP_bit_piece:
    4272           0 :           start = data;
    4273             :           uint64_t uleb2;
    4274           0 :           NEED (1);
    4275           0 :           get_uleb128 (uleb, data, data + len);
    4276             :           NEED (1);
    4277           0 :           get_uleb128 (uleb2, data, data + len);
    4278           0 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 ", %" PRIu64 "\n",
    4279             :                   indent, "", (uintmax_t) offset, op_name, uleb, uleb2);
    4280           0 :           CONSUME (data - start);
    4281           0 :           offset += 1 + (data - start);
    4282           0 :           break;
    4283             : 
    4284       71355 :         case DW_OP_fbreg:
    4285             :         case DW_OP_breg0 ... DW_OP_breg31:
    4286             :         case DW_OP_consts:
    4287       71355 :           start = data;
    4288             :           int64_t sleb;
    4289       71355 :           NEED (1);
    4290       71355 :           get_sleb128 (sleb, data, data + len);
    4291       71355 :           printf ("%*s[%4" PRIuMAX "] %s %" PRId64 "\n",
    4292             :                   indent, "", (uintmax_t) offset, op_name, sleb);
    4293      142710 :           CONSUME (data - start);
    4294       71355 :           offset += 1 + (data - start);
    4295       71355 :           break;
    4296             : 
    4297           0 :         case DW_OP_bregx:
    4298           0 :           start = data;
    4299           0 :           NEED (1);
    4300           0 :           get_uleb128 (uleb, data, data + len);
    4301             :           NEED (1);
    4302           0 :           get_sleb128 (sleb, data, data + len);
    4303           0 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 " %" PRId64 "\n",
    4304             :                   indent, "", (uintmax_t) offset, op_name, uleb, sleb);
    4305           0 :           CONSUME (data - start);
    4306           0 :           offset += 1 + (data - start);
    4307           0 :           break;
    4308             : 
    4309           0 :         case DW_OP_call2:
    4310           0 :           NEED (2);
    4311           0 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu16 "\n",
    4312             :                   indent, "", (uintmax_t) offset, op_name,
    4313           0 :                   read_2ubyte_unaligned (dbg, data));
    4314           0 :           CONSUME (2);
    4315           0 :           offset += 3;
    4316           0 :           break;
    4317             : 
    4318           0 :         case DW_OP_call4:
    4319           0 :           NEED (4);
    4320           0 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu32 "\n",
    4321             :                   indent, "", (uintmax_t) offset, op_name,
    4322           0 :                   read_4ubyte_unaligned (dbg, data));
    4323           0 :           CONSUME (4);
    4324           0 :           offset += 5;
    4325           0 :           break;
    4326             : 
    4327         198 :         case DW_OP_skip:
    4328             :         case DW_OP_bra:
    4329         198 :           NEED (2);
    4330         198 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n",
    4331             :                   indent, "", (uintmax_t) offset, op_name,
    4332         198 :                   (uintmax_t) (offset + read_2sbyte_unaligned (dbg, data) + 3));
    4333         198 :           CONSUME (2);
    4334         198 :           data += 2;
    4335         198 :           offset += 3;
    4336         198 :           break;
    4337             : 
    4338         127 :         case DW_OP_implicit_value:
    4339         127 :           start = data;
    4340         127 :           NEED (1);
    4341         127 :           get_uleb128 (uleb, data, data + len);
    4342         127 :           printf ("%*s[%4" PRIuMAX "] %s: ",
    4343             :                   indent, "", (uintmax_t) offset, op_name);
    4344         127 :           NEED (uleb);
    4345         127 :           print_block (uleb, data);
    4346         127 :           data += uleb;
    4347         254 :           CONSUME (data - start);
    4348         127 :           offset += 1 + (data - start);
    4349         127 :           break;
    4350             : 
    4351        3340 :         case DW_OP_GNU_implicit_pointer:
    4352             :           /* DIE offset operand.  */
    4353        3340 :           start = data;
    4354        3340 :           NEED (ref_size);
    4355        3340 :           if (ref_size != 4 && ref_size != 8)
    4356             :             goto invalid; /* Cannot be used in CFA.  */
    4357        3340 :           if (ref_size == 4)
    4358        3340 :             addr = read_4ubyte_unaligned (dbg, data);
    4359             :           else
    4360           0 :             addr = read_8ubyte_unaligned (dbg, data);
    4361        3340 :           data += ref_size;
    4362             :           /* Byte offset operand.  */
    4363        3340 :           NEED (1);
    4364        3340 :           get_sleb128 (sleb, data, data + len);
    4365             : 
    4366        6680 :           printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "] %+" PRId64 "\n",
    4367             :                   indent, "", (intmax_t) offset,
    4368             :                   op_name, (uintmax_t) addr, sleb);
    4369        6680 :           CONSUME (data - start);
    4370        3340 :           offset += 1 + (data - start);
    4371        3340 :           break;
    4372             : 
    4373       22504 :         case DW_OP_GNU_entry_value:
    4374             :           /* Size plus expression block.  */
    4375       22504 :           start = data;
    4376       22504 :           NEED (1);
    4377       22504 :           get_uleb128 (uleb, data, data + len);
    4378       22504 :           printf ("%*s[%4" PRIuMAX "] %s:\n",
    4379             :                   indent, "", (uintmax_t) offset, op_name);
    4380       22504 :           NEED (uleb);
    4381       22504 :           print_ops (dwflmod, dbg, indent + 6, indent + 6, vers,
    4382             :                      addrsize, offset_size, cu, uleb, data);
    4383       22504 :           data += uleb;
    4384       45008 :           CONSUME (data - start);
    4385       22504 :           offset += 1 + (data - start);
    4386       22504 :           break;
    4387             : 
    4388           1 :         case DW_OP_GNU_const_type:
    4389             :           /* uleb128 CU relative DW_TAG_base_type DIE offset, 1-byte
    4390             :              unsigned size plus block.  */
    4391           1 :           start = data;
    4392           1 :           NEED (1);
    4393           1 :           get_uleb128 (uleb, data, data + len);
    4394           1 :           if (! print_unresolved_addresses && cu != NULL)
    4395           1 :             uleb += cu->start;
    4396             :           NEED (1);
    4397           1 :           uint8_t usize = *(uint8_t *) data++;
    4398           1 :           NEED (usize);
    4399           1 :           printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "] ",
    4400             :                   indent, "", (uintmax_t) offset, op_name, uleb);
    4401           1 :           print_block (usize, data);
    4402           1 :           data += usize;
    4403           2 :           CONSUME (data - start);
    4404           1 :           offset += 1 + (data - start);
    4405           1 :           break;
    4406             : 
    4407           0 :         case DW_OP_GNU_regval_type:
    4408             :           /* uleb128 register number, uleb128 CU relative
    4409             :              DW_TAG_base_type DIE offset.  */
    4410           0 :           start = data;
    4411           0 :           NEED (1);
    4412           0 :           get_uleb128 (uleb, data, data + len);
    4413             :           NEED (1);
    4414           0 :           get_uleb128 (uleb2, data, data + len);
    4415           0 :           if (! print_unresolved_addresses && cu != NULL)
    4416           0 :             uleb2 += cu->start;
    4417           0 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu64 " [%6" PRIx64 "]\n",
    4418             :                   indent, "", (uintmax_t) offset, op_name, uleb, uleb2);
    4419           0 :           CONSUME (data - start);
    4420           0 :           offset += 1 + (data - start);
    4421           0 :           break;
    4422             : 
    4423           6 :         case DW_OP_GNU_deref_type:
    4424             :           /* 1-byte unsigned size of value, uleb128 CU relative
    4425             :              DW_TAG_base_type DIE offset.  */
    4426           6 :           start = data;
    4427           6 :           NEED (1);
    4428           6 :           usize = *(uint8_t *) data++;
    4429             :           NEED (1);
    4430           6 :           get_uleb128 (uleb, data, data + len);
    4431           6 :           if (! print_unresolved_addresses && cu != NULL)
    4432           6 :             uleb += cu->start;
    4433          12 :           printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 " [%6" PRIxMAX "]\n",
    4434             :                   indent, "", (uintmax_t) offset,
    4435             :                   op_name, usize, uleb);
    4436          12 :           CONSUME (data - start);
    4437           6 :           offset += 1 + (data - start);
    4438           6 :           break;
    4439             : 
    4440         147 :         case DW_OP_GNU_convert:
    4441             :         case DW_OP_GNU_reinterpret:
    4442             :           /* uleb128 CU relative offset to DW_TAG_base_type, or zero
    4443             :              for conversion to untyped.  */
    4444         147 :           start = data;
    4445         147 :           NEED (1);
    4446         147 :           get_uleb128 (uleb, data, data + len);
    4447         147 :           if (uleb != 0 && ! print_unresolved_addresses && cu != NULL)
    4448          99 :             uleb += cu->start;
    4449         147 :           printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "]\n",
    4450             :                   indent, "", (uintmax_t) offset, op_name, uleb);
    4451         294 :           CONSUME (data - start);
    4452         147 :           offset += 1 + (data - start);
    4453         147 :           break;
    4454             : 
    4455          21 :         case DW_OP_GNU_parameter_ref:
    4456             :           /* 4 byte CU relative reference to the abstract optimized away
    4457             :              DW_TAG_formal_parameter.  */
    4458          21 :           NEED (4);
    4459          21 :           uintmax_t param_off = (uintmax_t) read_4ubyte_unaligned (dbg, data);
    4460          21 :           if (! print_unresolved_addresses && cu != NULL)
    4461          21 :             param_off += cu->start;
    4462          21 :           printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "]\n",
    4463             :                   indent, "", (uintmax_t) offset, op_name, param_off);
    4464          21 :           CONSUME (4);
    4465          21 :           data += 4;
    4466          21 :           offset += 5;
    4467          21 :           break;
    4468             : 
    4469      273242 :         default:
    4470             :           /* No Operand.  */
    4471      273242 :           printf ("%*s[%4" PRIuMAX "] %s\n",
    4472             :                   indent, "", (uintmax_t) offset, op_name);
    4473      273242 :           ++offset;
    4474      273242 :           break;
    4475             :         }
    4476             : 
    4477      401094 :       indent = indentrest;
    4478      401094 :       continue;
    4479             : 
    4480           0 :     invalid:
    4481           0 :       printf (gettext ("%*s[%4" PRIuMAX "] %s  <TRUNCATED>\n"),
    4482             :               indent, "", (uintmax_t) offset, op_name);
    4483             :       break;
    4484             :     }
    4485             : }
    4486             : 
    4487             : 
    4488             : struct listptr
    4489             : {
    4490             :   Dwarf_Off offset:(64 - 3);
    4491             :   bool addr64:1;
    4492             :   bool dwarf64:1;
    4493             :   bool warned:1;
    4494             :   struct Dwarf_CU *cu;
    4495             : };
    4496             : 
    4497             : #define listptr_offset_size(p)  ((p)->dwarf64 ? 8 : 4)
    4498             : #define listptr_address_size(p) ((p)->addr64 ? 8 : 4)
    4499             : 
    4500             : static Dwarf_Addr
    4501       58808 : listptr_base (struct listptr *p)
    4502             : {
    4503             :   Dwarf_Addr base;
    4504      117616 :   Dwarf_Die cu = CUDIE (p->cu);
    4505             :   /* Find the base address of the compilation unit.  It will normally
    4506             :      be specified by DW_AT_low_pc.  In DWARF-3 draft 4, the base
    4507             :      address could be overridden by DW_AT_entry_pc.  It's been
    4508             :      removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc for
    4509             :      compilation units with discontinuous ranges.  */
    4510       58808 :   if (unlikely (dwarf_lowpc (&cu, &base) != 0))
    4511             :     {
    4512             :       Dwarf_Attribute attr_mem;
    4513           0 :       if (dwarf_formaddr (dwarf_attr (&cu, DW_AT_entry_pc, &attr_mem),
    4514             :                           &base) != 0)
    4515           0 :         base = 0;
    4516             :     }
    4517       58808 :   return base;
    4518             : }
    4519             : 
    4520             : static int
    4521      321562 : compare_listptr (const void *a, const void *b, void *arg)
    4522             : {
    4523      321562 :   const char *name = arg;
    4524      321562 :   struct listptr *p1 = (void *) a;
    4525      321562 :   struct listptr *p2 = (void *) b;
    4526             : 
    4527      321562 :   if (p1->offset < p2->offset)
    4528             :     return -1;
    4529       19410 :   if (p1->offset > p2->offset)
    4530             :     return 1;
    4531             : 
    4532        3718 :   if (!p1->warned && !p2->warned)
    4533             :     {
    4534        3718 :       if (p1->addr64 != p2->addr64)
    4535             :         {
    4536           0 :           p1->warned = p2->warned = true;
    4537           0 :           error (0, 0,
    4538           0 :                  gettext ("%s %#" PRIx64 " used with different address sizes"),
    4539             :                  name, (uint64_t) p1->offset);
    4540             :         }
    4541        3718 :       if (p1->dwarf64 != p2->dwarf64)
    4542             :         {
    4543           0 :           p1->warned = p2->warned = true;
    4544           0 :           error (0, 0,
    4545           0 :                  gettext ("%s %#" PRIx64 " used with different offset sizes"),
    4546           0 :                  name, (uint64_t) p1->offset);
    4547             :         }
    4548        3718 :       if (listptr_base (p1) != listptr_base (p2))
    4549             :         {
    4550           0 :           p1->warned = p2->warned = true;
    4551           0 :           error (0, 0,
    4552           0 :                  gettext ("%s %#" PRIx64 " used with different base addresses"),
    4553           0 :                  name, (uint64_t) p1->offset);
    4554             :         }
    4555             :     }
    4556             : 
    4557             :   return 0;
    4558             : }
    4559             : 
    4560             : struct listptr_table
    4561             : {
    4562             :   size_t n;
    4563             :   size_t alloc;
    4564             :   struct listptr *table;
    4565             : };
    4566             : 
    4567             : static struct listptr_table known_loclistptr;
    4568             : static struct listptr_table known_rangelistptr;
    4569             : 
    4570             : static void
    4571             : reset_listptr (struct listptr_table *table)
    4572             : {
    4573         178 :   free (table->table);
    4574         178 :   table->table = NULL;
    4575         178 :   table->n = table->alloc = 0;
    4576             : }
    4577             : 
    4578             : /* Returns false if offset doesn't fit.  See struct listptr.  */
    4579             : static bool
    4580       54977 : notice_listptr (enum section_e section, struct listptr_table *table,
    4581             :                 uint_fast8_t address_size, uint_fast8_t offset_size,
    4582             :                 struct Dwarf_CU *cu, Dwarf_Off offset)
    4583             : {
    4584       54977 :   if (print_debug_sections & section)
    4585             :     {
    4586       54970 :       if (table->n == table->alloc)
    4587             :         {
    4588         157 :           if (table->alloc == 0)
    4589          55 :             table->alloc = 128;
    4590             :           else
    4591         102 :             table->alloc *= 2;
    4592         157 :           table->table = xrealloc (table->table,
    4593         157 :                                    table->alloc * sizeof table->table[0]);
    4594             :         }
    4595             : 
    4596       54970 :       struct listptr *p = &table->table[table->n++];
    4597             : 
    4598      109940 :       *p = (struct listptr)
    4599             :         {
    4600       54970 :           .addr64 = address_size == 8,
    4601       54970 :           .dwarf64 = offset_size == 8,
    4602             :           .offset = offset,
    4603             :           .cu = cu
    4604             :         };
    4605             : 
    4606       54970 :       if (p->offset != offset)
    4607             :         {
    4608           0 :           table->n--;
    4609           0 :           return false;
    4610             :         }
    4611             :     }
    4612             :   return true;
    4613             : }
    4614             : 
    4615             : static void
    4616             : sort_listptr (struct listptr_table *table, const char *name)
    4617             : {
    4618          55 :   if (table->n > 0)
    4619          55 :     qsort_r (table->table, table->n, sizeof table->table[0],
    4620             :              &compare_listptr, (void *) name);
    4621             : }
    4622             : 
    4623             : static bool
    4624       51372 : skip_listptr_hole (struct listptr_table *table, size_t *idxp,
    4625             :                    uint_fast8_t *address_sizep, uint_fast8_t *offset_sizep,
    4626             :                    Dwarf_Addr *base, struct Dwarf_CU **cu, ptrdiff_t offset,
    4627             :                    unsigned char **readp, unsigned char *endp)
    4628             : {
    4629       51372 :   if (table->n == 0)
    4630             :     return false;
    4631             : 
    4632      106287 :   while (*idxp < table->n && table->table[*idxp].offset < (Dwarf_Off) offset)
    4633       54915 :     ++*idxp;
    4634             : 
    4635       51372 :   struct listptr *p = &table->table[*idxp];
    4636             : 
    4637       51372 :   if (*idxp == table->n
    4638       51372 :       || p->offset >= (Dwarf_Off) (endp - *readp + offset))
    4639             :     {
    4640           0 :       *readp = endp;
    4641           0 :       printf (gettext (" [%6tx]  <UNUSED GARBAGE IN REST OF SECTION>\n"),
    4642             :               offset);
    4643             :       return true;
    4644             :     }
    4645             : 
    4646       51372 :   if (p->offset != (Dwarf_Off) offset)
    4647             :     {
    4648           0 :       *readp += p->offset - offset;
    4649           0 :       printf (gettext (" [%6tx]  <UNUSED GARBAGE> ... %" PRIu64 " bytes ...\n"),
    4650             :               offset, (Dwarf_Off) p->offset - offset);
    4651             :       return true;
    4652             :     }
    4653             : 
    4654       51372 :   if (address_sizep != NULL)
    4655       51372 :     *address_sizep = listptr_address_size (p);
    4656       51372 :   if (offset_sizep != NULL)
    4657       42545 :     *offset_sizep = listptr_offset_size (p);
    4658       51372 :   if (base != NULL)
    4659       51372 :     *base = listptr_base (p);
    4660       51372 :   if (cu != NULL)
    4661       42545 :     *cu = p->cu;
    4662             : 
    4663             :   return false;
    4664             : }
    4665             : 
    4666             : 
    4667             : static void
    4668          34 : print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
    4669             :                             Ebl *ebl, GElf_Ehdr *ehdr,
    4670             :                             Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    4671             : {
    4672          68 :   const size_t sh_size = (dbg->sectiondata[IDX_debug_abbrev] ?
    4673          34 :                           dbg->sectiondata[IDX_debug_abbrev]->d_size : 0);
    4674             : 
    4675         102 :   printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
    4676             :                    " [ Code]\n"),
    4677             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    4678          34 :           (uint64_t) shdr->sh_offset);
    4679             : 
    4680          34 :   Dwarf_Off offset = 0;
    4681          34 :   while (offset < sh_size)
    4682             :     {
    4683        1271 :       printf (gettext ("\nAbbreviation section at offset %" PRIu64 ":\n"),
    4684             :               offset);
    4685             : 
    4686             :       while (1)
    4687       65837 :         {
    4688             :           size_t length;
    4689             :           Dwarf_Abbrev abbrev;
    4690             : 
    4691       67108 :           int res = dwarf_offabbrev (dbg, offset, &length, &abbrev);
    4692       67108 :           if (res != 0)
    4693             :             {
    4694        1271 :               if (unlikely (res < 0))
    4695             :                 {
    4696           0 :                   printf (gettext ("\
    4697             :  *** error while reading abbreviation: %s\n"),
    4698             :                           dwarf_errmsg (-1));
    4699           0 :                   return;
    4700             :                 }
    4701             : 
    4702             :               /* This is the NUL byte at the end of the section.  */
    4703        1271 :               ++offset;
    4704        1271 :               break;
    4705             :             }
    4706             : 
    4707             :           /* We know these calls can never fail.  */
    4708       65837 :           unsigned int code = dwarf_getabbrevcode (&abbrev);
    4709       65837 :           unsigned int tag = dwarf_getabbrevtag (&abbrev);
    4710       65837 :           int has_children = dwarf_abbrevhaschildren (&abbrev);
    4711             : 
    4712      131674 :           printf (gettext (" [%5u] offset: %" PRId64
    4713             :                            ", children: %s, tag: %s\n"),
    4714             :                   code, (int64_t) offset,
    4715             :                   has_children ? gettext ("yes") : gettext ("no"),
    4716             :                   dwarf_tag_name (tag));
    4717             : 
    4718       65837 :           size_t cnt = 0;
    4719             :           unsigned int name;
    4720             :           unsigned int form;
    4721             :           Dwarf_Off enoffset;
    4722      384974 :           while (dwarf_getabbrevattr (&abbrev, cnt,
    4723             :                                       &name, &form, &enoffset) == 0)
    4724             :             {
    4725      506600 :               printf ("          attr: %s, form: %s, offset: %#" PRIx64 "\n",
    4726             :                       dwarf_attr_name (name), dwarf_form_name (form),
    4727             :                       (uint64_t) enoffset);
    4728             : 
    4729      253300 :               ++cnt;
    4730             :             }
    4731             : 
    4732       65837 :           offset += length;
    4733             :         }
    4734             :     }
    4735             : }
    4736             : 
    4737             : 
    4738             : /* Print content of DWARF .debug_aranges section.  We fortunately do
    4739             :    not have to know a bit about the structure of the section, libdwarf
    4740             :    takes care of it.  */
    4741             : static void
    4742           1 : print_decoded_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
    4743             :                                GElf_Shdr *shdr, Dwarf *dbg)
    4744             : {
    4745             :   Dwarf_Aranges *aranges;
    4746             :   size_t cnt;
    4747           1 :   if (unlikely (dwarf_getaranges (dbg, &aranges, &cnt) != 0))
    4748             :     {
    4749           0 :       error (0, 0, gettext ("cannot get .debug_aranges content: %s"),
    4750             :              dwarf_errmsg (-1));
    4751           0 :       return;
    4752             :     }
    4753             : 
    4754             :   GElf_Shdr glink_mem;
    4755             :   GElf_Shdr *glink;
    4756           1 :   glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink_mem);
    4757           1 :   if (glink == NULL)
    4758             :     {
    4759           0 :       error (0, 0, gettext ("invalid sh_link value in section %zu"),
    4760             :              elf_ndxscn (scn));
    4761             :       return;
    4762             :     }
    4763             : 
    4764           4 :   printf (ngettext ("\
    4765             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entry:\n",
    4766             :                     "\
    4767             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entries:\n",
    4768             :                     cnt),
    4769             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    4770           1 :           (uint64_t) shdr->sh_offset, cnt);
    4771             : 
    4772             :   /* Compute floor(log16(cnt)).  */
    4773           1 :   size_t tmp = cnt;
    4774           1 :   int digits = 1;
    4775           2 :   while (tmp >= 16)
    4776             :     {
    4777           0 :       ++digits;
    4778           0 :       tmp >>= 4;
    4779             :     }
    4780             : 
    4781           5 :   for (size_t n = 0; n < cnt; ++n)
    4782             :     {
    4783           5 :       Dwarf_Arange *runp = dwarf_onearange (aranges, n);
    4784           5 :       if (unlikely (runp == NULL))
    4785             :         {
    4786           0 :           printf ("cannot get arange %zu: %s\n", n, dwarf_errmsg (-1));
    4787           0 :           return;
    4788             :         }
    4789             : 
    4790             :       Dwarf_Addr start;
    4791             :       Dwarf_Word length;
    4792             :       Dwarf_Off offset;
    4793             : 
    4794           5 :       if (unlikely (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0))
    4795           0 :         printf (gettext (" [%*zu] ???\n"), digits, n);
    4796             :       else
    4797          10 :         printf (gettext (" [%*zu] start: %0#*" PRIx64
    4798             :                          ", length: %5" PRIu64 ", CU DIE offset: %6"
    4799             :                          PRId64 "\n"),
    4800           5 :                 digits, n, ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 10 : 18,
    4801             :                 (uint64_t) start, (uint64_t) length, (int64_t) offset);
    4802             :     }
    4803             : }
    4804             : 
    4805             : 
    4806             : /* Print content of DWARF .debug_aranges section.  */
    4807             : static void
    4808          38 : print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
    4809             :                              Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
    4810             :                              GElf_Shdr *shdr, Dwarf *dbg)
    4811             : {
    4812          38 :   if (decodedaranges)
    4813             :     {
    4814           1 :       print_decoded_aranges_section (ebl, ehdr, scn, shdr, dbg);
    4815           1 :       return;
    4816             :     }
    4817             : 
    4818          37 :   Elf_Data *data = dbg->sectiondata[IDX_debug_aranges];
    4819             : 
    4820          37 :   if (unlikely (data == NULL))
    4821             :     {
    4822           0 :       error (0, 0, gettext ("cannot get .debug_aranges content: %s"),
    4823             :              elf_errmsg (-1));
    4824             :       return;
    4825             :     }
    4826             : 
    4827         111 :   printf (gettext ("\
    4828             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
    4829             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    4830          37 :           (uint64_t) shdr->sh_offset);
    4831             : 
    4832          37 :   const unsigned char *readp = data->d_buf;
    4833          37 :   const unsigned char *readendp = readp + data->d_size;
    4834             : 
    4835        1342 :   while (readp < readendp)
    4836             :     {
    4837        1268 :       const unsigned char *hdrstart = readp;
    4838        1268 :       size_t start_offset = hdrstart - (const unsigned char *) data->d_buf;
    4839             : 
    4840        2536 :       printf (gettext ("\nTable at offset %zu:\n"), start_offset);
    4841        1268 :       if (readp + 4 > readendp)
    4842             :         {
    4843           0 :         invalid_data:
    4844           0 :           error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
    4845             :                  elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
    4846             :           return;
    4847             :         }
    4848             : 
    4849        1282 :       Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
    4850        1268 :       unsigned int length_bytes = 4;
    4851        1268 :       if (length == DWARF3_LENGTH_64_BIT)
    4852             :         {
    4853           0 :           if (readp + 8 > readendp)
    4854             :             goto invalid_data;
    4855           0 :           length = read_8ubyte_unaligned_inc (dbg, readp);
    4856           0 :           length_bytes = 8;
    4857             :         }
    4858             : 
    4859        1268 :       const unsigned char *nexthdr = readp + length;
    4860        2536 :       printf (gettext ("\n Length:        %6" PRIu64 "\n"),
    4861             :               (uint64_t) length);
    4862             : 
    4863        1268 :       if (unlikely (length > (size_t) (readendp - readp)))
    4864             :         goto invalid_data;
    4865             : 
    4866        1268 :       if (length == 0)
    4867           0 :         continue;
    4868             : 
    4869        1268 :       if (readp + 2 > readendp)
    4870             :         goto invalid_data;
    4871        1268 :       uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, readp);
    4872        2536 :       printf (gettext (" DWARF version: %6" PRIuFAST16 "\n"),
    4873             :               version);
    4874        1268 :       if (version != 2)
    4875             :         {
    4876           0 :           error (0, 0, gettext ("unsupported aranges version"));
    4877             :           goto next_table;
    4878             :         }
    4879             : 
    4880             :       Dwarf_Word offset;
    4881        1268 :       if (readp + length_bytes > readendp)
    4882             :         goto invalid_data;
    4883        1268 :       if (length_bytes == 8)
    4884           0 :         offset = read_8ubyte_unaligned_inc (dbg, readp);
    4885             :       else
    4886        1282 :         offset = read_4ubyte_unaligned_inc (dbg, readp);
    4887        2536 :       printf (gettext (" CU offset:     %6" PRIx64 "\n"),
    4888             :               (uint64_t) offset);
    4889             : 
    4890        1268 :       if (readp + 1 > readendp)
    4891             :         goto invalid_data;
    4892        1268 :       unsigned int address_size = *readp++;
    4893        2536 :       printf (gettext (" Address size:  %6" PRIu64 "\n"),
    4894             :               (uint64_t) address_size);
    4895        1268 :       if (address_size != 4 && address_size != 8)
    4896             :         {
    4897           0 :           error (0, 0, gettext ("unsupported address size"));
    4898             :           goto next_table;
    4899             :         }
    4900             : 
    4901        1268 :       unsigned int segment_size = *readp++;
    4902        2536 :       printf (gettext (" Segment size:  %6" PRIu64 "\n\n"),
    4903             :               (uint64_t) segment_size);
    4904        1268 :       if (segment_size != 0 && segment_size != 4 && segment_size != 8)
    4905             :         {
    4906           0 :           error (0, 0, gettext ("unsupported segment size"));
    4907             :           goto next_table;
    4908             :         }
    4909             : 
    4910             :       /* Round the address to the next multiple of 2*address_size.  */
    4911        2536 :       readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
    4912        1268 :                 % (2 * address_size));
    4913             : 
    4914        3863 :       while (readp < nexthdr)
    4915             :         {
    4916             :           Dwarf_Word range_address;
    4917             :           Dwarf_Word range_length;
    4918        2595 :           Dwarf_Word segment = 0;
    4919        2595 :           if (readp + 2 * address_size + segment_size > readendp)
    4920             :             goto invalid_data;
    4921        2595 :           if (address_size == 4)
    4922             :             {
    4923          36 :               range_address = read_4ubyte_unaligned_inc (dbg, readp);
    4924          36 :               range_length = read_4ubyte_unaligned_inc (dbg, readp);
    4925             :             }
    4926             :           else
    4927             :             {
    4928        2585 :               range_address = read_8ubyte_unaligned_inc (dbg, readp);
    4929        2585 :               range_length = read_8ubyte_unaligned_inc (dbg, readp);
    4930             :             }
    4931             : 
    4932        2595 :           if (segment_size == 4)
    4933           0 :             segment = read_4ubyte_unaligned_inc (dbg, readp);
    4934        2595 :           else if (segment_size == 8)
    4935           0 :             segment = read_8ubyte_unaligned_inc (dbg, readp);
    4936             : 
    4937        2595 :           if (range_address == 0 && range_length == 0 && segment == 0)
    4938             :             break;
    4939             : 
    4940        1327 :           char *b = format_dwarf_addr (dwflmod, address_size, range_address,
    4941             :                                        range_address);
    4942        1327 :           char *e = format_dwarf_addr (dwflmod, address_size,
    4943        1327 :                                        range_address + range_length - 1,
    4944             :                                        range_length);
    4945        1327 :           if (segment_size != 0)
    4946           0 :             printf (gettext ("   %s..%s (%" PRIx64 ")\n"), b, e,
    4947             :                     (uint64_t) segment);
    4948             :           else
    4949        1327 :             printf (gettext ("   %s..%s\n"), b, e);
    4950        1327 :           free (b);
    4951        1327 :           free (e);
    4952             :         }
    4953             : 
    4954        1268 :     next_table:
    4955        1268 :       if (readp != nexthdr)
    4956             :         {
    4957           0 :           size_t padding = nexthdr - readp;
    4958           0 :           printf (gettext ("   %zu padding bytes\n"), padding);
    4959           0 :           readp = nexthdr;
    4960             :         }
    4961             :     }
    4962             : }
    4963             : 
    4964             : 
    4965             : /* Print content of DWARF .debug_ranges section.  */
    4966             : static void
    4967          25 : print_debug_ranges_section (Dwfl_Module *dwflmod,
    4968             :                             Ebl *ebl, GElf_Ehdr *ehdr,
    4969             :                             Elf_Scn *scn, GElf_Shdr *shdr,
    4970             :                             Dwarf *dbg)
    4971             : {
    4972          25 :   Elf_Data *data = dbg->sectiondata[IDX_debug_ranges];
    4973             : 
    4974          25 :   if (unlikely (data == NULL))
    4975             :     {
    4976           0 :       error (0, 0, gettext ("cannot get .debug_ranges content: %s"),
    4977             :              elf_errmsg (-1));
    4978           0 :       return;
    4979             :     }
    4980             : 
    4981          75 :   printf (gettext ("\
    4982             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
    4983             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    4984          25 :           (uint64_t) shdr->sh_offset);
    4985             : 
    4986          50 :   sort_listptr (&known_rangelistptr, "rangelistptr");
    4987          25 :   size_t listptr_idx = 0;
    4988             : 
    4989          25 :   uint_fast8_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
    4990             : 
    4991          25 :   bool first = true;
    4992          25 :   Dwarf_Addr base = 0;
    4993          25 :   unsigned char *const endp = (unsigned char *) data->d_buf + data->d_size;
    4994          25 :   unsigned char *readp = data->d_buf;
    4995       36757 :   while (readp < endp)
    4996             :     {
    4997       36707 :       ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
    4998             : 
    4999       36707 :       if (first && skip_listptr_hole (&known_rangelistptr, &listptr_idx,
    5000             :                                       &address_size, NULL, &base, NULL,
    5001             :                                       offset, &readp, endp))
    5002           0 :         continue;
    5003             : 
    5004       36707 :       if (unlikely (data->d_size - offset < (size_t) address_size * 2))
    5005             :         {
    5006           0 :           printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
    5007             :           break;
    5008             :         }
    5009             : 
    5010             :       Dwarf_Addr begin;
    5011             :       Dwarf_Addr end;
    5012       36707 :       if (address_size == 8)
    5013             :         {
    5014       36707 :           begin = read_8ubyte_unaligned_inc (dbg, readp);
    5015       36707 :           end = read_8ubyte_unaligned_inc (dbg, readp);
    5016             :         }
    5017             :       else
    5018             :         {
    5019           0 :           begin = read_4ubyte_unaligned_inc (dbg, readp);
    5020           0 :           end = read_4ubyte_unaligned_inc (dbg, readp);
    5021           0 :           if (begin == (Dwarf_Addr) (uint32_t) -1)
    5022             :             begin = (Dwarf_Addr) -1l;
    5023             :         }
    5024             : 
    5025       36707 :       if (begin == (Dwarf_Addr) -1l) /* Base address entry.  */
    5026             :         {
    5027           0 :           char *b = format_dwarf_addr (dwflmod, address_size, end, end);
    5028           0 :           printf (gettext (" [%6tx]  base address %s\n"), offset, b);
    5029           0 :           free (b);
    5030           0 :           base = end;
    5031             :         }
    5032       36707 :       else if (begin == 0 && end == 0) /* End of list entry.  */
    5033             :         {
    5034        8827 :           if (first)
    5035           0 :             printf (gettext (" [%6tx]  empty list\n"), offset);
    5036             :           first = true;
    5037             :         }
    5038             :       else
    5039             :         {
    5040       27880 :           char *b = format_dwarf_addr (dwflmod, address_size, base + begin,
    5041             :                                        begin);
    5042       27880 :           char *e = format_dwarf_addr (dwflmod, address_size, base + end,
    5043             :                                        end);
    5044             :           /* We have an address range entry.  */
    5045       27880 :           if (first)            /* First address range entry in a list.  */
    5046        8827 :             printf (gettext (" [%6tx]  %s..%s\n"), offset, b, e);
    5047             :           else
    5048       19053 :             printf (gettext ("           %s..%s\n"), b, e);
    5049       27880 :           free (b);
    5050       27880 :           free (e);
    5051             : 
    5052       27880 :           first = false;
    5053             :         }
    5054             :     }
    5055             : }
    5056             : 
    5057             : #define REGNAMESZ 16
    5058             : static const char *
    5059       10545 : register_info (Ebl *ebl, unsigned int regno, const Ebl_Register_Location *loc,
    5060             :                char name[REGNAMESZ], int *bits, int *type)
    5061             : {
    5062             :   const char *set;
    5063             :   const char *pfx;
    5064             :   int ignore;
    5065       10545 :   ssize_t n = ebl_register_info (ebl, regno, name, REGNAMESZ, &pfx, &set,
    5066             :                                  bits ?: &ignore, type ?: &ignore);
    5067       10545 :   if (n <= 0)
    5068             :     {
    5069           0 :       if (loc != NULL)
    5070           0 :         snprintf (name, REGNAMESZ, "reg%u", loc->regno);
    5071             :       else
    5072             :         snprintf (name, REGNAMESZ, "??? 0x%x", regno);
    5073           0 :       if (bits != NULL)
    5074           0 :         *bits = loc != NULL ? loc->bits : 0;
    5075           0 :       if (type != NULL)
    5076           0 :         *type = DW_ATE_unsigned;
    5077           0 :       set = "??? unrecognized";
    5078             :     }
    5079             :   else
    5080             :     {
    5081       10545 :       if (bits != NULL && *bits <= 0)
    5082           0 :         *bits = loc != NULL ? loc->bits : 0;
    5083       10545 :       if (type != NULL && *type == DW_ATE_void)
    5084           0 :         *type = DW_ATE_unsigned;
    5085             : 
    5086             :     }
    5087       10545 :   return set;
    5088             : }
    5089             : 
    5090             : static const unsigned char *
    5091          32 : read_encoded (unsigned int encoding, const unsigned char *readp,
    5092             :               const unsigned char *const endp, uint64_t *res, Dwarf *dbg)
    5093             : {
    5094          32 :   if ((encoding & 0xf) == DW_EH_PE_absptr)
    5095           0 :     encoding = gelf_getclass (dbg->elf) == ELFCLASS32
    5096           0 :       ? DW_EH_PE_udata4 : DW_EH_PE_udata8;
    5097             : 
    5098          32 :   switch (encoding & 0xf)
    5099             :     {
    5100           0 :     case DW_EH_PE_uleb128:
    5101           0 :       get_uleb128 (*res, readp, endp);
    5102             :       break;
    5103           0 :     case DW_EH_PE_sleb128:
    5104           0 :       get_sleb128 (*res, readp, endp);
    5105             :       break;
    5106           0 :     case DW_EH_PE_udata2:
    5107           0 :       if (readp + 2 > endp)
    5108             :         goto invalid;
    5109           0 :       *res = read_2ubyte_unaligned_inc (dbg, readp);
    5110             :       break;
    5111          16 :     case DW_EH_PE_udata4:
    5112          16 :       if (readp + 4 > endp)
    5113             :         goto invalid;
    5114          16 :       *res = read_4ubyte_unaligned_inc (dbg, readp);
    5115             :       break;
    5116           0 :     case DW_EH_PE_udata8:
    5117           0 :       if (readp + 8 > endp)
    5118             :         goto invalid;
    5119           0 :       *res = read_8ubyte_unaligned_inc (dbg, readp);
    5120             :       break;
    5121           0 :     case DW_EH_PE_sdata2:
    5122           0 :       if (readp + 2 > endp)
    5123             :         goto invalid;
    5124           0 :       *res = read_2sbyte_unaligned_inc (dbg, readp);
    5125             :       break;
    5126          16 :     case DW_EH_PE_sdata4:
    5127          16 :       if (readp + 4 > endp)
    5128             :         goto invalid;
    5129          16 :       *res = read_4sbyte_unaligned_inc (dbg, readp);
    5130             :       break;
    5131           0 :     case DW_EH_PE_sdata8:
    5132           0 :       if (readp + 8 > endp)
    5133             :         goto invalid;
    5134           0 :       *res = read_8sbyte_unaligned_inc (dbg, readp);
    5135             :       break;
    5136             :     default:
    5137           0 :     invalid:
    5138             :       error (1, 0,
    5139           0 :              gettext ("invalid encoding"));
    5140             :     }
    5141             : 
    5142          32 :   return readp;
    5143             : }
    5144             : 
    5145             : 
    5146             : static void
    5147        5569 : print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
    5148             :                    Dwarf_Word vma_base, unsigned int code_align,
    5149             :                    int data_align,
    5150             :                    unsigned int version, unsigned int ptr_size,
    5151             :                    unsigned int encoding,
    5152             :                    Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg)
    5153             : {
    5154             :   char regnamebuf[REGNAMESZ];
    5155             :   const char *regname (unsigned int regno)
    5156             :   {
    5157        9759 :     register_info (ebl, regno, NULL, regnamebuf, NULL, NULL);
    5158             :     return regnamebuf;
    5159             :   }
    5160             : 
    5161        5569 :   puts ("\n   Program:");
    5162        5569 :   Dwarf_Word pc = vma_base;
    5163      110443 :   while (readp < endp)
    5164             :     {
    5165       99305 :       unsigned int opcode = *readp++;
    5166             : 
    5167       99305 :       if (opcode < DW_CFA_advance_loc)
    5168             :         /* Extended opcode.  */
    5169       63240 :         switch (opcode)
    5170             :           {
    5171             :             uint64_t op1;
    5172             :             int64_t sop1;
    5173             :             uint64_t op2;
    5174             :             int64_t sop2;
    5175             : 
    5176       28539 :           case DW_CFA_nop:
    5177       28539 :             puts ("     nop");
    5178       91779 :             break;
    5179           0 :           case DW_CFA_set_loc:
    5180           0 :             if ((uint64_t) (endp - readp) < 1)
    5181             :               goto invalid;
    5182           0 :             readp = read_encoded (encoding, readp, endp, &op1, dbg);
    5183           0 :             printf ("     set_loc %#" PRIx64 " to %#" PRIx64 "\n",
    5184           0 :                     op1, pc = vma_base + op1);
    5185             :             break;
    5186        1879 :           case DW_CFA_advance_loc1:
    5187        1879 :             if ((uint64_t) (endp - readp) < 1)
    5188             :               goto invalid;
    5189        3758 :             printf ("     advance_loc1 %u to %#" PRIx64 "\n",
    5190        1879 :                     *readp, pc += *readp * code_align);
    5191        1879 :             ++readp;
    5192        1879 :             break;
    5193         773 :           case DW_CFA_advance_loc2:
    5194         773 :             if ((uint64_t) (endp - readp) < 2)
    5195             :               goto invalid;
    5196         773 :             op1 = read_2ubyte_unaligned_inc (dbg, readp);
    5197         773 :             printf ("     advance_loc2 %" PRIu64 " to %#" PRIx64 "\n",
    5198         773 :                     op1, pc += op1 * code_align);
    5199             :             break;
    5200          24 :           case DW_CFA_advance_loc4:
    5201          24 :             if ((uint64_t) (endp - readp) < 4)
    5202             :               goto invalid;
    5203          48 :             op1 = read_4ubyte_unaligned_inc (dbg, readp);
    5204          24 :             printf ("     advance_loc4 %" PRIu64 " to %#" PRIx64 "\n",
    5205          24 :                     op1, pc += op1 * code_align);
    5206             :             break;
    5207           4 :           case DW_CFA_offset_extended:
    5208           4 :             if ((uint64_t) (endp - readp) < 1)
    5209             :               goto invalid;
    5210           4 :             get_uleb128 (op1, readp, endp);
    5211           4 :             if ((uint64_t) (endp - readp) < 1)
    5212             :               goto invalid;
    5213           4 :             get_uleb128 (op2, readp, endp);
    5214           8 :             printf ("     offset_extended r%" PRIu64 " (%s) at cfa%+" PRId64
    5215             :                     "\n",
    5216             :                     op1, regname (op1), op2 * data_align);
    5217             :             break;
    5218           0 :           case DW_CFA_restore_extended:
    5219           0 :             if ((uint64_t) (endp - readp) < 1)
    5220             :               goto invalid;
    5221           0 :             get_uleb128 (op1, readp, endp);
    5222           0 :             printf ("     restore_extended r%" PRIu64 " (%s)\n",
    5223             :                     op1, regname (op1));
    5224             :             break;
    5225           8 :           case DW_CFA_undefined:
    5226           8 :             if ((uint64_t) (endp - readp) < 1)
    5227             :               goto invalid;
    5228           8 :             get_uleb128 (op1, readp, endp);
    5229          16 :             printf ("     undefined r%" PRIu64 " (%s)\n", op1, regname (op1));
    5230             :             break;
    5231           0 :           case DW_CFA_same_value:
    5232           0 :             if ((uint64_t) (endp - readp) < 1)
    5233             :               goto invalid;
    5234           0 :             get_uleb128 (op1, readp, endp);
    5235           0 :             printf ("     same_value r%" PRIu64 " (%s)\n", op1, regname (op1));
    5236             :             break;
    5237           0 :           case DW_CFA_register:
    5238           0 :             if ((uint64_t) (endp - readp) < 1)
    5239             :               goto invalid;
    5240           0 :             get_uleb128 (op1, readp, endp);
    5241           0 :             if ((uint64_t) (endp - readp) < 1)
    5242             :               goto invalid;
    5243           0 :             get_uleb128 (op2, readp, endp);
    5244           0 :             printf ("     register r%" PRIu64 " (%s) in r%" PRIu64 " (%s)\n",
    5245             :                     op1, regname (op1), op2, regname (op2));
    5246             :             break;
    5247        2976 :           case DW_CFA_remember_state:
    5248        2976 :             puts ("     remember_state");
    5249        2976 :             break;
    5250        2976 :           case DW_CFA_restore_state:
    5251        2976 :             puts ("     restore_state");
    5252        2976 :             break;
    5253         128 :           case DW_CFA_def_cfa:
    5254         128 :             if ((uint64_t) (endp - readp) < 1)
    5255             :               goto invalid;
    5256         128 :             get_uleb128 (op1, readp, endp);
    5257         128 :             if ((uint64_t) (endp - readp) < 1)
    5258             :               goto invalid;
    5259         128 :             get_uleb128 (op2, readp, endp);
    5260         256 :             printf ("     def_cfa r%" PRIu64 " (%s) at offset %" PRIu64 "\n",
    5261             :                     op1, regname (op1), op2);
    5262             :             break;
    5263          45 :           case DW_CFA_def_cfa_register:
    5264          45 :             if ((uint64_t) (endp - readp) < 1)
    5265             :               goto invalid;
    5266          45 :             get_uleb128 (op1, readp, endp);
    5267          90 :             printf ("     def_cfa_register r%" PRIu64 " (%s)\n",
    5268             :                     op1, regname (op1));
    5269             :             break;
    5270       25858 :           case DW_CFA_def_cfa_offset:
    5271       25858 :             if ((uint64_t) (endp - readp) < 1)
    5272             :               goto invalid;
    5273       25858 :             get_uleb128 (op1, readp, endp);
    5274       25858 :             printf ("     def_cfa_offset %" PRIu64 "\n", op1);
    5275             :             break;
    5276          14 :           case DW_CFA_def_cfa_expression:
    5277          14 :             if ((uint64_t) (endp - readp) < 1)
    5278             :               goto invalid;
    5279          14 :             get_uleb128 (op1, readp, endp);     /* Length of DW_FORM_block.  */
    5280          28 :             printf ("     def_cfa_expression %" PRIu64 "\n", op1);
    5281          14 :             if ((uint64_t) (endp - readp) < op1)
    5282             :               {
    5283           0 :             invalid:
    5284           0 :                 fputs (gettext ("         <INVALID DATA>\n"), stdout);
    5285           0 :                 return;
    5286             :               }
    5287          14 :             print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0, NULL,
    5288             :                        op1, readp);
    5289          14 :             readp += op1;
    5290          14 :             break;
    5291           0 :           case DW_CFA_expression:
    5292           0 :             if ((uint64_t) (endp - readp) < 1)
    5293             :               goto invalid;
    5294           0 :             get_uleb128 (op1, readp, endp);
    5295           0 :             if ((uint64_t) (endp - readp) < 1)
    5296             :               goto invalid;
    5297           0 :             get_uleb128 (op2, readp, endp);     /* Length of DW_FORM_block.  */
    5298           0 :             printf ("     expression r%" PRIu64 " (%s) \n",
    5299             :                     op1, regname (op1));
    5300           0 :             if ((uint64_t) (endp - readp) < op2)
    5301             :               goto invalid;
    5302           0 :             print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0, NULL,
    5303             :                        op2, readp);
    5304           0 :             readp += op2;
    5305           0 :             break;
    5306          16 :           case DW_CFA_offset_extended_sf:
    5307          16 :             if ((uint64_t) (endp - readp) < 1)
    5308             :               goto invalid;
    5309          16 :             get_uleb128 (op1, readp, endp);
    5310          16 :             if ((uint64_t) (endp - readp) < 1)
    5311             :               goto invalid;
    5312          16 :             get_sleb128 (sop2, readp, endp);
    5313          32 :             printf ("     offset_extended_sf r%" PRIu64 " (%s) at cfa%+"
    5314             :                     PRId64 "\n",
    5315             :                     op1, regname (op1), sop2 * data_align);
    5316             :             break;
    5317           0 :           case DW_CFA_def_cfa_sf:
    5318           0 :             if ((uint64_t) (endp - readp) < 1)
    5319             :               goto invalid;
    5320           0 :             get_uleb128 (op1, readp, endp);
    5321           0 :             if ((uint64_t) (endp - readp) < 1)
    5322             :               goto invalid;
    5323           0 :             get_sleb128 (sop2, readp, endp);
    5324           0 :             printf ("     def_cfa_sf r%" PRIu64 " (%s) at offset %" PRId64 "\n",
    5325             :                     op1, regname (op1), sop2 * data_align);
    5326             :             break;
    5327           0 :           case DW_CFA_def_cfa_offset_sf:
    5328           0 :             if ((uint64_t) (endp - readp) < 1)
    5329             :               goto invalid;
    5330           0 :             get_sleb128 (sop1, readp, endp);
    5331           0 :             printf ("     def_cfa_offset_sf %" PRId64 "\n", sop1 * data_align);
    5332             :             break;
    5333           0 :           case DW_CFA_val_offset:
    5334           0 :             if ((uint64_t) (endp - readp) < 1)
    5335             :               goto invalid;
    5336           0 :             get_uleb128 (op1, readp, endp);
    5337           0 :             if ((uint64_t) (endp - readp) < 1)
    5338             :               goto invalid;
    5339           0 :             get_uleb128 (op2, readp, endp);
    5340           0 :             printf ("     val_offset %" PRIu64 " at offset %" PRIu64 "\n",
    5341             :                     op1, op2 * data_align);
    5342             :             break;
    5343           0 :           case DW_CFA_val_offset_sf:
    5344           0 :             if ((uint64_t) (endp - readp) < 1)
    5345             :               goto invalid;
    5346           0 :             get_uleb128 (op1, readp, endp);
    5347           0 :             if ((uint64_t) (endp - readp) < 1)
    5348             :               goto invalid;
    5349           0 :             get_sleb128 (sop2, readp, endp);
    5350           0 :             printf ("     val_offset_sf %" PRIu64 " at offset %" PRId64 "\n",
    5351             :                     op1, sop2 * data_align);
    5352             :             break;
    5353           0 :           case DW_CFA_val_expression:
    5354           0 :             if ((uint64_t) (endp - readp) < 1)
    5355             :               goto invalid;
    5356           0 :             get_uleb128 (op1, readp, endp);
    5357           0 :             if ((uint64_t) (endp - readp) < 1)
    5358             :               goto invalid;
    5359           0 :             get_uleb128 (op2, readp, endp);     /* Length of DW_FORM_block.  */
    5360           0 :             printf ("     val_expression r%" PRIu64 " (%s)\n",
    5361             :                     op1, regname (op1));
    5362           0 :             if ((uint64_t) (endp - readp) < op2)
    5363             :               goto invalid;
    5364           0 :             print_ops (dwflmod, dbg, 10, 10, version, ptr_size, 0,
    5365             :                        NULL, op2, readp);
    5366           0 :             readp += op2;
    5367           0 :             break;
    5368           0 :           case DW_CFA_MIPS_advance_loc8:
    5369           0 :             if ((uint64_t) (endp - readp) < 8)
    5370             :               goto invalid;
    5371           0 :             op1 = read_8ubyte_unaligned_inc (dbg, readp);
    5372           0 :             printf ("     MIPS_advance_loc8 %" PRIu64 " to %#" PRIx64 "\n",
    5373           0 :                     op1, pc += op1 * code_align);
    5374             :             break;
    5375           0 :           case DW_CFA_GNU_window_save:
    5376           0 :             puts ("     GNU_window_save");
    5377           0 :             break;
    5378           0 :           case DW_CFA_GNU_args_size:
    5379           0 :             if ((uint64_t) (endp - readp) < 1)
    5380             :               goto invalid;
    5381           0 :             get_uleb128 (op1, readp, endp);
    5382           0 :             printf ("     args_size %" PRIu64 "\n", op1);
    5383             :             break;
    5384           0 :           default:
    5385             :             printf ("     ??? (%u)\n", opcode);
    5386             :             break;
    5387             :           }
    5388       36065 :       else if (opcode < DW_CFA_offset)
    5389       26507 :         printf ("     advance_loc %u to %#" PRIx64 "\n",
    5390       26507 :                 opcode & 0x3f, pc += (opcode & 0x3f) * code_align);
    5391        9558 :       else if (opcode < DW_CFA_restore)
    5392             :         {
    5393             :           uint64_t offset;
    5394        8186 :           if ((uint64_t) (endp - readp) < 1)
    5395             :             goto invalid;
    5396        8186 :           get_uleb128 (offset, readp, endp);
    5397       16372 :           printf ("     offset r%u (%s) at cfa%+" PRId64 "\n",
    5398             :                   opcode & 0x3f, regname (opcode & 0x3f), offset * data_align);
    5399             :         }
    5400             :       else
    5401        2744 :         printf ("     restore r%u (%s)\n",
    5402             :                 opcode & 0x3f, regname (opcode & 0x3f));
    5403             :     }
    5404             : }
    5405             : 
    5406             : 
    5407             : static unsigned int
    5408        5503 : encoded_ptr_size (int encoding, unsigned int ptr_size)
    5409             : {
    5410        5503 :   switch (encoding & 7)
    5411             :     {
    5412             :     case DW_EH_PE_udata4:
    5413             :       return 4;
    5414           0 :     case DW_EH_PE_udata8:
    5415           0 :       return 8;
    5416          34 :     case 0:
    5417          34 :       return ptr_size;
    5418             :     }
    5419             : 
    5420           0 :   fprintf (stderr, "Unsupported pointer encoding: %#x, "
    5421             :            "assuming pointer size of %d.\n", encoding, ptr_size);
    5422           0 :   return ptr_size;
    5423             : }
    5424             : 
    5425             : 
    5426             : static unsigned int
    5427          88 : print_encoding (unsigned int val)
    5428             : {
    5429          88 :   switch (val & 0xf)
    5430             :     {
    5431           0 :     case DW_EH_PE_absptr:
    5432           0 :       fputs ("absptr", stdout);
    5433           0 :       break;
    5434           0 :     case DW_EH_PE_uleb128:
    5435           0 :       fputs ("uleb128", stdout);
    5436           0 :       break;
    5437           0 :     case DW_EH_PE_udata2:
    5438           0 :       fputs ("udata2", stdout);
    5439           0 :       break;
    5440          16 :     case DW_EH_PE_udata4:
    5441          16 :       fputs ("udata4", stdout);
    5442          16 :       break;
    5443           0 :     case DW_EH_PE_udata8:
    5444           0 :       fputs ("udata8", stdout);
    5445           0 :       break;
    5446           0 :     case DW_EH_PE_sleb128:
    5447           0 :       fputs ("sleb128", stdout);
    5448           0 :       break;
    5449           0 :     case DW_EH_PE_sdata2:
    5450           0 :       fputs ("sdata2", stdout);
    5451           0 :       break;
    5452          72 :     case DW_EH_PE_sdata4:
    5453          72 :       fputs ("sdata4", stdout);
    5454          72 :       break;
    5455           0 :     case DW_EH_PE_sdata8:
    5456           0 :       fputs ("sdata8", stdout);
    5457           0 :       break;
    5458             :     default:
    5459             :       /* We did not use any of the bits after all.  */
    5460             :       return val;
    5461             :     }
    5462             : 
    5463          88 :   return val & ~0xf;
    5464             : }
    5465             : 
    5466             : 
    5467             : static unsigned int
    5468          72 : print_relinfo (unsigned int val)
    5469             : {
    5470          72 :   switch (val & 0x70)
    5471             :     {
    5472          56 :     case DW_EH_PE_pcrel:
    5473          56 :       fputs ("pcrel", stdout);
    5474          56 :       break;
    5475           0 :     case DW_EH_PE_textrel:
    5476           0 :       fputs ("textrel", stdout);
    5477           0 :       break;
    5478          16 :     case DW_EH_PE_datarel:
    5479          16 :       fputs ("datarel", stdout);
    5480          16 :       break;
    5481           0 :     case DW_EH_PE_funcrel:
    5482           0 :       fputs ("funcrel", stdout);
    5483           0 :       break;
    5484           0 :     case DW_EH_PE_aligned:
    5485           0 :       fputs ("aligned", stdout);
    5486           0 :       break;
    5487             :     default:
    5488             :       return val;
    5489             :     }
    5490             : 
    5491          72 :   return val & ~0x70;
    5492             : }
    5493             : 
    5494             : 
    5495             : static void
    5496          88 : print_encoding_base (const char *pfx, unsigned int fde_encoding)
    5497             : {
    5498          88 :   printf ("(%s", pfx);
    5499             : 
    5500          88 :   if (fde_encoding == DW_EH_PE_omit)
    5501           0 :     puts ("omit)");
    5502             :   else
    5503             :     {
    5504          88 :       unsigned int w = fde_encoding;
    5505             : 
    5506          88 :       w = print_encoding (w);
    5507             : 
    5508          88 :       if (w & 0x70)
    5509             :         {
    5510          72 :           if (w != fde_encoding)
    5511          72 :             fputc_unlocked (' ', stdout);
    5512             : 
    5513          72 :           w = print_relinfo (w);
    5514             :         }
    5515             : 
    5516          88 :       if (w != 0)
    5517           0 :         printf ("%s%x", w != fde_encoding ? " " : "", w);
    5518             : 
    5519          88 :       puts (")");
    5520             :     }
    5521          88 : }
    5522             : 
    5523             : 
    5524             : static void
    5525          42 : print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
    5526             :                            Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    5527             : {
    5528             :   size_t shstrndx;
    5529             :   /* We know this call will succeed since it did in the caller.  */
    5530          42 :   (void) elf_getshdrstrndx (ebl->elf, &shstrndx);
    5531          42 :   const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
    5532             : 
    5533             :   /* Needed if we find PC-relative addresses.  */
    5534             :   GElf_Addr bias;
    5535          42 :   if (dwfl_module_getelf (dwflmod, &bias) == NULL)
    5536             :     {
    5537           0 :       error (0, 0, gettext ("cannot get ELF: %s"), dwfl_errmsg (-1));
    5538           0 :       return;
    5539             :     }
    5540             : 
    5541          42 :   bool is_eh_frame = strcmp (scnname, ".eh_frame") == 0;
    5542          42 :   Elf_Data *data = (is_eh_frame
    5543             :                     ? elf_rawdata (scn, NULL)
    5544          42 :                     : dbg->sectiondata[IDX_debug_frame]);
    5545             : 
    5546          42 :   if (unlikely (data == NULL))
    5547             :     {
    5548           0 :       error (0, 0, gettext ("cannot get %s content: %s"),
    5549             :              scnname, elf_errmsg (-1));
    5550             :       return;
    5551             :     }
    5552             : 
    5553          42 :   if (is_eh_frame)
    5554          28 :     printf (gettext ("\
    5555             : \nCall frame information section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
    5556          28 :             elf_ndxscn (scn), scnname, (uint64_t) shdr->sh_offset);
    5557             :   else
    5558          14 :     printf (gettext ("\
    5559             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
    5560          14 :             elf_ndxscn (scn), scnname, (uint64_t) shdr->sh_offset);
    5561             : 
    5562             :   struct cieinfo
    5563             :   {
    5564             :     ptrdiff_t cie_offset;
    5565             :     const char *augmentation;
    5566             :     unsigned int code_alignment_factor;
    5567             :     unsigned int data_alignment_factor;
    5568             :     uint8_t address_size;
    5569             :     uint8_t fde_encoding;
    5570             :     uint8_t lsda_encoding;
    5571             :     struct cieinfo *next;
    5572          42 :   } *cies = NULL;
    5573             : 
    5574          42 :   const unsigned char *readp = data->d_buf;
    5575          42 :   const unsigned char *const dataend = ((unsigned char *) data->d_buf
    5576          42 :                                         + data->d_size);
    5577        5669 :   while (readp < dataend)
    5578             :     {
    5579        5585 :       if (unlikely (readp + 4 > dataend))
    5580             :         {
    5581           0 :         invalid_data:
    5582           0 :           error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
    5583             :                      elf_ndxscn (scn), scnname);
    5584             :               return;
    5585             :         }
    5586             : 
    5587             :       /* At the beginning there must be a CIE.  There can be multiple,
    5588             :          hence we test tis in a loop.  */
    5589        5585 :       ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
    5590             : 
    5591        5617 :       Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, readp);
    5592        5585 :       unsigned int length = 4;
    5593        5585 :       if (unlikely (unit_length == 0xffffffff))
    5594             :         {
    5595           0 :           if (unlikely (readp + 8 > dataend))
    5596             :             goto invalid_data;
    5597             : 
    5598           0 :           unit_length = read_8ubyte_unaligned_inc (dbg, readp);
    5599           0 :           length = 8;
    5600             :         }
    5601             : 
    5602        5585 :       if (unlikely (unit_length == 0))
    5603             :         {
    5604          32 :           printf (gettext ("\n [%6tx] Zero terminator\n"), offset);
    5605          16 :           continue;
    5606             :         }
    5607             : 
    5608        5569 :       Dwarf_Word maxsize = dataend - readp;
    5609        5569 :       if (unlikely (unit_length > maxsize))
    5610             :         goto invalid_data;
    5611             : 
    5612        5569 :       unsigned int ptr_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
    5613             : 
    5614        5569 :       ptrdiff_t start = readp - (unsigned char *) data->d_buf;
    5615        5569 :       const unsigned char *const cieend = readp + unit_length;
    5616       11138 :       if (unlikely (cieend > dataend || readp + 8 > dataend))
    5617             :         goto invalid_data;
    5618             : 
    5619             :       Dwarf_Off cie_id;
    5620        5569 :       if (length == 4)
    5621             :         {
    5622        5601 :           cie_id = read_4ubyte_unaligned_inc (dbg, readp);
    5623        5569 :           if (!is_eh_frame && cie_id == DW_CIE_ID_32)
    5624          24 :             cie_id = DW_CIE_ID_64;
    5625             :         }
    5626             :       else
    5627           0 :         cie_id = read_8ubyte_unaligned_inc (dbg, readp);
    5628             : 
    5629        5569 :       uint_fast8_t version = 2;
    5630             :       unsigned int code_alignment_factor;
    5631             :       int data_alignment_factor;
    5632        5569 :       unsigned int fde_encoding = 0;
    5633        5569 :       unsigned int lsda_encoding = 0;
    5634        5569 :       Dwarf_Word initial_location = 0;
    5635        5569 :       Dwarf_Word vma_base = 0;
    5636             : 
    5637        5569 :       if (cie_id == (is_eh_frame ? 0 : DW_CIE_ID_64))
    5638             :         {
    5639          66 :           version = *readp++;
    5640          66 :           const char *const augmentation = (const char *) readp;
    5641          66 :           readp = memchr (readp, '\0', cieend - readp);
    5642          66 :           if (unlikely (readp == NULL))
    5643             :             goto invalid_data;
    5644          66 :           ++readp;
    5645             : 
    5646          66 :           uint_fast8_t segment_size = 0;
    5647          66 :           if (version >= 4)
    5648             :             {
    5649           0 :               if (cieend - readp < 5)
    5650             :                 goto invalid_data;
    5651           0 :               ptr_size = *readp++;
    5652           0 :               segment_size = *readp++;
    5653             :             }
    5654             : 
    5655          66 :           if (cieend - readp < 1)
    5656             :             goto invalid_data;
    5657          66 :           get_uleb128 (code_alignment_factor, readp, cieend);
    5658          66 :           if (cieend - readp < 1)
    5659             :             goto invalid_data;
    5660          66 :           get_sleb128 (data_alignment_factor, readp, cieend);
    5661             : 
    5662             :           /* In some variant for unwind data there is another field.  */
    5663          66 :           if (strcmp (augmentation, "eh") == 0)
    5664           0 :             readp += ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
    5665             : 
    5666             :           unsigned int return_address_register;
    5667          66 :           if (cieend - readp < 1)
    5668             :             goto invalid_data;
    5669          66 :           if (unlikely (version == 1))
    5670          54 :             return_address_register = *readp++;
    5671             :           else
    5672          12 :             get_uleb128 (return_address_register, readp, cieend);
    5673             : 
    5674         132 :           printf ("\n [%6tx] CIE length=%" PRIu64 "\n"
    5675             :                   "   CIE_id:                   %" PRIu64 "\n"
    5676             :                   "   version:                  %u\n"
    5677             :                   "   augmentation:             \"%s\"\n",
    5678             :                   offset, (uint64_t) unit_length, (uint64_t) cie_id,
    5679             :                   version, augmentation);
    5680          66 :           if (version >= 4)
    5681           0 :             printf ("   address_size:             %u\n"
    5682             :                     "   segment_size:             %u\n",
    5683             :                     ptr_size, segment_size);
    5684          66 :           printf ("   code_alignment_factor:    %u\n"
    5685             :                   "   data_alignment_factor:    %d\n"
    5686             :                   "   return_address_register:  %u\n",
    5687             :                   code_alignment_factor,
    5688             :                   data_alignment_factor, return_address_register);
    5689             : 
    5690          66 :           if (augmentation[0] == 'z')
    5691             :             {
    5692             :               unsigned int augmentationlen;
    5693          40 :               get_uleb128 (augmentationlen, readp, cieend);
    5694             : 
    5695          40 :               if (augmentationlen > (size_t) (cieend - readp))
    5696             :                 {
    5697           0 :                   error (0, 0, gettext ("invalid augmentation length"));
    5698           0 :                   readp = cieend;
    5699           0 :                   continue;
    5700             :                 }
    5701             : 
    5702          40 :               const char *hdr = "Augmentation data:";
    5703          40 :               const char *cp = augmentation + 1;
    5704         120 :               while (*cp != '\0' && cp < augmentation + augmentationlen + 1)
    5705             :                 {
    5706          80 :                   printf ("   %-26s%#x ", hdr, *readp);
    5707          40 :                   hdr = "";
    5708             : 
    5709          40 :                   if (*cp == 'R')
    5710             :                     {
    5711          40 :                       fde_encoding = *readp++;
    5712          40 :                       print_encoding_base (gettext ("FDE address encoding: "),
    5713             :                                            fde_encoding);
    5714             :                     }
    5715           0 :                   else if (*cp == 'L')
    5716             :                     {
    5717           0 :                       lsda_encoding = *readp++;
    5718           0 :                       print_encoding_base (gettext ("LSDA pointer encoding: "),
    5719             :                                            lsda_encoding);
    5720             :                     }
    5721           0 :                   else if (*cp == 'P')
    5722             :                     {
    5723             :                       /* Personality.  This field usually has a relocation
    5724             :                          attached pointing to __gcc_personality_v0.  */
    5725           0 :                       const unsigned char *startp = readp;
    5726           0 :                       unsigned int encoding = *readp++;
    5727           0 :                       uint64_t val = 0;
    5728           0 :                       readp = read_encoded (encoding, readp,
    5729           0 :                                             readp - 1 + augmentationlen,
    5730             :                                             &val, dbg);
    5731             : 
    5732           0 :                       while (++startp < readp)
    5733           0 :                         printf ("%#x ", *startp);
    5734             : 
    5735           0 :                       putchar ('(');
    5736           0 :                       print_encoding (encoding);
    5737           0 :                       putchar (' ');
    5738           0 :                       switch (encoding & 0xf)
    5739             :                         {
    5740           0 :                         case DW_EH_PE_sleb128:
    5741             :                         case DW_EH_PE_sdata2:
    5742             :                         case DW_EH_PE_sdata4:
    5743           0 :                           printf ("%" PRId64 ")\n", val);
    5744             :                           break;
    5745           0 :                         default:
    5746           0 :                           printf ("%#" PRIx64 ")\n", val);
    5747             :                           break;
    5748             :                         }
    5749             :                     }
    5750             :                   else
    5751           0 :                     printf ("(%x)\n", *readp++);
    5752             : 
    5753          40 :                   ++cp;
    5754             :                 }
    5755             :             }
    5756             : 
    5757          66 :           if (likely (ptr_size == 4 || ptr_size == 8))
    5758             :             {
    5759          66 :               struct cieinfo *newp = alloca (sizeof (*newp));
    5760          66 :               newp->cie_offset = offset;
    5761          66 :               newp->augmentation = augmentation;
    5762          66 :               newp->fde_encoding = fde_encoding;
    5763          66 :               newp->lsda_encoding = lsda_encoding;
    5764          66 :               newp->address_size = ptr_size;
    5765          66 :               newp->code_alignment_factor = code_alignment_factor;
    5766          66 :               newp->data_alignment_factor = data_alignment_factor;
    5767          66 :               newp->next = cies;
    5768          66 :               cies = newp;
    5769             :             }
    5770             :         }
    5771             :       else
    5772             :         {
    5773             :           struct cieinfo *cie = cies;
    5774        5503 :           while (cie != NULL)
    5775       11006 :             if (is_eh_frame
    5776        5475 :                 ? ((Dwarf_Off) start - cie_id) == (Dwarf_Off) cie->cie_offset
    5777          28 :                 : cie_id == (Dwarf_Off) cie->cie_offset)
    5778             :               break;
    5779             :             else
    5780           0 :               cie = cie->next;
    5781        5503 :           if (unlikely (cie == NULL))
    5782             :             {
    5783           0 :               puts ("invalid CIE reference in FDE");
    5784           0 :               return;
    5785             :             }
    5786             : 
    5787             :           /* Initialize from CIE data.  */
    5788        5503 :           fde_encoding = cie->fde_encoding;
    5789        5503 :           lsda_encoding = cie->lsda_encoding;
    5790        5503 :           ptr_size = encoded_ptr_size (fde_encoding, cie->address_size);
    5791        5503 :           code_alignment_factor = cie->code_alignment_factor;
    5792        5503 :           data_alignment_factor = cie->data_alignment_factor;
    5793             : 
    5794        5503 :           const unsigned char *base = readp;
    5795             :           // XXX There are sometimes relocations for this value
    5796        5519 :           initial_location = read_addr_unaligned_inc (ptr_size, dbg, readp);
    5797        5503 :           Dwarf_Word address_range
    5798        5519 :             = read_addr_unaligned_inc (ptr_size, dbg, readp);
    5799             : 
    5800             :           /* pcrel for an FDE address is relative to the runtime
    5801             :              address of the start_address field itself.  Sign extend
    5802             :              if necessary to make sure the calculation is done on the
    5803             :              full 64 bit address even when initial_location only holds
    5804             :              the lower 32 bits.  */
    5805        5503 :           Dwarf_Addr pc_start = initial_location;
    5806        5503 :           if (ptr_size == 4)
    5807        5473 :             pc_start = (uint64_t) (int32_t) pc_start;
    5808        5503 :           if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
    5809       10938 :             pc_start += ((uint64_t) shdr->sh_addr
    5810        5469 :                          + (base - (const unsigned char *) data->d_buf)
    5811        5469 :                          - bias);
    5812             : 
    5813        5503 :           char *a = format_dwarf_addr (dwflmod, cie->address_size,
    5814             :                                        pc_start, initial_location);
    5815       11006 :           printf ("\n [%6tx] FDE length=%" PRIu64 " cie=[%6tx]\n"
    5816             :                   "   CIE_pointer:              %" PRIu64 "\n"
    5817             :                   "   initial_location:         %s",
    5818             :                   offset, (uint64_t) unit_length,
    5819             :                   cie->cie_offset, (uint64_t) cie_id, a);
    5820        5503 :           free (a);
    5821        5503 :           if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
    5822             :             {
    5823       10938 :               vma_base = (((uint64_t) shdr->sh_offset
    5824        5469 :                            + (base - (const unsigned char *) data->d_buf)
    5825        5469 :                            + (uint64_t) initial_location)
    5826             :                           & (ptr_size == 4
    5827             :                              ? UINT64_C (0xffffffff)
    5828        5469 :                              : UINT64_C (0xffffffffffffffff)));
    5829        5469 :               printf (gettext (" (offset: %#" PRIx64 ")"),
    5830             :                       (uint64_t) vma_base);
    5831             :             }
    5832             : 
    5833        5503 :           printf ("\n   address_range:            %#" PRIx64,
    5834             :                   (uint64_t) address_range);
    5835        5503 :           if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
    5836        5469 :             printf (gettext (" (end offset: %#" PRIx64 ")"),
    5837        5469 :                     ((uint64_t) vma_base + (uint64_t) address_range)
    5838             :                     & (ptr_size == 4
    5839             :                        ? UINT64_C (0xffffffff)
    5840        5469 :                        : UINT64_C (0xffffffffffffffff)));
    5841        5503 :           putchar ('\n');
    5842             : 
    5843        5503 :           if (cie->augmentation[0] == 'z')
    5844             :             {
    5845             :               unsigned int augmentationlen;
    5846        5469 :               if (cieend - readp < 1)
    5847             :                 goto invalid_data;
    5848        5469 :               get_uleb128 (augmentationlen, readp, cieend);
    5849             : 
    5850        5469 :               if (augmentationlen > (size_t) (cieend - readp))
    5851             :                 {
    5852           0 :                   error (0, 0, gettext ("invalid augmentation length"));
    5853           0 :                   readp = cieend;
    5854           0 :                   continue;
    5855             :                 }
    5856             : 
    5857        5469 :               if (augmentationlen > 0)
    5858             :                 {
    5859           0 :                   const char *hdr = "Augmentation data:";
    5860           0 :                   const char *cp = cie->augmentation + 1;
    5861           0 :                   unsigned int u = 0;
    5862           0 :                   while (*cp != '\0'
    5863           0 :                          && cp < cie->augmentation + augmentationlen + 1)
    5864             :                     {
    5865           0 :                       if (*cp == 'L')
    5866             :                         {
    5867             :                           uint64_t lsda_pointer;
    5868           0 :                           const unsigned char *p
    5869           0 :                             = read_encoded (lsda_encoding, &readp[u],
    5870             :                                             &readp[augmentationlen],
    5871             :                                             &lsda_pointer, dbg);
    5872           0 :                           u = p - readp;
    5873           0 :                           printf (gettext ("\
    5874             :    %-26sLSDA pointer: %#" PRIx64 "\n"),
    5875             :                                   hdr, lsda_pointer);
    5876           0 :                           hdr = "";
    5877             :                         }
    5878           0 :                       ++cp;
    5879             :                     }
    5880             : 
    5881           0 :                   while (u < augmentationlen)
    5882             :                     {
    5883           0 :                       printf ("   %-26s%#x\n", hdr, readp[u++]);
    5884           0 :                       hdr = "";
    5885             :                     }
    5886             :                 }
    5887             : 
    5888        5469 :               readp += augmentationlen;
    5889             :             }
    5890             :         }
    5891             : 
    5892             :       /* Handle the initialization instructions.  */
    5893        5569 :       if (ptr_size != 4 && ptr_size !=8)
    5894             :         printf ("invalid CIE pointer size (%u), must be 4 or 8.\n", ptr_size);
    5895             :       else
    5896        5569 :         print_cfa_program (readp, cieend, vma_base, code_alignment_factor,
    5897             :                            data_alignment_factor, version, ptr_size,
    5898             :                            fde_encoding, dwflmod, ebl, dbg);
    5899        5569 :       readp = cieend;
    5900             :     }
    5901             : }
    5902             : 
    5903             : 
    5904             : struct attrcb_args
    5905             : {
    5906             :   Dwfl_Module *dwflmod;
    5907             :   Dwarf *dbg;
    5908             :   Dwarf_Die *die;
    5909             :   int level;
    5910             :   bool silent;
    5911             :   unsigned int version;
    5912             :   unsigned int addrsize;
    5913             :   unsigned int offset_size;
    5914             :   struct Dwarf_CU *cu;
    5915             : };
    5916             : 
    5917             : 
    5918             : static int
    5919     2782169 : attr_callback (Dwarf_Attribute *attrp, void *arg)
    5920             : {
    5921     2782169 :   struct attrcb_args *cbargs = (struct attrcb_args *) arg;
    5922     2782169 :   const int level = cbargs->level;
    5923             : 
    5924     2782169 :   unsigned int attr = dwarf_whatattr (attrp);
    5925     2782169 :   if (unlikely (attr == 0))
    5926             :     {
    5927           0 :       if (!cbargs->silent)
    5928           0 :         error (0, 0, gettext ("cannot get attribute code: %s"),
    5929             :                dwarf_errmsg (-1));
    5930             :       return DWARF_CB_ABORT;
    5931             :     }
    5932             : 
    5933     2782169 :   unsigned int form = dwarf_whatform (attrp);
    5934     2782169 :   if (unlikely (form == 0))
    5935             :     {
    5936           0 :       if (!cbargs->silent)
    5937           0 :         error (0, 0, gettext ("cannot get attribute form: %s"),
    5938             :                dwarf_errmsg (-1));
    5939             :       return DWARF_CB_ABORT;
    5940             :     }
    5941             : 
    5942     2782169 :   switch (form)
    5943             :     {
    5944       42676 :     case DW_FORM_addr:
    5945       42676 :       if (!cbargs->silent)
    5946             :         {
    5947             :           Dwarf_Addr addr;
    5948       42624 :           if (unlikely (dwarf_formaddr (attrp, &addr) != 0))
    5949             :             {
    5950           0 :             attrval_out:
    5951           0 :               if (!cbargs->silent)
    5952           0 :                 error (0, 0, gettext ("cannot get attribute value: %s"),
    5953             :                        dwarf_errmsg (-1));
    5954           0 :               return DWARF_CB_ABORT;
    5955             :             }
    5956       42624 :           char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize,
    5957             :                                        addr, addr);
    5958       85248 :           printf ("           %*s%-20s (%s) %s\n",
    5959             :                   (int) (level * 2), "", dwarf_attr_name (attr),
    5960             :                   dwarf_form_name (form), a);
    5961       42624 :           free (a);
    5962             :         }
    5963     2491704 :       break;
    5964             : 
    5965      517346 :     case DW_FORM_indirect:
    5966             :     case DW_FORM_strp:
    5967             :     case DW_FORM_string:
    5968             :     case DW_FORM_GNU_strp_alt:
    5969      517346 :       if (cbargs->silent)
    5970             :         break;
    5971      517200 :       const char *str = dwarf_formstring (attrp);
    5972      517200 :       if (unlikely (str == NULL))
    5973             :         goto attrval_out;
    5974      517200 :       printf ("           %*s%-20s (%s) \"%s\"\n",
    5975             :               (int) (level * 2), "", dwarf_attr_name (attr),
    5976             :               dwarf_form_name (form), str);
    5977             :       break;
    5978             : 
    5979      664165 :     case DW_FORM_ref_addr:
    5980             :     case DW_FORM_ref_udata:
    5981             :     case DW_FORM_ref8:
    5982             :     case DW_FORM_ref4:
    5983             :     case DW_FORM_ref2:
    5984             :     case DW_FORM_ref1:
    5985             :     case DW_FORM_GNU_ref_alt:
    5986      664165 :       if (cbargs->silent)
    5987             :         break;
    5988             :       Dwarf_Die ref;
    5989      664031 :       if (unlikely (dwarf_formref_die (attrp, &ref) == NULL))
    5990             :         goto attrval_out;
    5991             : 
    5992      664031 :       printf ("           %*s%-20s (%s) [%6" PRIxMAX "]\n",
    5993             :               (int) (level * 2), "", dwarf_attr_name (attr),
    5994      664031 :               dwarf_form_name (form), (uintmax_t) dwarf_dieoffset (&ref));
    5995             :       break;
    5996             : 
    5997           0 :     case DW_FORM_ref_sig8:
    5998           0 :       if (cbargs->silent)
    5999             :         break;
    6000           0 :       printf ("           %*s%-20s (%s) {%6" PRIx64 "}\n",
    6001             :               (int) (level * 2), "", dwarf_attr_name (attr),
    6002             :               dwarf_form_name (form),
    6003           0 :               (uint64_t) read_8ubyte_unaligned (attrp->cu->dbg, attrp->valp));
    6004             :       break;
    6005             : 
    6006     1385560 :     case DW_FORM_sec_offset:
    6007             :     case DW_FORM_udata:
    6008             :     case DW_FORM_sdata:
    6009             :     case DW_FORM_data8:
    6010             :     case DW_FORM_data4:
    6011             :     case DW_FORM_data2:
    6012             :     case DW_FORM_data1:;
    6013             :       Dwarf_Word num;
    6014     1385560 :       if (unlikely (dwarf_formudata (attrp, &num) != 0))
    6015             :         goto attrval_out;
    6016             : 
    6017     1385560 :       const char *valuestr = NULL;
    6018     1385560 :       switch (attr)
    6019             :         {
    6020             :           /* This case can take either a constant or a loclistptr.  */
    6021      235488 :         case DW_AT_data_member_location:
    6022      235488 :           if (form != DW_FORM_sec_offset
    6023      235488 :               && (cbargs->version >= 4
    6024       23806 :                   || (form != DW_FORM_data4 && form != DW_FORM_data8)))
    6025             :             {
    6026      235488 :               if (!cbargs->silent)
    6027      235488 :                 printf ("           %*s%-20s (%s) %" PRIxMAX "\n",
    6028             :                         (int) (level * 2), "", dwarf_attr_name (attr),
    6029             :                         dwarf_form_name (form), (uintmax_t) num);
    6030             :               return DWARF_CB_OK;
    6031             :             }
    6032             :           /* else fallthrough */
    6033             : 
    6034             :         /* These cases always take a loclistptr and no constant. */
    6035             :         case DW_AT_location:
    6036             :         case DW_AT_data_location:
    6037             :         case DW_AT_vtable_elem_location:
    6038             :         case DW_AT_string_length:
    6039             :         case DW_AT_use_location:
    6040             :         case DW_AT_frame_base:
    6041             :         case DW_AT_return_addr:
    6042             :         case DW_AT_static_link:
    6043             :         case DW_AT_GNU_call_site_value:
    6044             :         case DW_AT_GNU_call_site_data_value:
    6045             :         case DW_AT_GNU_call_site_target:
    6046             :         case DW_AT_GNU_call_site_target_clobbered:
    6047          16 :           {
    6048      132309 :             bool nlpt = notice_listptr (section_loc, &known_loclistptr,
    6049       88206 :                                         cbargs->addrsize, cbargs->offset_size,
    6050             :                                         cbargs->cu, num);
    6051       44103 :             if (!cbargs->silent)
    6052       44087 :               printf ("           %*s%-20s (%s) location list [%6" PRIxMAX "]%s\n",
    6053             :                       (int) (level * 2), "", dwarf_attr_name (attr),
    6054             :                       dwarf_form_name (form), (uintmax_t) num,
    6055             :                       nlpt ? "" : " <WARNING offset too big>");
    6056             :           }
    6057             :           return DWARF_CB_OK;
    6058             : 
    6059       10874 :         case DW_AT_ranges:
    6060          10 :           {
    6061       32622 :             bool nlpt = notice_listptr (section_ranges, &known_rangelistptr,
    6062       21748 :                                         cbargs->addrsize, cbargs->offset_size,
    6063             :                                         cbargs->cu, num);
    6064       10874 :             if (!cbargs->silent)
    6065       10864 :               printf ("           %*s%-20s (%s) range list [%6" PRIxMAX "]%s\n",
    6066             :                       (int) (level * 2), "", dwarf_attr_name (attr),
    6067             :                       dwarf_form_name (form), (uintmax_t) num,
    6068             :                       nlpt ? "" : " <WARNING offset too big>");
    6069             :           }
    6070             :           return DWARF_CB_OK;
    6071             : 
    6072        1294 :         case DW_AT_language:
    6073        1294 :           valuestr = dwarf_lang_name (num);
    6074        1294 :           break;
    6075       18838 :         case DW_AT_encoding:
    6076       37676 :           valuestr = dwarf_encoding_name (num);
    6077       18838 :           break;
    6078           0 :         case DW_AT_accessibility:
    6079           0 :           valuestr = dwarf_access_name (num);
    6080           0 :           break;
    6081           0 :         case DW_AT_defaulted:
    6082           0 :           valuestr = dwarf_defaulted_name (num);
    6083           0 :           break;
    6084           0 :         case DW_AT_visibility:
    6085           0 :           valuestr = dwarf_visibility_name (num);
    6086           0 :           break;
    6087           0 :         case DW_AT_virtuality:
    6088           0 :           valuestr = dwarf_virtuality_name (num);
    6089           0 :           break;
    6090           0 :         case DW_AT_identifier_case:
    6091           0 :           valuestr = dwarf_identifier_case_name (num);
    6092           0 :           break;
    6093           0 :         case DW_AT_calling_convention:
    6094           0 :           valuestr = dwarf_calling_convention_name (num);
    6095           0 :           break;
    6096        2943 :         case DW_AT_inline:
    6097        5886 :           valuestr = dwarf_inline_name (num);
    6098        2943 :           break;
    6099           0 :         case DW_AT_ordering:
    6100           0 :           valuestr = dwarf_ordering_name (num);
    6101           0 :           break;
    6102           0 :         case DW_AT_discr_list:
    6103           0 :           valuestr = dwarf_discr_list_name (num);
    6104           0 :           break;
    6105             :         default:
    6106             :           /* Nothing.  */
    6107             :           break;
    6108             :         }
    6109             : 
    6110     1095095 :       if (cbargs->silent)
    6111             :         break;
    6112             : 
    6113             :       /* When highpc is in constant form it is relative to lowpc.
    6114             :          In that case also show the address.  */
    6115             :       Dwarf_Addr highpc;
    6116     1094794 :       if (attr == DW_AT_high_pc && dwarf_highpc (cbargs->die, &highpc) == 0)
    6117       15240 :         {
    6118       15240 :           char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize,
    6119             :                                        highpc, highpc);
    6120       30480 :           printf ("           %*s%-20s (%s) %" PRIuMAX " (%s)\n",
    6121             :                   (int) (level * 2), "", dwarf_attr_name (attr),
    6122             :                   dwarf_form_name (form), (uintmax_t) num, a);
    6123       15240 :           free (a);
    6124             :         }
    6125             :       else
    6126     1079554 :         {
    6127     1079554 :           Dwarf_Sword snum = 0;
    6128     1079554 :           if (form == DW_FORM_sdata)
    6129        1209 :             if (unlikely (dwarf_formsdata (attrp, &snum) != 0))
    6130             :               goto attrval_out;
    6131             : 
    6132     1079554 :           if (valuestr == NULL)
    6133             :             {
    6134     2113068 :               printf ("           %*s%-20s (%s)",
    6135             :                       (int) (level * 2), "", dwarf_attr_name (attr),
    6136             :                       dwarf_form_name (form));
    6137     1056534 :               if (form == DW_FORM_sdata)
    6138        1209 :                 printf (" %" PRIdMAX "\n", (intmax_t) snum);
    6139             :               else
    6140     1055325 :                 printf (" %" PRIuMAX "\n", (uintmax_t) num);
    6141             :             }
    6142             :           else
    6143             :             {
    6144       46040 :               printf ("           %*s%-20s (%s) %s",
    6145             :                       (int) (level * 2), "", dwarf_attr_name (attr),
    6146             :                       dwarf_form_name (form), valuestr);
    6147       23020 :               if (form == DW_FORM_sdata)
    6148           0 :                 printf (" (%" PRIdMAX ")\n", (intmax_t) snum);
    6149             :               else
    6150       23020 :                 printf (" (%" PRIuMAX ")\n", (uintmax_t) num);
    6151             :             }
    6152             :         }
    6153             :       break;
    6154             : 
    6155        9081 :     case DW_FORM_flag:
    6156        9081 :       if (cbargs->silent)
    6157             :         break;
    6158             :       bool flag;
    6159        9048 :       if (unlikely (dwarf_formflag (attrp, &flag) != 0))
    6160             :         goto attrval_out;
    6161             : 
    6162        9048 :       printf ("           %*s%-20s (%s) %s\n",
    6163             :               (int) (level * 2), "", dwarf_attr_name (attr),
    6164        9048 :               dwarf_form_name (form), flag ? gettext ("yes") : gettext ("no"));
    6165             :       break;
    6166             : 
    6167       72797 :     case DW_FORM_flag_present:
    6168       72797 :       if (cbargs->silent)
    6169             :         break;
    6170       72788 :       printf ("           %*s%-20s (%s) %s\n",
    6171             :               (int) (level * 2), "", dwarf_attr_name (attr),
    6172             :               dwarf_form_name (form), gettext ("yes"));
    6173             :       break;
    6174             : 
    6175       90544 :     case DW_FORM_exprloc:
    6176             :     case DW_FORM_block4:
    6177             :     case DW_FORM_block2:
    6178             :     case DW_FORM_block1:
    6179             :     case DW_FORM_block:
    6180       90544 :       if (cbargs->silent)
    6181             :         break;
    6182             :       Dwarf_Block block;
    6183       90508 :       if (unlikely (dwarf_formblock (attrp, &block) != 0))
    6184             :         goto attrval_out;
    6185             : 
    6186      181016 :       printf ("           %*s%-20s (%s) ",
    6187             :               (int) (level * 2), "", dwarf_attr_name (attr),
    6188             :               dwarf_form_name (form));
    6189             : 
    6190       90508 :       switch (attr)
    6191             :         {
    6192          16 :         default:
    6193          16 :           if (form != DW_FORM_exprloc)
    6194             :             {
    6195          16 :               print_block (block.length, block.data);
    6196          16 :               break;
    6197             :             }
    6198             :           /* Fall through.  */
    6199             : 
    6200             :         case DW_AT_location:
    6201             :         case DW_AT_data_location:
    6202             :         case DW_AT_data_member_location:
    6203             :         case DW_AT_vtable_elem_location:
    6204             :         case DW_AT_string_length:
    6205             :         case DW_AT_use_location:
    6206             :         case DW_AT_frame_base:
    6207             :         case DW_AT_return_addr:
    6208             :         case DW_AT_static_link:
    6209             :         case DW_AT_allocated:
    6210             :         case DW_AT_associated:
    6211             :         case DW_AT_bit_size:
    6212             :         case DW_AT_bit_offset:
    6213             :         case DW_AT_bit_stride:
    6214             :         case DW_AT_byte_size:
    6215             :         case DW_AT_byte_stride:
    6216             :         case DW_AT_count:
    6217             :         case DW_AT_lower_bound:
    6218             :         case DW_AT_upper_bound:
    6219             :         case DW_AT_GNU_call_site_value:
    6220             :         case DW_AT_GNU_call_site_data_value:
    6221             :         case DW_AT_GNU_call_site_target:
    6222             :         case DW_AT_GNU_call_site_target_clobbered:
    6223       90492 :           putchar ('\n');
    6224      180984 :           print_ops (cbargs->dwflmod, cbargs->dbg,
    6225       90492 :                      12 + level * 2, 12 + level * 2,
    6226             :                      cbargs->version, cbargs->addrsize, cbargs->offset_size,
    6227       90492 :                      attrp->cu, block.length, block.data);
    6228       90492 :           break;
    6229             :         }
    6230             :       break;
    6231             : 
    6232           0 :     default:
    6233           0 :       if (cbargs->silent)
    6234             :         break;
    6235           0 :       printf ("           %*s%-20s (form: %#x) ???\n",
    6236             :               (int) (level * 2), "", dwarf_attr_name (attr),
    6237             :               (int) form);
    6238             :       break;
    6239             :     }
    6240             : 
    6241     2491704 :   return DWARF_CB_OK;
    6242             : }
    6243             : 
    6244             : static void
    6245          54 : print_debug_units (Dwfl_Module *dwflmod,
    6246             :                    Ebl *ebl, GElf_Ehdr *ehdr,
    6247             :                    Elf_Scn *scn, GElf_Shdr *shdr,
    6248             :                    Dwarf *dbg, bool debug_types)
    6249             : {
    6250          54 :   const bool silent = !(print_debug_sections & section_info);
    6251         108 :   const char *secname = section_name (ebl, ehdr, shdr);
    6252             : 
    6253          54 :   if (!silent)
    6254          44 :     printf (gettext ("\
    6255             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n [Offset]\n"),
    6256          44 :             elf_ndxscn (scn), secname, (uint64_t) shdr->sh_offset);
    6257             : 
    6258             :   /* If the section is empty we don't have to do anything.  */
    6259          54 :   if (!silent && shdr->sh_size == 0)
    6260           0 :     return;
    6261             : 
    6262          54 :   int maxdies = 20;
    6263          54 :   Dwarf_Die *dies = (Dwarf_Die *) xmalloc (maxdies * sizeof (Dwarf_Die));
    6264             : 
    6265          54 :   Dwarf_Off offset = 0;
    6266             : 
    6267             :   /* New compilation unit.  */
    6268             :   size_t cuhl;
    6269             :   Dwarf_Half version;
    6270             :   Dwarf_Off abbroffset;
    6271             :   uint8_t addrsize;
    6272             :   uint8_t offsize;
    6273             :   Dwarf_Off nextcu;
    6274             :   uint64_t typesig;
    6275             :   Dwarf_Off typeoff;
    6276        2642 :  next_cu:
    6277        1348 :   if (dwarf_next_unit (dbg, offset, &nextcu, &cuhl, &version,
    6278             :                        &abbroffset, &addrsize, &offsize,
    6279             :                        debug_types ? &typesig : NULL,
    6280             :                        debug_types ? &typeoff : NULL) != 0)
    6281             :     goto do_return;
    6282             : 
    6283        1294 :   if (!silent)
    6284             :     {
    6285        1281 :       if (debug_types)
    6286           0 :         printf (gettext (" Type unit at offset %" PRIu64 ":\n"
    6287             :                          " Version: %" PRIu16 ", Abbreviation section offset: %"
    6288             :                          PRIu64 ", Address size: %" PRIu8
    6289             :                          ", Offset size: %" PRIu8
    6290             :                          "\n Type signature: %#" PRIx64
    6291             :                          ", Type offset: %#" PRIx64 "\n"),
    6292             :                 (uint64_t) offset, version, abbroffset, addrsize, offsize,
    6293             :                 typesig, (uint64_t) typeoff);
    6294             :       else
    6295        1281 :         printf (gettext (" Compilation unit at offset %" PRIu64 ":\n"
    6296             :                          " Version: %" PRIu16 ", Abbreviation section offset: %"
    6297             :                          PRIu64 ", Address size: %" PRIu8
    6298             :                          ", Offset size: %" PRIu8 "\n"),
    6299             :                 (uint64_t) offset, version, abbroffset, addrsize, offsize);
    6300             :     }
    6301             : 
    6302        1294 :   struct attrcb_args args =
    6303             :     {
    6304             :       .dwflmod = dwflmod,
    6305             :       .dbg = dbg,
    6306             :       .silent = silent,
    6307             :       .version = version,
    6308             :       .addrsize = addrsize,
    6309             :       .offset_size = offsize
    6310             :     };
    6311             : 
    6312        1294 :   offset += cuhl;
    6313             : 
    6314        1294 :   int level = 0;
    6315             : 
    6316        1294 :   if (unlikely ((debug_types ? dwarf_offdie_types : dwarf_offdie)
    6317             :                 (dbg, offset, &dies[level]) == NULL))
    6318             :     {
    6319           0 :       if (!silent)
    6320           0 :         error (0, 0, gettext ("cannot get DIE at offset %" PRIu64
    6321             :                               " in section '%s': %s"),
    6322             :                (uint64_t) offset, secname, dwarf_errmsg (-1));
    6323             :       goto do_return;
    6324             :     }
    6325             : 
    6326        1294 :   args.cu = dies[0].cu;
    6327             : 
    6328             :   do
    6329             :     {
    6330      794470 :       offset = dwarf_dieoffset (&dies[level]);
    6331      794470 :       if (unlikely (offset == ~0ul))
    6332             :         {
    6333           0 :           if (!silent)
    6334           0 :             error (0, 0, gettext ("cannot get DIE offset: %s"),
    6335             :                    dwarf_errmsg (-1));
    6336             :           goto do_return;
    6337             :         }
    6338             : 
    6339      794470 :       int tag = dwarf_tag (&dies[level]);
    6340      794470 :       if (unlikely (tag == DW_TAG_invalid))
    6341             :         {
    6342           0 :           if (!silent)
    6343           0 :             error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64
    6344             :                                   " in section '%s': %s"),
    6345             :                    (uint64_t) offset, secname, dwarf_errmsg (-1));
    6346             :           goto do_return;
    6347             :         }
    6348             : 
    6349      794470 :       if (!silent)
    6350      794309 :         printf (" [%6" PRIx64 "]  %*s%s\n",
    6351             :                 (uint64_t) offset, (int) (level * 2), "",
    6352             :                 dwarf_tag_name (tag));
    6353             : 
    6354             :       /* Print the attribute values.  */
    6355      794470 :       args.level = level;
    6356      794470 :       args.die = &dies[level];
    6357      794470 :       (void) dwarf_getattrs (&dies[level], attr_callback, &args, 0);
    6358             : 
    6359             :       /* Make room for the next level's DIE.  */
    6360      794470 :       if (level + 1 == maxdies)
    6361           0 :         dies = (Dwarf_Die *) xrealloc (dies,
    6362           0 :                                        (maxdies += 10)
    6363             :                                        * sizeof (Dwarf_Die));
    6364             : 
    6365      794470 :       int res = dwarf_child (&dies[level], &dies[level + 1]);
    6366      794470 :       if (res > 0)
    6367             :         {
    6368      794470 :           while ((res = dwarf_siblingof (&dies[level], &dies[level])) == 1)
    6369      112632 :             if (level-- == 0)
    6370             :               break;
    6371             : 
    6372      683132 :           if (unlikely (res == -1))
    6373             :             {
    6374           0 :               if (!silent)
    6375           0 :                 error (0, 0, gettext ("cannot get next DIE: %s\n"),
    6376             :                        dwarf_errmsg (-1));
    6377             :               goto do_return;
    6378             :             }
    6379             :         }
    6380      111338 :       else if (unlikely (res < 0))
    6381             :         {
    6382           0 :           if (!silent)
    6383           0 :             error (0, 0, gettext ("cannot get next DIE: %s"),
    6384             :                    dwarf_errmsg (-1));
    6385             :           goto do_return;
    6386             :         }
    6387             :       else
    6388             :         ++level;
    6389             :     }
    6390      794470 :   while (level >= 0);
    6391             : 
    6392        1294 :   offset = nextcu;
    6393        1294 :   if (offset != 0)
    6394             :      goto next_cu;
    6395             : 
    6396          54 :  do_return:
    6397          54 :   free (dies);
    6398             : }
    6399             : 
    6400             : static void
    6401          54 : print_debug_info_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
    6402             :                           Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    6403             : {
    6404          54 :   print_debug_units (dwflmod, ebl, ehdr, scn, shdr, dbg, false);
    6405          54 : }
    6406             : 
    6407             : static void
    6408           0 : print_debug_types_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
    6409             :                            Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    6410             : {
    6411           0 :   print_debug_units (dwflmod, ebl, ehdr, scn, shdr, dbg, true);
    6412           0 : }
    6413             : 
    6414             : 
    6415             : static void
    6416           1 : print_decoded_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
    6417             :                             Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    6418             : {
    6419           3 :   printf (gettext ("\
    6420             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n\n"),
    6421             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    6422           1 :           (uint64_t) shdr->sh_offset);
    6423             : 
    6424           1 :   size_t address_size
    6425           1 :     = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8;
    6426             : 
    6427             :   Dwarf_Off cuoffset;
    6428           1 :   Dwarf_Off ncuoffset = 0;
    6429             :   size_t hsize;
    6430           5 :   while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize,
    6431             :                        NULL, NULL, NULL) == 0)
    6432             :     {
    6433             :       Dwarf_Die cudie;
    6434           3 :       if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL)
    6435           0 :         continue;
    6436             : 
    6437             :       size_t nlines;
    6438             :       Dwarf_Lines *lines;
    6439           3 :       if (dwarf_getsrclines (&cudie, &lines, &nlines) != 0)
    6440           0 :         continue;
    6441             : 
    6442           6 :       printf (" CU [%" PRIx64 "] %s\n",
    6443             :               dwarf_dieoffset (&cudie), dwarf_diename (&cudie));
    6444           3 :       printf ("  line:col SBPE* disc isa op address"
    6445             :               " (Statement Block Prologue Epilogue *End)\n");
    6446           3 :       const char *last_file = "";
    6447          42 :       for (size_t n = 0; n < nlines; n++)
    6448             :         {
    6449          39 :           Dwarf_Line *line = dwarf_onesrcline (lines, n);
    6450          39 :           if (line == NULL)
    6451             :             {
    6452           0 :               printf ("  dwarf_onesrcline: %s\n", dwarf_errmsg (-1));
    6453           0 :               continue;
    6454             :             }
    6455             :           Dwarf_Word mtime, length;
    6456          39 :           const char *file = dwarf_linesrc (line, &mtime, &length);
    6457          39 :           if (file == NULL)
    6458             :             {
    6459           0 :               printf ("  <%s> (mtime: ?, length: ?)\n", dwarf_errmsg (-1));
    6460           0 :               last_file = "";
    6461             :             }
    6462          39 :           else if (strcmp (last_file, file) != 0)
    6463             :             {
    6464           6 :               printf ("  %s (mtime: %" PRIu64 ", length: %" PRIu64 ")\n",
    6465             :                       file, mtime, length);
    6466           3 :               last_file = file;
    6467             :             }
    6468             : 
    6469             :           int lineno, colno;
    6470             :           bool statement, endseq, block, prologue_end, epilogue_begin;
    6471             :           unsigned int lineop, isa, disc;
    6472             :           Dwarf_Addr address;
    6473          39 :           dwarf_lineaddr (line, &address);
    6474          39 :           dwarf_lineno (line, &lineno);
    6475          39 :           dwarf_linecol (line, &colno);
    6476          39 :           dwarf_lineop_index (line, &lineop);
    6477          39 :           dwarf_linebeginstatement (line, &statement);
    6478          39 :           dwarf_lineendsequence (line, &endseq);
    6479          39 :           dwarf_lineblock (line, &block);
    6480          39 :           dwarf_lineprologueend (line, &prologue_end);
    6481          39 :           dwarf_lineepiloguebegin (line, &epilogue_begin);
    6482          39 :           dwarf_lineisa (line, &isa);
    6483          39 :           dwarf_linediscriminator (line, &disc);
    6484             : 
    6485             :           /* End sequence is special, it is one byte past.  */
    6486          78 :           char *a = format_dwarf_addr (dwflmod, address_size,
    6487          39 :                                        address - (endseq ? 1 : 0), address);
    6488         273 :           printf ("  %4d:%-3d %c%c%c%c%c %4d %3d %2d %s\n",
    6489             :                   lineno, colno,
    6490          39 :                   (statement ? 'S' : ' '),
    6491          39 :                   (block ? 'B' : ' '),
    6492          39 :                   (prologue_end ? 'P' : ' '),
    6493          39 :                   (epilogue_begin ? 'E' : ' '),
    6494          39 :                   (endseq ? '*' : ' '),
    6495             :                   disc, isa, lineop, a);
    6496          39 :           free (a);
    6497             : 
    6498          39 :           if (endseq)
    6499             :             printf("\n");
    6500             :         }
    6501             :     }
    6502           1 : }
    6503             : 
    6504             : 
    6505             : static void
    6506          38 : print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
    6507             :                           Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    6508             : {
    6509          38 :   if (decodedline)
    6510             :     {
    6511           1 :       print_decoded_line_section (dwflmod, ebl, ehdr, scn, shdr, dbg);
    6512           1 :       return;
    6513             :     }
    6514             : 
    6515         111 :   printf (gettext ("\
    6516             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
    6517             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    6518          37 :           (uint64_t) shdr->sh_offset);
    6519             : 
    6520          37 :   if (shdr->sh_size == 0)
    6521             :     return;
    6522             : 
    6523             :   /* There is no functionality in libdw to read the information in the
    6524             :      way it is represented here.  Hardcode the decoder.  */
    6525          37 :   Elf_Data *data = dbg->sectiondata[IDX_debug_line];
    6526          37 :   if (unlikely (data == NULL || data->d_buf == NULL))
    6527             :     {
    6528           0 :       error (0, 0, gettext ("cannot get line data section data: %s"),
    6529             :              elf_errmsg (-1));
    6530             :       return;
    6531             :     }
    6532             : 
    6533          37 :   const unsigned char *linep = (const unsigned char *) data->d_buf;
    6534             :   const unsigned char *lineendp;
    6535             : 
    6536        1350 :   while (linep
    6537        1313 :          < (lineendp = (const unsigned char *) data->d_buf + data->d_size))
    6538             :     {
    6539        1276 :       size_t start_offset = linep - (const unsigned char *) data->d_buf;
    6540             : 
    6541        2552 :       printf (gettext ("\nTable at offset %zu:\n"), start_offset);
    6542             : 
    6543        1276 :       if (unlikely (linep + 4 > lineendp))
    6544             :         goto invalid_data;
    6545        1294 :       Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
    6546        1276 :       unsigned int length = 4;
    6547        1276 :       if (unlikely (unit_length == 0xffffffff))
    6548             :         {
    6549           0 :           if (unlikely (linep + 8 > lineendp))
    6550             :             {
    6551           0 :             invalid_data:
    6552           0 :               error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
    6553             :                      elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
    6554           0 :               return;
    6555             :             }
    6556           0 :           unit_length = read_8ubyte_unaligned_inc (dbg, linep);
    6557           0 :           length = 8;
    6558             :         }
    6559             : 
    6560             :       /* Check whether we have enough room in the section.  */
    6561        2552 :       if (unlikely (unit_length > (size_t) (lineendp - linep)
    6562             :           || unit_length < 2 + length + 5 * 1))
    6563             :         goto invalid_data;
    6564        1276 :       lineendp = linep + unit_length;
    6565             : 
    6566             :       /* The next element of the header is the version identifier.  */
    6567        1276 :       uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
    6568             : 
    6569             :       /* Next comes the header length.  */
    6570             :       Dwarf_Word header_length;
    6571        1276 :       if (length == 4)
    6572        1294 :         header_length = read_4ubyte_unaligned_inc (dbg, linep);
    6573             :       else
    6574           0 :         header_length = read_8ubyte_unaligned_inc (dbg, linep);
    6575             :       //const unsigned char *header_start = linep;
    6576             : 
    6577             :       /* Next the minimum instruction length.  */
    6578        1276 :       uint_fast8_t minimum_instr_len = *linep++;
    6579             : 
    6580             :       /* Next the maximum operations per instruction, in version 4 format.  */
    6581        1276 :       uint_fast8_t max_ops_per_instr = version < 4 ? 1 : *linep++;
    6582             : 
    6583             :         /* Then the flag determining the default value of the is_stmt
    6584             :            register.  */
    6585        1276 :       uint_fast8_t default_is_stmt = *linep++;
    6586             : 
    6587             :       /* Now the line base.  */
    6588        1276 :       int_fast8_t line_base = *((const int_fast8_t *) linep);
    6589        1276 :       ++linep;
    6590             : 
    6591             :       /* And the line range.  */
    6592        1276 :       uint_fast8_t line_range = *linep++;
    6593             : 
    6594             :       /* The opcode base.  */
    6595        1276 :       uint_fast8_t opcode_base = *linep++;
    6596             : 
    6597             :       /* Print what we got so far.  */
    6598        2552 :       printf (gettext ("\n"
    6599             :                        " Length:                     %" PRIu64 "\n"
    6600             :                        " DWARF version:              %" PRIuFAST16 "\n"
    6601             :                        " Prologue length:            %" PRIu64 "\n"
    6602             :                        " Minimum instruction length: %" PRIuFAST8 "\n"
    6603             :                        " Maximum operations per instruction: %" PRIuFAST8 "\n"
    6604             :                        " Initial value if '%s': %" PRIuFAST8 "\n"
    6605             :                        " Line base:                  %" PRIdFAST8 "\n"
    6606             :                        " Line range:                 %" PRIuFAST8 "\n"
    6607             :                        " Opcode base:                %" PRIuFAST8 "\n"
    6608             :                        "\n"
    6609             :                        "Opcodes:\n"),
    6610             :               (uint64_t) unit_length, version, (uint64_t) header_length,
    6611             :               minimum_instr_len, max_ops_per_instr,
    6612             :               "is_stmt", default_is_stmt, line_base,
    6613             :               line_range, opcode_base);
    6614             : 
    6615        1276 :       if (unlikely (linep + opcode_base - 1 >= lineendp))
    6616             :         {
    6617           0 :         invalid_unit:
    6618           0 :           error (0, 0,
    6619           0 :                  gettext ("invalid data at offset %tu in section [%zu] '%s'"),
    6620           0 :                  linep - (const unsigned char *) data->d_buf,
    6621             :                  elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
    6622           0 :           linep = lineendp;
    6623           0 :           continue;
    6624             :         }
    6625        1276 :       int opcode_base_l10 = 1;
    6626        1276 :       unsigned int tmp = opcode_base;
    6627        3826 :       while (tmp > 10)
    6628             :         {
    6629        1274 :           tmp /= 10;
    6630        1274 :           ++opcode_base_l10;
    6631             :         }
    6632        1276 :       const uint8_t *standard_opcode_lengths = linep - 1;
    6633       16582 :       for (uint_fast8_t cnt = 1; cnt < opcode_base; ++cnt)
    6634       30612 :         printf (ngettext ("  [%*" PRIuFAST8 "]  %hhu argument\n",
    6635             :                           "  [%*" PRIuFAST8 "]  %hhu arguments\n",
    6636             :                           (int) linep[cnt - 1]),
    6637       15306 :                 opcode_base_l10, cnt, linep[cnt - 1]);
    6638        1276 :       linep += opcode_base - 1;
    6639        1276 :       if (unlikely (linep >= lineendp))
    6640             :         goto invalid_unit;
    6641             : 
    6642        1276 :       puts (gettext ("\nDirectory table:"));
    6643       10824 :       while (*linep != 0)
    6644             :         {
    6645        8272 :           unsigned char *endp = memchr (linep, '\0', lineendp - linep);
    6646        8272 :           if (unlikely (endp == NULL))
    6647             :             goto invalid_unit;
    6648             : 
    6649       16544 :           printf (" %s\n", (char *) linep);
    6650             : 
    6651        8272 :           linep = endp + 1;
    6652             :         }
    6653             :       /* Skip the final NUL byte.  */
    6654        1276 :       ++linep;
    6655             : 
    6656        1276 :       if (unlikely (linep >= lineendp))
    6657             :         goto invalid_unit;
    6658        1276 :       puts (gettext ("\nFile name table:\n"
    6659             :                      " Entry Dir   Time      Size      Name"));
    6660       23377 :       for (unsigned int cnt = 1; *linep != 0; ++cnt)
    6661             :         {
    6662             :           /* First comes the file name.  */
    6663       22101 :           char *fname = (char *) linep;
    6664       22101 :           unsigned char *endp = memchr (fname, '\0', lineendp - linep);
    6665       22101 :           if (unlikely (endp == NULL))
    6666             :             goto invalid_unit;
    6667       22101 :           linep = endp + 1;
    6668             : 
    6669             :           /* Then the index.  */
    6670             :           unsigned int diridx;
    6671       22101 :           if (lineendp - linep < 1)
    6672             :             goto invalid_unit;
    6673       22101 :           get_uleb128 (diridx, linep, lineendp);
    6674             : 
    6675             :           /* Next comes the modification time.  */
    6676             :           unsigned int mtime;
    6677       22101 :           if (lineendp - linep < 1)
    6678             :             goto invalid_unit;
    6679       22101 :           get_uleb128 (mtime, linep, lineendp);
    6680             : 
    6681             :           /* Finally the length of the file.  */
    6682             :           unsigned int fsize;
    6683       22101 :           if (lineendp - linep < 1)
    6684             :             goto invalid_unit;
    6685       22101 :           get_uleb128 (fsize, linep, lineendp);
    6686             : 
    6687       22101 :           printf (" %-5u %-5u %-9u %-9u %s\n",
    6688             :                   cnt, diridx, mtime, fsize, fname);
    6689             :         }
    6690             :       /* Skip the final NUL byte.  */
    6691        1276 :       ++linep;
    6692             : 
    6693        1276 :       puts (gettext ("\nLine number statements:"));
    6694             :       Dwarf_Word address = 0;
    6695             :       unsigned int op_index = 0;
    6696        1276 :       size_t line = 1;
    6697        1276 :       uint_fast8_t is_stmt = default_is_stmt;
    6698             : 
    6699             :       /* Default address value, in case we do not find the CU.  */
    6700        1276 :       size_t address_size
    6701        1276 :         = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8;
    6702             : 
    6703             :       /* Determine the CU this block is for.  */
    6704             :       Dwarf_Off cuoffset;
    6705        1276 :       Dwarf_Off ncuoffset = 0;
    6706             :       size_t hsize;
    6707       95842 :       while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize,
    6708             :                            NULL, NULL, NULL) == 0)
    6709             :         {
    6710             :           Dwarf_Die cudie;
    6711       94566 :           if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL)
    6712           0 :             continue;
    6713             :           Dwarf_Attribute stmt_list;
    6714       94566 :           if (dwarf_attr (&cudie, DW_AT_stmt_list, &stmt_list) == NULL)
    6715           0 :             continue;
    6716             :           Dwarf_Word lineoff;
    6717       94566 :           if (dwarf_formudata (&stmt_list, &lineoff) != 0)
    6718           0 :             continue;
    6719       94566 :           if (lineoff == start_offset)
    6720             :             {
    6721             :               /* Found the CU.  */
    6722        1276 :               address_size = cudie.cu->address_size;
    6723        1276 :               break;
    6724             :             }
    6725             :         }
    6726             : 
    6727             :       /* Apply the "operation advance" from a special opcode
    6728             :          or DW_LNS_advance_pc (as per DWARF4 6.2.5.1).  */
    6729             :       unsigned int op_addr_advance;
    6730             :       bool show_op_index;
    6731             :       inline void advance_pc (unsigned int op_advance)
    6732             :       {
    6733      319556 :         op_addr_advance = minimum_instr_len * ((op_index + op_advance)
    6734      159778 :                                                / max_ops_per_instr);
    6735      159778 :         address += op_advance;
    6736      319556 :         show_op_index = (op_index > 0 ||
    6737      159778 :                          (op_index + op_advance) % max_ops_per_instr > 0);
    6738      159778 :         op_index = (op_index + op_advance) % max_ops_per_instr;
    6739             :       }
    6740             : 
    6741        1276 :       if (max_ops_per_instr == 0)
    6742             :         {
    6743           0 :           error (0, 0,
    6744           0 :                  gettext ("invalid maximum operations per instruction is zero"));
    6745           0 :           linep = lineendp;
    6746           0 :           continue;
    6747             :         }
    6748             : 
    6749      258877 :       while (linep < lineendp)
    6750             :         {
    6751      257601 :           size_t offset = linep - (const unsigned char *) data->d_buf;
    6752             :           unsigned int u128;
    6753             :           int s128;
    6754             : 
    6755             :           /* Read the opcode.  */
    6756      257601 :           unsigned int opcode = *linep++;
    6757             : 
    6758      257601 :           printf (" [%6" PRIx64 "]", (uint64_t)offset);
    6759             :           /* Is this a special opcode?  */
    6760      257601 :           if (likely (opcode >= opcode_base))
    6761             :             {
    6762      118654 :               if (unlikely (line_range == 0))
    6763             :                 goto invalid_unit;
    6764             : 
    6765             :               /* Yes.  Handling this is quite easy since the opcode value
    6766             :                  is computed with
    6767             : 
    6768             :                  opcode = (desired line increment - line_base)
    6769             :                            + (line_range * address advance) + opcode_base
    6770             :               */
    6771      118654 :               int line_increment = (line_base
    6772      118654 :                                     + (opcode - opcode_base) % line_range);
    6773             : 
    6774             :               /* Perform the increments.  */
    6775      118654 :               line += line_increment;
    6776      237308 :               advance_pc ((opcode - opcode_base) / line_range);
    6777             : 
    6778      118654 :               char *a = format_dwarf_addr (dwflmod, 0, address, address);
    6779      118654 :               if (show_op_index)
    6780           0 :                 printf (gettext ("\
    6781             :  special opcode %u: address+%u = %s, op_index = %u, line%+d = %zu\n"),
    6782             :                         opcode, op_addr_advance, a, op_index,
    6783             :                         line_increment, line);
    6784             :               else
    6785      118654 :                 printf (gettext ("\
    6786             :  special opcode %u: address+%u = %s, line%+d = %zu\n"),
    6787             :                         opcode, op_addr_advance, a, line_increment, line);
    6788      118654 :               free (a);
    6789             :             }
    6790      138947 :           else if (opcode == 0)
    6791             :             {
    6792             :               /* This an extended opcode.  */
    6793       14604 :               if (unlikely (linep + 2 > lineendp))
    6794             :                 goto invalid_unit;
    6795             : 
    6796             :               /* The length.  */
    6797       14604 :               unsigned int len = *linep++;
    6798             : 
    6799       14604 :               if (unlikely (linep + len > lineendp))
    6800             :                 goto invalid_unit;
    6801             : 
    6802             :               /* The sub-opcode.  */
    6803       14604 :               opcode = *linep++;
    6804             : 
    6805       29208 :               printf (gettext (" extended opcode %u: "), opcode);
    6806             : 
    6807       14604 :               switch (opcode)
    6808             :                 {
    6809        1311 :                 case DW_LNE_end_sequence:
    6810        1311 :                   puts (gettext (" end of sequence"));
    6811             : 
    6812             :                   /* Reset the registers we care about.  */
    6813             :                   address = 0;
    6814             :                   op_index = 0;
    6815        1311 :                   line = 1;
    6816        1311 :                   is_stmt = default_is_stmt;
    6817        1311 :                   break;
    6818             : 
    6819        1331 :                 case DW_LNE_set_address:
    6820             :                   op_index = 0;
    6821        1331 :                   if (unlikely ((size_t) (lineendp - linep) < address_size))
    6822             :                     goto invalid_unit;
    6823        1331 :                   if (address_size == 4)
    6824          17 :                     address = read_4ubyte_unaligned_inc (dbg, linep);
    6825             :                   else
    6826        1326 :                     address = read_8ubyte_unaligned_inc (dbg, linep);
    6827             :                   {
    6828        1331 :                     char *a = format_dwarf_addr (dwflmod, 0, address, address);
    6829        2662 :                     printf (gettext (" set address to %s\n"), a);
    6830        1331 :                     free (a);
    6831             :                   }
    6832        1331 :                   break;
    6833             : 
    6834           0 :                 case DW_LNE_define_file:
    6835             :                   {
    6836           0 :                     char *fname = (char *) linep;
    6837           0 :                     unsigned char *endp = memchr (linep, '\0',
    6838           0 :                                                   lineendp - linep);
    6839           0 :                     if (unlikely (endp == NULL))
    6840             :                       goto invalid_unit;
    6841           0 :                     linep = endp + 1;
    6842             : 
    6843             :                     unsigned int diridx;
    6844           0 :                     if (lineendp - linep < 1)
    6845             :                       goto invalid_unit;
    6846           0 :                     get_uleb128 (diridx, linep, lineendp);
    6847             :                     Dwarf_Word mtime;
    6848           0 :                     if (lineendp - linep < 1)
    6849             :                       goto invalid_unit;
    6850           0 :                     get_uleb128 (mtime, linep, lineendp);
    6851             :                     Dwarf_Word filelength;
    6852           0 :                     if (lineendp - linep < 1)
    6853             :                       goto invalid_unit;
    6854           0 :                     get_uleb128 (filelength, linep, lineendp);
    6855             : 
    6856           0 :                     printf (gettext ("\
    6857             :  define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
    6858             :                             diridx, (uint64_t) mtime, (uint64_t) filelength,
    6859             :                             fname);
    6860             :                   }
    6861             :                   break;
    6862             : 
    6863       11962 :                 case DW_LNE_set_discriminator:
    6864             :                   /* Takes one ULEB128 parameter, the discriminator.  */
    6865       11962 :                   if (unlikely (standard_opcode_lengths[opcode] != 1))
    6866             :                     goto invalid_unit;
    6867             : 
    6868       11962 :                   get_uleb128 (u128, linep, lineendp);
    6869       11962 :                   printf (gettext (" set discriminator to %u\n"), u128);
    6870             :                   break;
    6871             : 
    6872           0 :                 default:
    6873             :                   /* Unknown, ignore it.  */
    6874           0 :                   puts (gettext (" unknown opcode"));
    6875           0 :                   linep += len - 1;
    6876           0 :                   break;
    6877             :                 }
    6878             :             }
    6879      124343 :           else if (opcode <= DW_LNS_set_isa)
    6880             :             {
    6881             :               /* This is a known standard opcode.  */
    6882      124343 :               switch (opcode)
    6883             :                 {
    6884        8731 :                 case DW_LNS_copy:
    6885             :                   /* Takes no argument.  */
    6886        8731 :                   puts (gettext (" copy"));
    6887        8731 :                   break;
    6888             : 
    6889       12660 :                 case DW_LNS_advance_pc:
    6890             :                   /* Takes one uleb128 parameter which is added to the
    6891             :                      address.  */
    6892       12660 :                   get_uleb128 (u128, linep, lineendp);
    6893       12660 :                   advance_pc (u128);
    6894             :                   {
    6895       12660 :                     char *a = format_dwarf_addr (dwflmod, 0, address, address);
    6896       12660 :                     if (show_op_index)
    6897           0 :                       printf (gettext ("\
    6898             :  advance address by %u to %s, op_index to %u\n"),
    6899             :                               op_addr_advance, a, op_index);
    6900             :                     else
    6901       12660 :                       printf (gettext (" advance address by %u to %s\n"),
    6902             :                               op_addr_advance, a);
    6903       12660 :                     free (a);
    6904             :                   }
    6905       12660 :                   break;
    6906             : 
    6907       50744 :                 case DW_LNS_advance_line:
    6908             :                   /* Takes one sleb128 parameter which is added to the
    6909             :                      line.  */
    6910       50744 :                   get_sleb128 (s128, linep, lineendp);
    6911       50744 :                   line += s128;
    6912       50744 :                   printf (gettext ("\
    6913             :  advance line by constant %d to %" PRId64 "\n"),
    6914             :                           s128, (int64_t) line);
    6915             :                   break;
    6916             : 
    6917       18920 :                 case DW_LNS_set_file:
    6918             :                   /* Takes one uleb128 parameter which is stored in file.  */
    6919       18920 :                   get_uleb128 (u128, linep, lineendp);
    6920       18920 :                   printf (gettext (" set file to %" PRIu64 "\n"),
    6921             :                           (uint64_t) u128);
    6922             :                   break;
    6923             : 
    6924           0 :                 case DW_LNS_set_column:
    6925             :                   /* Takes one uleb128 parameter which is stored in column.  */
    6926           0 :                   if (unlikely (standard_opcode_lengths[opcode] != 1))
    6927             :                     goto invalid_unit;
    6928             : 
    6929           0 :                   get_uleb128 (u128, linep, lineendp);
    6930           0 :                   printf (gettext (" set column to %" PRIu64 "\n"),
    6931             :                           (uint64_t) u128);
    6932             :                   break;
    6933             : 
    6934        4824 :                 case DW_LNS_negate_stmt:
    6935             :                   /* Takes no argument.  */
    6936        4824 :                   is_stmt = 1 - is_stmt;
    6937        4824 :                   printf (gettext (" set '%s' to %" PRIuFAST8 "\n"),
    6938             :                           "is_stmt", is_stmt);
    6939             :                   break;
    6940             : 
    6941           0 :                 case DW_LNS_set_basic_block:
    6942             :                   /* Takes no argument.  */
    6943           0 :                   puts (gettext (" set basic block flag"));
    6944           0 :                   break;
    6945             : 
    6946       28464 :                 case DW_LNS_const_add_pc:
    6947             :                   /* Takes no argument.  */
    6948             : 
    6949       28464 :                   if (unlikely (line_range == 0))
    6950             :                     goto invalid_unit;
    6951             : 
    6952       56928 :                   advance_pc ((255 - opcode_base) / line_range);
    6953             :                   {
    6954       28464 :                     char *a = format_dwarf_addr (dwflmod, 0, address, address);
    6955       28464 :                     if (show_op_index)
    6956           0 :                       printf (gettext ("\
    6957             :  advance address by constant %u to %s, op_index to %u\n"),
    6958             :                               op_addr_advance, a, op_index);
    6959             :                     else
    6960       28464 :                       printf (gettext ("\
    6961             :  advance address by constant %u to %s\n"),
    6962             :                               op_addr_advance, a);
    6963       28464 :                     free (a);
    6964             :                   }
    6965       28464 :                   break;
    6966             : 
    6967           0 :                 case DW_LNS_fixed_advance_pc:
    6968             :                   /* Takes one 16 bit parameter which is added to the
    6969             :                      address.  */
    6970           0 :                   if (unlikely (standard_opcode_lengths[opcode] != 1))
    6971             :                     goto invalid_unit;
    6972             : 
    6973           0 :                   u128 = read_2ubyte_unaligned_inc (dbg, linep);
    6974           0 :                   address += u128;
    6975             :                   op_index = 0;
    6976             :                   {
    6977           0 :                     char *a = format_dwarf_addr (dwflmod, 0, address, address);
    6978           0 :                     printf (gettext ("\
    6979             :  advance address by fixed value %u to %s\n"),
    6980             :                             u128, a);
    6981           0 :                     free (a);
    6982             :                   }
    6983           0 :                   break;
    6984             : 
    6985           0 :                 case DW_LNS_set_prologue_end:
    6986             :                   /* Takes no argument.  */
    6987           0 :                   puts (gettext (" set prologue end flag"));
    6988           0 :                   break;
    6989             : 
    6990           0 :                 case DW_LNS_set_epilogue_begin:
    6991             :                   /* Takes no argument.  */
    6992           0 :                   puts (gettext (" set epilogue begin flag"));
    6993           0 :                   break;
    6994             : 
    6995           0 :                 case DW_LNS_set_isa:
    6996             :                   /* Takes one uleb128 parameter which is stored in isa.  */
    6997           0 :                   if (unlikely (standard_opcode_lengths[opcode] != 1))
    6998             :                     goto invalid_unit;
    6999             : 
    7000           0 :                   get_uleb128 (u128, linep, lineendp);
    7001           0 :                   printf (gettext (" set isa to %u\n"), u128);
    7002             :                   break;
    7003             :                 }
    7004             :             }
    7005             :           else
    7006             :             {
    7007             :               /* This is a new opcode the generator but not we know about.
    7008             :                  Read the parameters associated with it but then discard
    7009             :                  everything.  Read all the parameters for this opcode.  */
    7010           0 :               printf (ngettext (" unknown opcode with %" PRIu8 " parameter:",
    7011             :                                 " unknown opcode with %" PRIu8 " parameters:",
    7012             :                                 standard_opcode_lengths[opcode]),
    7013           0 :                       standard_opcode_lengths[opcode]);
    7014           0 :               for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
    7015             :                 {
    7016           0 :                   get_uleb128 (u128, linep, lineendp);
    7017           0 :                   if (n != standard_opcode_lengths[opcode])
    7018           0 :                     putc_unlocked (',', stdout);
    7019           0 :                   printf (" %u", u128);
    7020             :                 }
    7021             : 
    7022             :               /* Next round, ignore this opcode.  */
    7023           0 :               continue;
    7024             :             }
    7025             :         }
    7026             :     }
    7027             : 
    7028             :   /* There must only be one data block.  */
    7029          37 :   assert (elf_getdata (scn, data) == NULL);
    7030             : }
    7031             : 
    7032             : 
    7033             : static void
    7034          30 : print_debug_loc_section (Dwfl_Module *dwflmod,
    7035             :                          Ebl *ebl, GElf_Ehdr *ehdr,
    7036             :                          Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    7037             : {
    7038          30 :   Elf_Data *data = dbg->sectiondata[IDX_debug_loc];
    7039             : 
    7040          30 :   if (unlikely (data == NULL))
    7041             :     {
    7042           0 :       error (0, 0, gettext ("cannot get .debug_loc content: %s"),
    7043             :              elf_errmsg (-1));
    7044           0 :       return;
    7045             :     }
    7046             : 
    7047          90 :   printf (gettext ("\
    7048             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
    7049             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    7050          30 :           (uint64_t) shdr->sh_offset);
    7051             : 
    7052          60 :   sort_listptr (&known_loclistptr, "loclistptr");
    7053          30 :   size_t listptr_idx = 0;
    7054             : 
    7055          30 :   uint_fast8_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
    7056          30 :   uint_fast8_t offset_size = 4;
    7057             : 
    7058          30 :   bool first = true;
    7059          30 :   struct Dwarf_CU *cu = NULL;
    7060          30 :   Dwarf_Addr base = 0;
    7061          30 :   unsigned char *readp = data->d_buf;
    7062          30 :   unsigned char *const endp = (unsigned char *) data->d_buf + data->d_size;
    7063      210714 :   while (readp < endp)
    7064             :     {
    7065      210654 :       ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
    7066             : 
    7067      210654 :       if (first && skip_listptr_hole (&known_loclistptr, &listptr_idx,
    7068             :                                       &address_size, &offset_size, &base,
    7069             :                                       &cu, offset, &readp, endp))
    7070           0 :         continue;
    7071             : 
    7072      210654 :       if (unlikely (data->d_size - offset < (size_t) address_size * 2))
    7073             :         {
    7074           0 :           printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
    7075             :           break;
    7076             :         }
    7077             : 
    7078             :       Dwarf_Addr begin;
    7079             :       Dwarf_Addr end;
    7080      210654 :       if (address_size == 8)
    7081             :         {
    7082      210654 :           begin = read_8ubyte_unaligned_inc (dbg, readp);
    7083      210654 :           end = read_8ubyte_unaligned_inc (dbg, readp);
    7084             :         }
    7085             :       else
    7086             :         {
    7087           0 :           begin = read_4ubyte_unaligned_inc (dbg, readp);
    7088           0 :           end = read_4ubyte_unaligned_inc (dbg, readp);
    7089           0 :           if (begin == (Dwarf_Addr) (uint32_t) -1)
    7090             :             begin = (Dwarf_Addr) -1l;
    7091             :         }
    7092             : 
    7093      210654 :       if (begin == (Dwarf_Addr) -1l) /* Base address entry.  */
    7094             :         {
    7095           0 :           char *b = format_dwarf_addr (dwflmod, address_size, end, end);
    7096           0 :           printf (gettext (" [%6tx]  base address %s\n"), offset, b);
    7097           0 :           free (b);
    7098           0 :           base = end;
    7099             :         }
    7100      210654 :       else if (begin == 0 && end == 0) /* End of list entry.  */
    7101             :         {
    7102       42545 :           if (first)
    7103           0 :             printf (gettext (" [%6tx]  empty list\n"), offset);
    7104             :           first = true;
    7105             :         }
    7106             :       else
    7107             :         {
    7108             :           /* We have a location expression entry.  */
    7109      168109 :           uint_fast16_t len = read_2ubyte_unaligned_inc (dbg, readp);
    7110             : 
    7111      168109 :           char *b = format_dwarf_addr (dwflmod, address_size, base + begin,
    7112             :                                        begin);
    7113      168109 :           char *e = format_dwarf_addr (dwflmod, address_size, base + end,
    7114             :                                        end);
    7115             : 
    7116      168109 :           if (first)            /* First entry in a list.  */
    7117       42545 :             printf (gettext (" [%6tx]  %s..%s"), offset, b, e);
    7118             :           else
    7119      125564 :             printf (gettext ("           %s..%s"), b, e);
    7120             : 
    7121      168109 :           free (b);
    7122      168109 :           free (e);
    7123             : 
    7124      168109 :           if (endp - readp <= (ptrdiff_t) len)
    7125             :             {
    7126           0 :               fputs (gettext ("   <INVALID DATA>\n"), stdout);
    7127           0 :               break;
    7128             :             }
    7129             : 
    7130      168109 :           print_ops (dwflmod, dbg, 1, 18 + (address_size * 4),
    7131             :                      3 /*XXX*/, address_size, offset_size, cu, len, readp);
    7132             : 
    7133      168109 :           first = false;
    7134      168109 :           readp += len;
    7135             :         }
    7136             :     }
    7137             : }
    7138             : 
    7139             : struct mac_culist
    7140             : {
    7141             :   Dwarf_Die die;
    7142             :   Dwarf_Off offset;
    7143             :   Dwarf_Files *files;
    7144             :   struct mac_culist *next;
    7145             : };
    7146             : 
    7147             : 
    7148             : static int
    7149           0 : mac_compare (const void *p1, const void *p2)
    7150             : {
    7151           0 :   struct mac_culist *m1 = (struct mac_culist *) p1;
    7152           0 :   struct mac_culist *m2 = (struct mac_culist *) p2;
    7153             : 
    7154           0 :   if (m1->offset < m2->offset)
    7155             :     return -1;
    7156           0 :   if (m1->offset > m2->offset)
    7157             :     return 1;
    7158           0 :   return 0;
    7159             : }
    7160             : 
    7161             : 
    7162             : static void
    7163           0 : print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
    7164             :                              Ebl *ebl, GElf_Ehdr *ehdr,
    7165             :                              Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    7166             : {
    7167           0 :   printf (gettext ("\
    7168             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
    7169             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    7170           0 :           (uint64_t) shdr->sh_offset);
    7171           0 :   putc_unlocked ('\n', stdout);
    7172             : 
    7173             :   /* There is no function in libdw to iterate over the raw content of
    7174             :      the section but it is easy enough to do.  */
    7175           0 :   Elf_Data *data = dbg->sectiondata[IDX_debug_macinfo];
    7176           0 :   if (unlikely (data == NULL || data->d_buf == NULL))
    7177             :     {
    7178           0 :       error (0, 0, gettext ("cannot get macro information section data: %s"),
    7179             :              elf_errmsg (-1));
    7180           0 :       return;
    7181             :     }
    7182             : 
    7183             :   /* Get the source file information for all CUs.  */
    7184             :   Dwarf_Off offset;
    7185           0 :   Dwarf_Off ncu = 0;
    7186             :   size_t hsize;
    7187           0 :   struct mac_culist *culist = NULL;
    7188           0 :   size_t nculist = 0;
    7189           0 :   while (dwarf_nextcu (dbg, offset = ncu, &ncu, &hsize, NULL, NULL, NULL) == 0)
    7190             :     {
    7191             :       Dwarf_Die cudie;
    7192           0 :       if (dwarf_offdie (dbg, offset + hsize, &cudie) == NULL)
    7193           0 :         continue;
    7194             : 
    7195             :       Dwarf_Attribute attr;
    7196           0 :       if (dwarf_attr (&cudie, DW_AT_macro_info, &attr) == NULL)
    7197           0 :         continue;
    7198             : 
    7199             :       Dwarf_Word macoff;
    7200           0 :       if (dwarf_formudata (&attr, &macoff) != 0)
    7201           0 :         continue;
    7202             : 
    7203           0 :       struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp));
    7204           0 :       newp->die = cudie;
    7205           0 :       newp->offset = macoff;
    7206           0 :       newp->files = NULL;
    7207           0 :       newp->next = culist;
    7208           0 :       culist = newp;
    7209           0 :       ++nculist;
    7210             :     }
    7211             : 
    7212             :   /* Convert the list into an array for easier consumption.  */
    7213           0 :   struct mac_culist *cus = (struct mac_culist *) alloca ((nculist + 1)
    7214             :                                                          * sizeof (*cus));
    7215             :   /* Add sentinel.  */
    7216           0 :   cus[nculist].offset = data->d_size;
    7217           0 :   cus[nculist].files = (Dwarf_Files *) -1l;
    7218           0 :   if (nculist > 0)
    7219             :     {
    7220           0 :       for (size_t cnt = nculist - 1; culist != NULL; --cnt)
    7221             :         {
    7222           0 :           assert (cnt < nculist);
    7223           0 :           cus[cnt] = *culist;
    7224           0 :           culist = culist->next;
    7225             :         }
    7226             : 
    7227             :       /* Sort the array according to the offset in the .debug_macinfo
    7228             :          section.  Note we keep the sentinel at the end.  */
    7229           0 :       qsort (cus, nculist, sizeof (*cus), mac_compare);
    7230             :     }
    7231             : 
    7232           0 :   const unsigned char *readp = (const unsigned char *) data->d_buf;
    7233           0 :   const unsigned char *readendp = readp + data->d_size;
    7234           0 :   int level = 1;
    7235             : 
    7236           0 :   while (readp < readendp)
    7237             :     {
    7238           0 :       unsigned int opcode = *readp++;
    7239             :       unsigned int u128;
    7240             :       unsigned int u128_2;
    7241             :       const unsigned char *endp;
    7242             : 
    7243           0 :       switch (opcode)
    7244             :         {
    7245           0 :         case DW_MACINFO_define:
    7246             :         case DW_MACINFO_undef:
    7247             :         case DW_MACINFO_vendor_ext:
    7248             :           /*  For the first two opcodes the parameters are
    7249             :                 line, string
    7250             :               For the latter
    7251             :                 number, string.
    7252             :               We can treat these cases together.  */
    7253           0 :           get_uleb128 (u128, readp, readendp);
    7254             : 
    7255           0 :           endp = memchr (readp, '\0', readendp - readp);
    7256           0 :           if (unlikely (endp == NULL))
    7257             :             {
    7258           0 :               printf (gettext ("\
    7259             : %*s*** non-terminated string at end of section"),
    7260             :                       level, "");
    7261             :               return;
    7262             :             }
    7263             : 
    7264           0 :           if (opcode == DW_MACINFO_define)
    7265           0 :             printf ("%*s#define %s, line %u\n",
    7266             :                     level, "", (char *) readp, u128);
    7267           0 :           else if (opcode == DW_MACINFO_undef)
    7268           0 :             printf ("%*s#undef %s, line %u\n",
    7269             :                     level, "", (char *) readp, u128);
    7270             :           else
    7271           0 :             printf (" #vendor-ext %s, number %u\n", (char *) readp, u128);
    7272             : 
    7273           0 :           readp = endp + 1;
    7274           0 :           break;
    7275             : 
    7276           0 :         case DW_MACINFO_start_file:
    7277             :           /* The two parameters are line and file index, in this order.  */
    7278           0 :           get_uleb128 (u128, readp, readendp);
    7279           0 :           if (readendp - readp < 1)
    7280             :             {
    7281           0 :               printf (gettext ("\
    7282             : %*s*** missing DW_MACINFO_start_file argument at end of section"),
    7283             :                       level, "");
    7284             :               return;
    7285             :             }
    7286           0 :           get_uleb128 (u128_2, readp, readendp);
    7287             : 
    7288             :           /* Find the CU DIE for this file.  */
    7289           0 :           size_t macoff = readp - (const unsigned char *) data->d_buf;
    7290           0 :           const char *fname = "???";
    7291           0 :           if (macoff >= cus[0].offset)
    7292             :             {
    7293           0 :               while (macoff >= cus[1].offset && cus[1].offset != data->d_size)
    7294           0 :                 ++cus;
    7295             : 
    7296           0 :               if (cus[0].files == NULL
    7297           0 :                 && dwarf_getsrcfiles (&cus[0].die, &cus[0].files, NULL) != 0)
    7298           0 :                 cus[0].files = (Dwarf_Files *) -1l;
    7299             : 
    7300           0 :               if (cus[0].files != (Dwarf_Files *) -1l)
    7301           0 :                 fname = (dwarf_filesrc (cus[0].files, u128_2, NULL, NULL)
    7302           0 :                          ?: "???");
    7303             :             }
    7304             : 
    7305           0 :           printf ("%*sstart_file %u, [%u] %s\n",
    7306             :                   level, "", u128, u128_2, fname);
    7307           0 :           ++level;
    7308           0 :           break;
    7309             : 
    7310           0 :         case DW_MACINFO_end_file:
    7311           0 :           --level;
    7312             :           printf ("%*send_file\n", level, "");
    7313             :           /* Nothing more to do.  */
    7314             :           break;
    7315             : 
    7316           0 :         default:
    7317             :           // XXX gcc seems to generate files with a trailing zero.
    7318           0 :           if (unlikely (opcode != 0 || readp != readendp))
    7319             :             printf ("%*s*** invalid opcode %u\n", level, "", opcode);
    7320             :           break;
    7321             :         }
    7322             :     }
    7323             : }
    7324             : 
    7325             : 
    7326             : static void
    7327           3 : print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
    7328             :                            Ebl *ebl, GElf_Ehdr *ehdr,
    7329             :                            Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    7330             : {
    7331           9 :   printf (gettext ("\
    7332             : \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
    7333             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    7334           3 :           (uint64_t) shdr->sh_offset);
    7335           6 :   putc_unlocked ('\n', stdout);
    7336             : 
    7337           3 :   Elf_Data *data = dbg->sectiondata[IDX_debug_macro];
    7338           3 :   if (unlikely (data == NULL || data->d_buf == NULL))
    7339             :     {
    7340           0 :       error (0, 0, gettext ("cannot get macro information section data: %s"),
    7341             :              elf_errmsg (-1));
    7342           0 :       return;
    7343             :     }
    7344             : 
    7345             :   /* Get the source file information for all CUs.  Uses same
    7346             :      datastructure as macinfo.  But uses offset field to directly
    7347             :      match .debug_line offset.  And just stored in a list.  */
    7348             :   Dwarf_Off offset;
    7349           3 :   Dwarf_Off ncu = 0;
    7350             :   size_t hsize;
    7351           3 :   struct mac_culist *culist = NULL;
    7352           3 :   size_t nculist = 0;
    7353          10 :   while (dwarf_nextcu (dbg, offset = ncu, &ncu, &hsize, NULL, NULL, NULL) == 0)
    7354             :     {
    7355             :       Dwarf_Die cudie;
    7356           4 :       if (dwarf_offdie (dbg, offset + hsize, &cudie) == NULL)
    7357           0 :         continue;
    7358             : 
    7359             :       Dwarf_Attribute attr;
    7360           4 :       if (dwarf_attr (&cudie, DW_AT_stmt_list, &attr) == NULL)
    7361           0 :         continue;
    7362             : 
    7363             :       Dwarf_Word lineoff;
    7364           4 :       if (dwarf_formudata (&attr, &lineoff) != 0)
    7365           0 :         continue;
    7366             : 
    7367           4 :       struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp));
    7368           4 :       newp->die = cudie;
    7369           4 :       newp->offset = lineoff;
    7370           4 :       newp->files = NULL;
    7371           4 :       newp->next = culist;
    7372           4 :       culist = newp;
    7373           4 :       ++nculist;
    7374             :     }
    7375             : 
    7376           3 :   const unsigned char *readp = (const unsigned char *) data->d_buf;
    7377           3 :   const unsigned char *readendp = readp + data->d_size;
    7378             : 
    7379          14 :   while (readp < readendp)
    7380             :     {
    7381          16 :       printf (gettext (" Offset:             0x%" PRIx64 "\n"),
    7382           8 :               (uint64_t) (readp - (const unsigned char *) data->d_buf));
    7383             : 
    7384             :       // Header, 2 byte version, 1 byte flag, optional .debug_line offset,
    7385             :       // optional vendor extension macro entry table.
    7386           8 :       if (readp + 2 > readendp)
    7387             :         {
    7388           0 :         invalid_data:
    7389           0 :           error (0, 0, gettext ("invalid data"));
    7390           0 :           return;
    7391             :         }
    7392           8 :       const uint16_t vers = read_2ubyte_unaligned_inc (dbg, readp);
    7393          16 :       printf (gettext (" Version:            %" PRIu16 "\n"), vers);
    7394             : 
    7395             :       // Version 4 is the GNU extension for DWARF4.  DWARF5 will use version
    7396             :       // 5 when it gets standardized.
    7397           8 :       if (vers != 4 && vers != 5)
    7398             :         {
    7399           0 :           printf (gettext ("  unknown version, cannot parse section\n"));
    7400             :           return;
    7401             :         }
    7402             : 
    7403           8 :       if (readp + 1 > readendp)
    7404             :         goto invalid_data;
    7405           8 :       const unsigned char flag = *readp++;
    7406          16 :       printf (gettext (" Flag:               0x%" PRIx8 "\n"), flag);
    7407             : 
    7408           8 :       unsigned int offset_len = (flag & 0x01) ? 8 : 4;
    7409          16 :       printf (gettext (" Offset length:      %" PRIu8 "\n"), offset_len);
    7410           8 :       Dwarf_Off line_offset = -1;
    7411           8 :       if (flag & 0x02)
    7412             :         {
    7413           4 :           if (offset_len == 8)
    7414           0 :             line_offset = read_8ubyte_unaligned_inc (dbg, readp);
    7415             :           else
    7416           4 :             line_offset = read_4ubyte_unaligned_inc (dbg, readp);
    7417           4 :           printf (gettext (" .debug_line offset: 0x%" PRIx64 "\n"),
    7418             :                   line_offset);
    7419             :         }
    7420             : 
    7421             :       const unsigned char *vendor[DW_MACRO_hi_user - DW_MACRO_lo_user];
    7422           8 :       memset (vendor, 0, sizeof vendor);
    7423           8 :       if (flag & 0x04)
    7424             :         {
    7425             :           // 1 byte length, for each item, 1 byte opcode, uleb128 number
    7426             :           // of arguments, for each argument 1 byte form code.
    7427           0 :           if (readp + 1 > readendp)
    7428             :             goto invalid_data;
    7429           0 :           unsigned int tlen = *readp++;
    7430           0 :           printf (gettext ("  extension opcode table, %" PRIu8 " items:\n"),
    7431             :                   tlen);
    7432           0 :           for (unsigned int i = 0; i < tlen; i++)
    7433             :             {
    7434           0 :               if (readp + 1 > readendp)
    7435             :                 goto invalid_data;
    7436           0 :               unsigned int opcode = *readp++;
    7437           0 :               printf (gettext ("    [%" PRIx8 "]"), opcode);
    7438           0 :               if (opcode < DW_MACRO_lo_user
    7439           0 :                   || opcode > DW_MACRO_hi_user)
    7440             :                 goto invalid_data;
    7441             :               // Record the start of description for this vendor opcode.
    7442             :               // uleb128 nr args, 1 byte per arg form.
    7443           0 :               vendor[opcode - DW_MACRO_lo_user] = readp;
    7444           0 :               if (readp + 1 > readendp)
    7445             :                 goto invalid_data;
    7446           0 :               unsigned int args = *readp++;
    7447           0 :               if (args > 0)
    7448             :                 {
    7449           0 :                   printf (gettext (" %" PRIu8 " arguments:"), args);
    7450           0 :                   while (args > 0)
    7451             :                     {
    7452           0 :                       if (readp + 1 > readendp)
    7453             :                         goto invalid_data;
    7454           0 :                       unsigned int form = *readp++;
    7455           0 :                       printf (" %s", dwarf_form_string (form));
    7456           0 :                       if (form != DW_FORM_data1
    7457           0 :                           && form != DW_FORM_data2
    7458             :                           && form != DW_FORM_data4
    7459           0 :                           && form != DW_FORM_data8
    7460           0 :                           && form != DW_FORM_sdata
    7461           0 :                           && form != DW_FORM_udata
    7462             :                           && form != DW_FORM_block
    7463           0 :                           && form != DW_FORM_block1
    7464             :                           && form != DW_FORM_block2
    7465           0 :                           && form != DW_FORM_block4
    7466           0 :                           && form != DW_FORM_flag
    7467           0 :                           && form != DW_FORM_string
    7468           0 :                           && form != DW_FORM_strp
    7469           0 :                           && form != DW_FORM_sec_offset)
    7470             :                         goto invalid_data;
    7471           0 :                       args--;
    7472           0 :                       if (args > 0)
    7473             :                         putchar_unlocked (',');
    7474             :                     }
    7475             :                 }
    7476             :               else
    7477           0 :                 printf (gettext (" no arguments."));
    7478           0 :               putchar_unlocked ('\n');
    7479             :             }
    7480             :         }
    7481           8 :       putchar_unlocked ('\n');
    7482             : 
    7483           8 :       int level = 1;
    7484           8 :       if (readp + 1 > readendp)
    7485             :         goto invalid_data;
    7486           8 :       unsigned int opcode = *readp++;
    7487         743 :       while (opcode != 0)
    7488             :         {
    7489             :           unsigned int u128;
    7490             :           unsigned int u128_2;
    7491             :           const unsigned char *endp;
    7492             :           uint64_t off;
    7493             : 
    7494         727 :           switch (opcode)
    7495             :             {
    7496           6 :             case DW_MACRO_start_file:
    7497           6 :               get_uleb128 (u128, readp, readendp);
    7498           6 :               if (readp >= readendp)
    7499             :                 goto invalid_data;
    7500           6 :               get_uleb128 (u128_2, readp, readendp);
    7501             : 
    7502             :               /* Find the CU DIE that matches this line offset.  */
    7503           6 :               const char *fname = "???";
    7504           6 :               if (line_offset != (Dwarf_Off) -1)
    7505             :                 {
    7506             :                   struct mac_culist *cu = culist;
    7507           8 :                   while (cu != NULL && line_offset != cu->offset)
    7508           2 :                     cu = cu->next;
    7509           6 :                   if (cu != NULL)
    7510             :                     {
    7511           6 :                       if (cu->files == NULL
    7512           4 :                           && dwarf_getsrcfiles (&cu->die, &cu->files,
    7513             :                                                 NULL) != 0)
    7514           0 :                         cu->files = (Dwarf_Files *) -1l;
    7515             : 
    7516           6 :                       if (cu->files != (Dwarf_Files *) -1l)
    7517           6 :                         fname = (dwarf_filesrc (cu->files, u128_2,
    7518           6 :                                                 NULL, NULL) ?: "???");
    7519             :                     }
    7520             :                 }
    7521           6 :               printf ("%*sstart_file %u, [%u] %s\n",
    7522             :                       level, "", u128, u128_2, fname);
    7523           6 :               ++level;
    7524           6 :               break;
    7525             : 
    7526           6 :             case DW_MACRO_end_file:
    7527           6 :               --level;
    7528             :               printf ("%*send_file\n", level, "");
    7529             :               break;
    7530             : 
    7531           1 :             case DW_MACRO_define:
    7532           1 :               get_uleb128 (u128, readp, readendp);
    7533           1 :               endp = memchr (readp, '\0', readendp - readp);
    7534           1 :               if (endp == NULL)
    7535             :                 goto invalid_data;
    7536           2 :               printf ("%*s#define %s, line %u\n",
    7537             :                       level, "", readp, u128);
    7538           1 :               readp = endp + 1;
    7539           1 :               break;
    7540             : 
    7541           0 :             case DW_MACRO_undef:
    7542           0 :               get_uleb128 (u128, readp, readendp);
    7543           0 :               endp = memchr (readp, '\0', readendp - readp);
    7544           0 :               if (endp == NULL)
    7545             :                 goto invalid_data;
    7546           0 :               printf ("%*s#undef %s, line %u\n",
    7547             :                       level, "", readp, u128);
    7548           0 :               readp = endp + 1;
    7549           0 :               break;
    7550             : 
    7551         707 :             case DW_MACRO_define_strp:
    7552         707 :               get_uleb128 (u128, readp, readendp);
    7553         707 :               if (readp + offset_len > readendp)
    7554             :                 goto invalid_data;
    7555         707 :               if (offset_len == 8)
    7556           0 :                 off = read_8ubyte_unaligned_inc (dbg, readp);
    7557             :               else
    7558         707 :                 off = read_4ubyte_unaligned_inc (dbg, readp);
    7559         707 :               printf ("%*s#define %s, line %u (indirect)\n",
    7560             :                       level, "", dwarf_getstring (dbg, off, NULL), u128);
    7561             :               break;
    7562             : 
    7563           1 :             case DW_MACRO_undef_strp:
    7564           1 :               get_uleb128 (u128, readp, readendp);
    7565           1 :               if (readp + offset_len > readendp)
    7566             :                 goto invalid_data;
    7567           1 :               if (offset_len == 8)
    7568           0 :                 off = read_8ubyte_unaligned_inc (dbg, readp);
    7569             :               else
    7570           1 :                 off = read_4ubyte_unaligned_inc (dbg, readp);
    7571           1 :               printf ("%*s#undef %s, line %u (indirect)\n",
    7572             :                       level, "", dwarf_getstring (dbg, off, NULL), u128);
    7573             :               break;
    7574             : 
    7575           6 :             case DW_MACRO_import:
    7576           6 :               if (readp + offset_len > readendp)
    7577             :                 goto invalid_data;
    7578           6 :               if (offset_len == 8)
    7579           0 :                 off = read_8ubyte_unaligned_inc (dbg, readp);
    7580             :               else
    7581           6 :                 off = read_4ubyte_unaligned_inc (dbg, readp);
    7582             :               printf ("%*s#include offset 0x%" PRIx64 "\n",
    7583             :                       level, "", off);
    7584             :               break;
    7585             : 
    7586           0 :             case DW_MACRO_define_sup:
    7587           0 :               get_uleb128 (u128, readp, readendp);
    7588           0 :               if (readp + offset_len > readendp)
    7589             :                 goto invalid_data;
    7590           0 :               if (offset_len == 8)
    7591           0 :                 off = read_8ubyte_unaligned_inc (dbg, readp);
    7592             :               else
    7593           0 :                 off = read_4ubyte_unaligned_inc (dbg, readp);
    7594             :               // Needs support for reading from supplementary object file.
    7595             :               printf ("%*s#define <str-at-0x%" PRIx64 ">, line %u (sup)\n",
    7596             :                       level, "", off, u128);
    7597             :               break;
    7598             : 
    7599           0 :             case DW_MACRO_undef_sup:
    7600           0 :               get_uleb128 (u128, readp, readendp);
    7601           0 :               if (readp + offset_len > readendp)
    7602             :                 goto invalid_data;
    7603           0 :               if (offset_len == 8)
    7604           0 :                 off = read_8ubyte_unaligned_inc (dbg, readp);
    7605             :               else
    7606           0 :                 off = read_4ubyte_unaligned_inc (dbg, readp);
    7607             :               // Needs support for reading from supplementary object file.
    7608             :               printf ("%*s#undef <str-at-0x%" PRIx64 ">, line %u (sup)\n",
    7609             :                       level, "", off, u128);
    7610             :               break;
    7611             : 
    7612           0 :             case DW_MACRO_import_sup:
    7613           0 :               if (readp + offset_len > readendp)
    7614             :                 goto invalid_data;
    7615           0 :               if (offset_len == 8)
    7616           0 :                 off = read_8ubyte_unaligned_inc (dbg, readp);
    7617             :               else
    7618           0 :                 off = read_4ubyte_unaligned_inc (dbg, readp);
    7619             :               printf ("%*s#include offset 0x%" PRIx64 " (sup)\n",
    7620             :                       level, "", off);
    7621             :               break;
    7622             : 
    7623           0 :             case DW_MACRO_define_strx:
    7624           0 :               get_uleb128 (u128, readp, readendp);
    7625           0 :               if (readp + offset_len > readendp)
    7626             :                 goto invalid_data;
    7627           0 :               if (offset_len == 8)
    7628           0 :                 off = read_8ubyte_unaligned_inc (dbg, readp);
    7629             :               else
    7630           0 :                 off = read_4ubyte_unaligned_inc (dbg, readp);
    7631             :               // Needs support for reading indirect string offset table
    7632             :               printf ("%*s#define <str-at-0x%" PRIx64 ">, line %u (strx)\n",
    7633             :                       level, "", off, u128);
    7634             :               break;
    7635             : 
    7636           0 :             case DW_MACRO_undef_strx:
    7637           0 :               get_uleb128 (u128, readp, readendp);
    7638           0 :               if (readp + offset_len > readendp)
    7639             :                 goto invalid_data;
    7640           0 :               if (offset_len == 8)
    7641           0 :                 off = read_8ubyte_unaligned_inc (dbg, readp);
    7642             :               else
    7643           0 :                 off = read_4ubyte_unaligned_inc (dbg, readp);
    7644             :               // Needs support for reading indirect string offset table.
    7645             :               printf ("%*s#undef <str-at-0x%" PRIx64 ">, line %u (strx)\n",
    7646             :                       level, "", off, u128);
    7647             :               break;
    7648             : 
    7649           0 :             default:
    7650           0 :               printf ("%*svendor opcode 0x%" PRIx8, level, "", opcode);
    7651           0 :               if (opcode < DW_MACRO_lo_user
    7652             :                   || opcode > DW_MACRO_lo_user
    7653           0 :                   || vendor[opcode - DW_MACRO_lo_user] == NULL)
    7654             :                 goto invalid_data;
    7655             : 
    7656             :               const unsigned char *op_desc;
    7657           0 :               op_desc = vendor[opcode - DW_MACRO_lo_user];
    7658             : 
    7659             :               // Just skip the arguments, we cannot really interpret them,
    7660             :               // but print as much as we can.
    7661           0 :               unsigned int args = *op_desc++;
    7662           0 :               while (args > 0)
    7663           0 :                 {
    7664           0 :                   unsigned int form = *op_desc++;
    7665             :                   Dwarf_Word val;
    7666           0 :                   switch (form)
    7667             :                     {
    7668           0 :                     case DW_FORM_data1:
    7669           0 :                       if (readp + 1 > readendp)
    7670             :                         goto invalid_data;
    7671           0 :                       val = *readp++;
    7672           0 :                       printf (" %" PRIx8, (unsigned int) val);
    7673             :                       break;
    7674             : 
    7675           0 :                     case DW_FORM_data2:
    7676           0 :                       if (readp + 2 > readendp)
    7677             :                         goto invalid_data;
    7678           0 :                       val = read_2ubyte_unaligned_inc (dbg, readp);
    7679           0 :                       printf(" %" PRIx16, (unsigned int) val);
    7680             :                       break;
    7681             : 
    7682           0 :                     case DW_FORM_data4:
    7683           0 :                       if (readp + 4 > readendp)
    7684             :                         goto invalid_data;
    7685           0 :                       val = read_4ubyte_unaligned_inc (dbg, readp);
    7686           0 :                       printf (" %" PRIx32, (unsigned int) val);
    7687             :                       break;
    7688             : 
    7689           0 :                     case DW_FORM_data8:
    7690           0 :                       if (readp + 8 > readendp)
    7691             :                         goto invalid_data;
    7692           0 :                       val = read_8ubyte_unaligned_inc (dbg, readp);
    7693             :                       printf (" %" PRIx64, val);
    7694             :                       break;
    7695             : 
    7696           0 :                     case DW_FORM_sdata:
    7697           0 :                       get_sleb128 (val, readp, readendp);
    7698             :                       printf (" %" PRIx64, val);
    7699             :                       break;
    7700             : 
    7701           0 :                     case DW_FORM_udata:
    7702           0 :                       get_uleb128 (val, readp, readendp);
    7703             :                       printf (" %" PRIx64, val);
    7704             :                       break;
    7705             : 
    7706           0 :                     case DW_FORM_block:
    7707           0 :                       get_uleb128 (val, readp, readendp);
    7708           0 :                       printf (" block[%" PRIu64 "]", val);
    7709           0 :                       if (readp + val > readendp)
    7710             :                         goto invalid_data;
    7711           0 :                       readp += val;
    7712           0 :                       break;
    7713             : 
    7714           0 :                     case DW_FORM_block1:
    7715           0 :                       if (readp + 1 > readendp)
    7716             :                         goto invalid_data;
    7717           0 :                       val = *readp++;
    7718           0 :                       printf (" block[%" PRIu64 "]", val);
    7719           0 :                       if (readp + val > readendp)
    7720             :                         goto invalid_data;
    7721             :                       break;
    7722             : 
    7723           0 :                     case DW_FORM_block2:
    7724           0 :                       if (readp + 2 > readendp)
    7725             :                         goto invalid_data;
    7726           0 :                       val = read_2ubyte_unaligned_inc (dbg, readp);
    7727           0 :                       printf (" block[%" PRIu64 "]", val);
    7728           0 :                       if (readp + val > readendp)
    7729             :                         goto invalid_data;
    7730             :                       break;
    7731             : 
    7732           0 :                     case DW_FORM_block4:
    7733           0 :                       if (readp + 2 > readendp)
    7734             :                         goto invalid_data;
    7735           0 :                       val =read_4ubyte_unaligned_inc (dbg, readp);
    7736           0 :                       printf (" block[%" PRIu64 "]", val);
    7737           0 :                       if (readp + val > readendp)
    7738             :                         goto invalid_data;
    7739             :                       break;
    7740             : 
    7741           0 :                     case DW_FORM_flag:
    7742           0 :                       if (readp + 1 > readendp)
    7743             :                         goto invalid_data;
    7744           0 :                       val = *readp++;
    7745           0 :                       printf (" %s", val != 0 ? gettext ("yes") : gettext ("no"));
    7746             :                       break;
    7747             : 
    7748           0 :                     case DW_FORM_string:
    7749           0 :                       endp = memchr (readp, '\0', readendp - readp);
    7750           0 :                       if (endp == NULL)
    7751             :                         goto invalid_data;
    7752           0 :                       printf (" %s", readp);
    7753           0 :                       readp = endp + 1;
    7754           0 :                       break;
    7755             : 
    7756           0 :                     case DW_FORM_strp:
    7757           0 :                       if (readp + offset_len > readendp)
    7758             :                         goto invalid_data;
    7759           0 :                       if (offset_len == 8)
    7760           0 :                         val = read_8ubyte_unaligned_inc (dbg, readp);
    7761             :                       else
    7762           0 :                         val = read_4ubyte_unaligned_inc (dbg, readp);
    7763           0 :                       printf (" %s", dwarf_getstring (dbg, val, NULL));
    7764             :                       break;
    7765             : 
    7766           0 :                     case DW_FORM_sec_offset:
    7767           0 :                       if (readp + offset_len > readendp)
    7768             :                         goto invalid_data;
    7769           0 :                       if (offset_len == 8)
    7770           0 :                         val = read_8ubyte_unaligned_inc (dbg, readp);
    7771             :                       else
    7772           0 :                         val = read_4ubyte_unaligned_inc (dbg, readp);
    7773             :                       printf (" %" PRIx64, val);
    7774             :                       break;
    7775             : 
    7776           0 :                       default:
    7777           0 :                         error (0, 0, gettext ("vendor opcode not verified?"));
    7778             :                         return;
    7779             :                     }
    7780             : 
    7781           0 :                   args--;
    7782           0 :                   if (args > 0)
    7783             :                     putchar_unlocked (',');
    7784             :                 }
    7785             :               putchar_unlocked ('\n');
    7786             :             }
    7787             : 
    7788         727 :           if (readp + 1 > readendp)
    7789             :             goto invalid_data;
    7790         727 :           opcode = *readp++;
    7791         727 :           if (opcode == 0)
    7792             :             putchar_unlocked ('\n');
    7793             :         }
    7794             :     }
    7795             : }
    7796             : 
    7797             : 
    7798             : /* Callback for printing global names.  */
    7799             : static int
    7800          34 : print_pubnames (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
    7801             :                 void *arg)
    7802             : {
    7803          34 :   int *np = (int *) arg;
    7804             : 
    7805         102 :   printf (gettext (" [%5d] DIE offset: %6" PRId64
    7806             :                    ", CU DIE offset: %6" PRId64 ", name: %s\n"),
    7807          34 :           (*np)++, global->die_offset, global->cu_offset, global->name);
    7808             : 
    7809          34 :   return 0;
    7810             : }
    7811             : 
    7812             : 
    7813             : /* Print the known exported symbols in the DWARF section '.debug_pubnames'.  */
    7814             : static void
    7815           8 : print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
    7816             :                               Ebl *ebl, GElf_Ehdr *ehdr,
    7817             :                               Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    7818             : {
    7819          24 :   printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
    7820             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    7821           8 :           (uint64_t) shdr->sh_offset);
    7822             : 
    7823           8 :   int n = 0;
    7824           8 :   (void) dwarf_getpubnames (dbg, print_pubnames, &n, 0);
    7825           8 : }
    7826             : 
    7827             : /* Print the content of the DWARF string section '.debug_str'.  */
    7828             : static void
    7829          34 : print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
    7830             :                          Ebl *ebl, GElf_Ehdr *ehdr,
    7831             :                          Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    7832             : {
    7833          68 :   const size_t sh_size = (dbg->sectiondata[IDX_debug_str] ?
    7834          34 :                           dbg->sectiondata[IDX_debug_str]->d_size : 0);
    7835             : 
    7836             :   /* Compute floor(log16(shdr->sh_size)).  */
    7837          34 :   GElf_Addr tmp = sh_size;
    7838          34 :   int digits = 1;
    7839         165 :   while (tmp >= 16)
    7840             :     {
    7841          97 :       ++digits;
    7842          97 :       tmp >>= 4;
    7843             :     }
    7844          34 :   digits = MAX (4, digits);
    7845             : 
    7846         136 :   printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
    7847             :                    " %*s  String\n"),
    7848             :           elf_ndxscn (scn),
    7849          34 :           section_name (ebl, ehdr, shdr), (uint64_t) shdr->sh_offset,
    7850             :           /* TRANS: the debugstr| prefix makes the string unique.  */
    7851          34 :           digits + 2, sgettext ("debugstr|Offset"));
    7852             : 
    7853          34 :   Dwarf_Off offset = 0;
    7854       60740 :   while (offset < sh_size)
    7855             :     {
    7856             :       size_t len;
    7857       60672 :       const char *str = dwarf_getstring (dbg, offset, &len);
    7858       60672 :       if (unlikely (str == NULL))
    7859             :         {
    7860           0 :           printf (gettext (" *** error while reading strings: %s\n"),
    7861             :                   dwarf_errmsg (-1));
    7862           0 :           break;
    7863             :         }
    7864             : 
    7865       60672 :       printf (" [%*" PRIx64 "]  \"%s\"\n", digits, (uint64_t) offset, str);
    7866             : 
    7867       60672 :       offset += len + 1;
    7868             :     }
    7869          34 : }
    7870             : 
    7871             : 
    7872             : /* Print the content of the call frame search table section
    7873             :    '.eh_frame_hdr'.  */
    7874             : static void
    7875          16 : print_debug_frame_hdr_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
    7876             :                                Ebl *ebl __attribute__ ((unused)),
    7877             :                                GElf_Ehdr *ehdr __attribute__ ((unused)),
    7878             :                                Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    7879             : {
    7880          32 :   printf (gettext ("\
    7881             : \nCall frame search table section [%2zu] '.eh_frame_hdr':\n"),
    7882             :           elf_ndxscn (scn));
    7883             : 
    7884          16 :   Elf_Data *data = elf_rawdata (scn, NULL);
    7885             : 
    7886          16 :   if (unlikely (data == NULL))
    7887             :     {
    7888           0 :       error (0, 0, gettext ("cannot get %s content: %s"),
    7889             :              ".eh_frame_hdr", elf_errmsg (-1));
    7890           0 :       return;
    7891             :     }
    7892             : 
    7893          16 :   const unsigned char *readp = data->d_buf;
    7894          16 :   const unsigned char *const dataend = ((unsigned char *) data->d_buf
    7895          16 :                                         + data->d_size);
    7896             : 
    7897          16 :   if (unlikely (readp + 4 > dataend))
    7898             :     {
    7899           0 :     invalid_data:
    7900           0 :       error (0, 0, gettext ("invalid data"));
    7901             :       return;
    7902             :     }
    7903             : 
    7904          16 :   unsigned int version = *readp++;
    7905          16 :   unsigned int eh_frame_ptr_enc = *readp++;
    7906          16 :   unsigned int fde_count_enc = *readp++;
    7907          16 :   unsigned int table_enc = *readp++;
    7908             : 
    7909          16 :   printf (" version:          %u\n"
    7910             :           " eh_frame_ptr_enc: %#x ",
    7911             :           version, eh_frame_ptr_enc);
    7912          16 :   print_encoding_base ("", eh_frame_ptr_enc);
    7913          16 :   printf (" fde_count_enc:    %#x ", fde_count_enc);
    7914          16 :   print_encoding_base ("", fde_count_enc);
    7915          16 :   printf (" table_enc:        %#x ", table_enc);
    7916          16 :   print_encoding_base ("", table_enc);
    7917             : 
    7918          16 :   uint64_t eh_frame_ptr = 0;
    7919          16 :   if (eh_frame_ptr_enc != DW_EH_PE_omit)
    7920             :     {
    7921          16 :       readp = read_encoded (eh_frame_ptr_enc, readp, dataend, &eh_frame_ptr,
    7922             :                             dbg);
    7923          16 :       if (unlikely (readp == NULL))
    7924             :         goto invalid_data;
    7925             : 
    7926          32 :       printf (" eh_frame_ptr:     %#" PRIx64, eh_frame_ptr);
    7927          16 :       if ((eh_frame_ptr_enc & 0x70) == DW_EH_PE_pcrel)
    7928          16 :         printf (" (offset: %#" PRIx64 ")",
    7929             :                 /* +4 because of the 4 byte header of the section.  */
    7930          16 :                 (uint64_t) shdr->sh_offset + 4 + eh_frame_ptr);
    7931             : 
    7932             :       putchar_unlocked ('\n');
    7933             :     }
    7934             : 
    7935          16 :   uint64_t fde_count = 0;
    7936          16 :   if (fde_count_enc != DW_EH_PE_omit)
    7937             :     {
    7938          16 :       readp = read_encoded (fde_count_enc, readp, dataend, &fde_count, dbg);
    7939          16 :       if (unlikely (readp == NULL))
    7940             :         goto invalid_data;
    7941             : 
    7942          16 :       printf (" fde_count:        %" PRIu64 "\n", fde_count);
    7943             :     }
    7944             : 
    7945          16 :   if (fde_count == 0 || table_enc == DW_EH_PE_omit)
    7946             :     return;
    7947             : 
    7948          16 :   puts (" Table:");
    7949             : 
    7950             :   /* Optimize for the most common case.  */
    7951          16 :   if (table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4))
    7952        5392 :     while (fde_count > 0 && readp + 8 <= dataend)
    7953             :       {
    7954        5376 :         int32_t initial_location = read_4sbyte_unaligned_inc (dbg, readp);
    7955       10752 :         uint64_t initial_offset = ((uint64_t) shdr->sh_offset
    7956        5376 :                                    + (int64_t) initial_location);
    7957        5376 :         int32_t address = read_4sbyte_unaligned_inc (dbg, readp);
    7958             :         // XXX Possibly print symbol name or section offset for initial_offset
    7959        5376 :         printf ("  %#" PRIx32 " (offset: %#6" PRIx64 ") -> %#" PRIx32
    7960             :                 " fde=[%6" PRIx64 "]\n",
    7961             :                 initial_location, initial_offset,
    7962        5376 :                 address, address - (eh_frame_ptr + 4));
    7963             :       }
    7964             :   else
    7965             :     while (0 && readp < dataend)
    7966             :       {
    7967             : 
    7968             :       }
    7969             : }
    7970             : 
    7971             : 
    7972             : /* Print the content of the exception handling table section
    7973             :    '.eh_frame_hdr'.  */
    7974             : static void
    7975           0 : print_debug_exception_table (Dwfl_Module *dwflmod __attribute__ ((unused)),
    7976             :                              Ebl *ebl __attribute__ ((unused)),
    7977             :                              GElf_Ehdr *ehdr __attribute__ ((unused)),
    7978             :                              Elf_Scn *scn,
    7979             :                              GElf_Shdr *shdr __attribute__ ((unused)),
    7980             :                              Dwarf *dbg __attribute__ ((unused)))
    7981             : {
    7982           0 :   printf (gettext ("\
    7983             : \nException handling table section [%2zu] '.gcc_except_table':\n"),
    7984             :           elf_ndxscn (scn));
    7985             : 
    7986           0 :   Elf_Data *data = elf_rawdata (scn, NULL);
    7987             : 
    7988           0 :   if (unlikely (data == NULL))
    7989             :     {
    7990           0 :       error (0, 0, gettext ("cannot get %s content: %s"),
    7991             :              ".gcc_except_table", elf_errmsg (-1));
    7992           0 :       return;
    7993             :     }
    7994             : 
    7995           0 :   const unsigned char *readp = data->d_buf;
    7996           0 :   const unsigned char *const dataend = readp + data->d_size;
    7997             : 
    7998           0 :   if (unlikely (readp + 1 > dataend))
    7999             :     {
    8000           0 :     invalid_data:
    8001           0 :       error (0, 0, gettext ("invalid data"));
    8002             :       return;
    8003             :     }
    8004           0 :   unsigned int lpstart_encoding = *readp++;
    8005           0 :   printf (gettext (" LPStart encoding:    %#x "), lpstart_encoding);
    8006           0 :   print_encoding_base ("", lpstart_encoding);
    8007           0 :   if (lpstart_encoding != DW_EH_PE_omit)
    8008             :     {
    8009             :       uint64_t lpstart;
    8010           0 :       readp = read_encoded (lpstart_encoding, readp, dataend, &lpstart, dbg);
    8011           0 :       printf (" LPStart:             %#" PRIx64 "\n", lpstart);
    8012             :     }
    8013             : 
    8014           0 :   if (unlikely (readp + 1 > dataend))
    8015             :     goto invalid_data;
    8016           0 :   unsigned int ttype_encoding = *readp++;
    8017           0 :   printf (gettext (" TType encoding:      %#x "), ttype_encoding);
    8018           0 :   print_encoding_base ("", ttype_encoding);
    8019           0 :   const unsigned char *ttype_base = NULL;
    8020           0 :   if (ttype_encoding != DW_EH_PE_omit)
    8021             :     {
    8022             :       unsigned int ttype_base_offset;
    8023           0 :       get_uleb128 (ttype_base_offset, readp, dataend);
    8024           0 :       printf (" TType base offset:   %#x\n", ttype_base_offset);
    8025           0 :       if ((size_t) (dataend - readp) > ttype_base_offset)
    8026           0 :         ttype_base = readp + ttype_base_offset;
    8027             :     }
    8028             : 
    8029           0 :   if (unlikely (readp + 1 > dataend))
    8030             :     goto invalid_data;
    8031           0 :   unsigned int call_site_encoding = *readp++;
    8032           0 :   printf (gettext (" Call site encoding:  %#x "), call_site_encoding);
    8033           0 :   print_encoding_base ("", call_site_encoding);
    8034             :   unsigned int call_site_table_len;
    8035           0 :   get_uleb128 (call_site_table_len, readp, dataend);
    8036             : 
    8037           0 :   const unsigned char *const action_table = readp + call_site_table_len;
    8038           0 :   if (unlikely (action_table > dataend))
    8039             :     goto invalid_data;
    8040             :   unsigned int u = 0;
    8041             :   unsigned int max_action = 0;
    8042           0 :   while (readp < action_table)
    8043             :     {
    8044           0 :       if (u == 0)
    8045           0 :         puts (gettext ("\n Call site table:"));
    8046             : 
    8047             :       uint64_t call_site_start;
    8048           0 :       readp = read_encoded (call_site_encoding, readp, dataend,
    8049             :                             &call_site_start, dbg);
    8050             :       uint64_t call_site_length;
    8051           0 :       readp = read_encoded (call_site_encoding, readp, dataend,
    8052             :                             &call_site_length, dbg);
    8053             :       uint64_t landing_pad;
    8054           0 :       readp = read_encoded (call_site_encoding, readp, dataend,
    8055             :                             &landing_pad, dbg);
    8056             :       unsigned int action;
    8057           0 :       get_uleb128 (action, readp, dataend);
    8058           0 :       max_action = MAX (action, max_action);
    8059           0 :       printf (gettext (" [%4u] Call site start:   %#" PRIx64 "\n"
    8060             :                        "        Call site length:  %" PRIu64 "\n"
    8061             :                        "        Landing pad:       %#" PRIx64 "\n"
    8062             :                        "        Action:            %u\n"),
    8063             :               u++, call_site_start, call_site_length, landing_pad, action);
    8064             :     }
    8065           0 :   if (readp != action_table)
    8066             :     goto invalid_data;
    8067             : 
    8068           0 :   unsigned int max_ar_filter = 0;
    8069           0 :   if (max_action > 0)
    8070             :     {
    8071           0 :       puts ("\n Action table:");
    8072             : 
    8073           0 :       size_t maxdata = (size_t) (dataend - action_table);
    8074           0 :       if (max_action > maxdata || maxdata - max_action < 1)
    8075             :         {
    8076           0 :         invalid_action_table:
    8077           0 :           fputs (gettext ("   <INVALID DATA>\n"), stdout);
    8078           0 :           return;
    8079             :         }
    8080             : 
    8081           0 :       const unsigned char *const action_table_end
    8082           0 :         = action_table + max_action + 1;
    8083             : 
    8084           0 :       u = 0;
    8085             :       do
    8086             :         {
    8087             :           int ar_filter;
    8088           0 :           get_sleb128 (ar_filter, readp, action_table_end);
    8089           0 :           if (ar_filter > 0 && (unsigned int) ar_filter > max_ar_filter)
    8090           0 :             max_ar_filter = ar_filter;
    8091             :           int ar_disp;
    8092           0 :           if (readp >= action_table_end)
    8093             :             goto invalid_action_table;
    8094           0 :           get_sleb128 (ar_disp, readp, action_table_end);
    8095             : 
    8096           0 :           printf (" [%4u] ar_filter:  % d\n"
    8097             :                   "        ar_disp:    % -5d",
    8098             :                   u, ar_filter, ar_disp);
    8099           0 :           if (abs (ar_disp) & 1)
    8100           0 :             printf (" -> [%4u]\n", u + (ar_disp + 1) / 2);
    8101           0 :           else if (ar_disp != 0)
    8102           0 :             puts (" -> ???");
    8103             :           else
    8104             :             putchar_unlocked ('\n');
    8105           0 :           ++u;
    8106             :         }
    8107           0 :       while (readp < action_table_end);
    8108             :     }
    8109             : 
    8110           0 :   if (max_ar_filter > 0 && ttype_base != NULL)
    8111             :     {
    8112             :       unsigned char dsize;
    8113           0 :       puts ("\n TType table:");
    8114             : 
    8115             :       // XXX Not *4, size of encoding;
    8116             :       switch (ttype_encoding & 7)
    8117             :         {
    8118             :         case DW_EH_PE_udata2:
    8119             :         case DW_EH_PE_sdata2:
    8120             :           dsize = 2;
    8121             :           break;
    8122             :         case DW_EH_PE_udata4:
    8123             :         case DW_EH_PE_sdata4:
    8124             :           dsize = 4;
    8125             :           break;
    8126             :         case DW_EH_PE_udata8:
    8127             :         case DW_EH_PE_sdata8:
    8128             :           dsize = 8;
    8129             :           break;
    8130           0 :         default:
    8131           0 :           dsize = 0;
    8132           0 :           error (1, 0, gettext ("invalid TType encoding"));
    8133             :         }
    8134             : 
    8135           0 :       if (max_ar_filter
    8136           0 :           > (size_t) (ttype_base - (const unsigned char *) data->d_buf) / dsize)
    8137             :         goto invalid_data;
    8138             : 
    8139           0 :       readp = ttype_base - max_ar_filter * dsize;
    8140             :       do
    8141             :         {
    8142             :           uint64_t ttype;
    8143           0 :           readp = read_encoded (ttype_encoding, readp, ttype_base, &ttype,
    8144             :                                 dbg);
    8145           0 :           printf (" [%4u] %#" PRIx64 "\n", max_ar_filter--, ttype);
    8146             :         }
    8147           0 :       while (readp < ttype_base);
    8148             :     }
    8149             : }
    8150             : 
    8151             : /* Print the content of the '.gdb_index' section.
    8152             :    http://sourceware.org/gdb/current/onlinedocs/gdb/Index-Section-Format.html
    8153             : */
    8154             : static void
    8155           2 : print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
    8156             :                          Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
    8157             : {
    8158           6 :   printf (gettext ("\nGDB section [%2zu] '%s' at offset %#" PRIx64
    8159             :                    " contains %" PRId64 " bytes :\n"),
    8160             :           elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
    8161           2 :           (uint64_t) shdr->sh_offset, (uint64_t) shdr->sh_size);
    8162             : 
    8163           2 :   Elf_Data *data = elf_rawdata (scn, NULL);
    8164             : 
    8165           2 :   if (unlikely (data == NULL))
    8166             :     {
    8167           0 :       error (0, 0, gettext ("cannot get %s content: %s"),
    8168             :              ".gdb_index", elf_errmsg (-1));
    8169           0 :       return;
    8170             :     }
    8171             : 
    8172             :   // .gdb_index is always in little endian.
    8173           2 :   Dwarf dummy_dbg = { .other_byte_order = MY_ELFDATA != ELFDATA2LSB };
    8174           2 :   dbg = &dummy_dbg;
    8175             : 
    8176           2 :   const unsigned char *readp = data->d_buf;
    8177           2 :   const unsigned char *const dataend = readp + data->d_size;
    8178             : 
    8179           2 :   if (unlikely (readp + 4 > dataend))
    8180             :     {
    8181           0 :     invalid_data:
    8182           0 :       error (0, 0, gettext ("invalid data"));
    8183             :       return;
    8184             :     }
    8185             : 
    8186           2 :   int32_t vers = read_4ubyte_unaligned (dbg, readp);
    8187           4 :   printf (gettext (" Version:         %" PRId32 "\n"), vers);
    8188             : 
    8189             :   // The only difference between version 4 and version 5 is the
    8190             :   // hash used for generating the table.  Version 6 contains symbols
    8191             :   // for inlined functions, older versions didn't.  Version 7 adds
    8192             :   // symbol kinds.  Version 8 just indicates that it correctly includes
    8193             :   // TUs for symbols.
    8194           2 :   if (vers < 4 || vers > 8)
    8195             :     {
    8196           0 :       printf (gettext ("  unknown version, cannot parse section\n"));
    8197             :       return;
    8198             :     }
    8199             : 
    8200           2 :   readp += 4;
    8201           2 :   if (unlikely (readp + 4 > dataend))
    8202             :     goto invalid_data;
    8203             : 
    8204           2 :   uint32_t cu_off = read_4ubyte_unaligned (dbg, readp);
    8205           4 :   printf (gettext (" CU offset:       %#" PRIx32 "\n"), cu_off);
    8206             : 
    8207           2 :   readp += 4;
    8208           2 :   if (unlikely (readp + 4 > dataend))
    8209             :     goto invalid_data;
    8210             : 
    8211           2 :   uint32_t tu_off = read_4ubyte_unaligned (dbg, readp);
    8212           4 :   printf (gettext (" TU offset:       %#" PRIx32 "\n"), tu_off);
    8213             : 
    8214           2 :   readp += 4;
    8215           2 :   if (unlikely (readp + 4 > dataend))
    8216             :     goto invalid_data;
    8217             : 
    8218           2 :   uint32_t addr_off = read_4ubyte_unaligned (dbg, readp);
    8219           4 :   printf (gettext (" address offset:  %#" PRIx32 "\n"), addr_off);
    8220             : 
    8221           2 :   readp += 4;
    8222           2 :   if (unlikely (readp + 4 > dataend))
    8223             :     goto invalid_data;
    8224             : 
    8225           2 :   uint32_t sym_off = read_4ubyte_unaligned (dbg, readp);
    8226           4 :   printf (gettext (" symbol offset:   %#" PRIx32 "\n"), sym_off);
    8227             : 
    8228           2 :   readp += 4;
    8229           2 :   if (unlikely (readp + 4 > dataend))
    8230             :     goto invalid_data;
    8231             : 
    8232           2 :   uint32_t const_off = read_4ubyte_unaligned (dbg, readp);
    8233           4 :   printf (gettext (" constant offset: %#" PRIx32 "\n"), const_off);
    8234             : 
    8235           2 :   if (unlikely ((size_t) (dataend - (const unsigned char *) data->d_buf)
    8236             :                 < const_off))
    8237             :     goto invalid_data;
    8238             : 
    8239           2 :   readp = data->d_buf + cu_off;
    8240             : 
    8241           2 :   const unsigned char *nextp = data->d_buf + tu_off;
    8242           2 :   if (tu_off >= data->d_size)
    8243             :     goto invalid_data;
    8244             : 
    8245           2 :   size_t cu_nr = (nextp - readp) / 16;
    8246             : 
    8247           4 :   printf (gettext ("\n CU list at offset %#" PRIx32
    8248             :                    " contains %zu entries:\n"),
    8249             :           cu_off, cu_nr);
    8250             : 
    8251           2 :   size_t n = 0;
    8252           8 :   while (dataend - readp >= 16 && n < cu_nr)
    8253             :     {
    8254           4 :       uint64_t off = read_8ubyte_unaligned (dbg, readp);
    8255           4 :       readp += 8;
    8256             : 
    8257           4 :       uint64_t len = read_8ubyte_unaligned (dbg, readp);
    8258           4 :       readp += 8;
    8259             : 
    8260           4 :       printf (" [%4zu] start: %0#8" PRIx64
    8261             :               ", length: %5" PRIu64 "\n", n, off, len);
    8262           4 :       n++;
    8263             :     }
    8264             : 
    8265           2 :   readp = data->d_buf + tu_off;
    8266           2 :   nextp = data->d_buf + addr_off;
    8267           2 :   if (addr_off >= data->d_size)
    8268             :     goto invalid_data;
    8269             : 
    8270           2 :   size_t tu_nr = (nextp - readp) / 24;
    8271             : 
    8272           4 :   printf (gettext ("\n TU list at offset %#" PRIx32
    8273             :                    " contains %zu entries:\n"),
    8274             :           tu_off, tu_nr);
    8275             : 
    8276           2 :   n = 0;
    8277           6 :   while (dataend - readp >= 24 && n < tu_nr)
    8278             :     {
    8279           2 :       uint64_t off = read_8ubyte_unaligned (dbg, readp);
    8280           2 :       readp += 8;
    8281             : 
    8282           2 :       uint64_t type = read_8ubyte_unaligned (dbg, readp);
    8283           2 :       readp += 8;
    8284             : 
    8285           2 :       uint64_t sig = read_8ubyte_unaligned (dbg, readp);
    8286           2 :       readp += 8;
    8287             : 
    8288           2 :       printf (" [%4zu] CU offset: %5" PRId64
    8289             :               ", type offset: %5" PRId64
    8290             :               ", signature: %0#8" PRIx64 "\n", n, off, type, sig);
    8291           2 :       n++;
    8292             :     }
    8293             : 
    8294           2 :   readp = data->d_buf + addr_off;
    8295           2 :   nextp = data->d_buf + sym_off;
    8296           2 :   if (sym_off >= data->d_size)
    8297             :     goto invalid_data;
    8298             : 
    8299           2 :   size_t addr_nr = (nextp - readp) / 20;
    8300             : 
    8301           4 :   printf (gettext ("\n Address list at offset %#" PRIx32
    8302             :                    " contains %zu entries:\n"),
    8303             :           addr_off, addr_nr);
    8304             : 
    8305           2 :   n = 0;
    8306           8 :   while (dataend - readp >= 20 && n < addr_nr)
    8307             :     {
    8308           4 :       uint64_t low = read_8ubyte_unaligned (dbg, readp);
    8309           4 :       readp += 8;
    8310             : 
    8311           4 :       uint64_t high = read_8ubyte_unaligned (dbg, readp);
    8312           4 :       readp += 8;
    8313             : 
    8314           4 :       uint32_t idx = read_4ubyte_unaligned (dbg, readp);
    8315           4 :       readp += 4;
    8316             : 
    8317           4 :       char *l = format_dwarf_addr (dwflmod, 8, low, low);
    8318           4 :       char *h = format_dwarf_addr (dwflmod, 8, high - 1, high);
    8319           4 :       printf (" [%4zu] %s..%s, CU index: %5" PRId32 "\n",
    8320             :               n, l, h, idx);
    8321           4 :       free (l);
    8322           4 :       free (h);
    8323           4 :       n++;
    8324             :     }
    8325             : 
    8326           2 :   const unsigned char *const_start = data->d_buf + const_off;
    8327           2 :   if (const_off >= data->d_size)
    8328             :     goto invalid_data;
    8329             : 
    8330           2 :   readp = data->d_buf + sym_off;
    8331           2 :   nextp = const_start;
    8332           2 :   size_t sym_nr = (nextp - readp) / 8;
    8333             : 
    8334           4 :   printf (gettext ("\n Symbol table at offset %#" PRIx32
    8335             :                    " contains %zu slots:\n"),
    8336             :           addr_off, sym_nr);
    8337             : 
    8338           2 :   n = 0;
    8339        2052 :   while (dataend - readp >= 8 && n < sym_nr)
    8340             :     {
    8341        2048 :       uint32_t name = read_4ubyte_unaligned (dbg, readp);
    8342        2048 :       readp += 4;
    8343             : 
    8344        2048 :       uint32_t vector = read_4ubyte_unaligned (dbg, readp);
    8345        2048 :       readp += 4;
    8346             : 
    8347        2048 :       if (name != 0 || vector != 0)
    8348             :         {
    8349          14 :           const unsigned char *sym = const_start + name;
    8350          28 :           if (unlikely ((size_t) (dataend - const_start) < name
    8351             :                         || memchr (sym, '\0', dataend - sym) == NULL))
    8352             :             goto invalid_data;
    8353             : 
    8354          14 :           printf (" [%4zu] symbol: %s, CUs: ", n, sym);
    8355             : 
    8356          14 :           const unsigned char *readcus = const_start + vector;
    8357          14 :           if (unlikely ((size_t) (dataend - const_start) < vector))
    8358             :             goto invalid_data;
    8359          14 :           uint32_t cus = read_4ubyte_unaligned (dbg, readcus);
    8360          44 :           while (cus--)
    8361             :             {
    8362             :               uint32_t cu_kind, cu, kind;
    8363             :               bool is_static;
    8364          16 :               readcus += 4;
    8365          16 :               if (unlikely (readcus + 4 > dataend))
    8366             :                 goto invalid_data;
    8367          16 :               cu_kind = read_4ubyte_unaligned (dbg, readcus);
    8368          16 :               cu = cu_kind & ((1 << 24) - 1);
    8369          16 :               kind = (cu_kind >> 28) & 7;
    8370          16 :               is_static = cu_kind & (1U << 31);
    8371          16 :               if (cu > cu_nr - 1)
    8372           2 :                 printf ("%" PRId32 "T", cu - (uint32_t) cu_nr);
    8373             :               else
    8374             :                 printf ("%" PRId32, cu);
    8375          16 :               if (kind != 0)
    8376             :                 {
    8377           8 :                   printf (" (");
    8378           8 :                   switch (kind)
    8379             :                     {
    8380           3 :                     case 1:
    8381             :                       printf ("type");
    8382             :                       break;
    8383           2 :                     case 2:
    8384             :                       printf ("var");
    8385             :                       break;
    8386           3 :                     case 3:
    8387             :                       printf ("func");
    8388             :                       break;
    8389           0 :                     case 4:
    8390             :                       printf ("other");
    8391             :                       break;
    8392           0 :                     default:
    8393             :                       printf ("unknown-0x%" PRIx32, kind);
    8394             :                       break;
    8395             :                     }
    8396           8 :                   printf (":%c)", (is_static ? 'S' : 'G'));
    8397             :                 }
    8398          16 :               if (cus > 0)
    8399             :                 printf (", ");
    8400             :             }
    8401             :           printf ("\n");
    8402             :         }
    8403        2048 :       n++;
    8404             :     }
    8405             : }
    8406             : 
    8407             : static void
    8408          89 : print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
    8409             : {
    8410             :   /* Before we start the real work get a debug context descriptor.  */
    8411             :   Dwarf_Addr dwbias;
    8412          89 :   Dwarf *dbg = dwfl_module_getdwarf (dwflmod, &dwbias);
    8413         267 :   Dwarf dummy_dbg =
    8414             :     {
    8415          89 :       .elf = ebl->elf,
    8416          89 :       .other_byte_order = MY_ELFDATA != ehdr->e_ident[EI_DATA]
    8417             :     };
    8418          89 :   if (dbg == NULL)
    8419             :     {
    8420          20 :       if ((print_debug_sections & ~section_exception) != 0)
    8421           0 :         error (0, 0, gettext ("cannot get debug context descriptor: %s"),
    8422             :                dwfl_errmsg (-1));
    8423             :       dbg = &dummy_dbg;
    8424             :     }
    8425             : 
    8426             :   /* Get the section header string table index.  */
    8427             :   size_t shstrndx;
    8428          89 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    8429             :     error (EXIT_FAILURE, 0,
    8430           0 :            gettext ("cannot get section header string table index"));
    8431             : 
    8432             :   /* Look through all the sections for the debugging sections to print.  */
    8433             :   Elf_Scn *scn = NULL;
    8434        2871 :   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    8435             :     {
    8436             :       GElf_Shdr shdr_mem;
    8437        2782 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    8438             : 
    8439        2782 :       if (shdr != NULL && shdr->sh_type == SHT_PROGBITS)
    8440             :         {
    8441             :           static const struct
    8442             :           {
    8443             :             const char *name;
    8444             :             enum section_e bitmask;
    8445             :             void (*fp) (Dwfl_Module *, Ebl *,
    8446             :                         GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *);
    8447             :           } debug_sections[] =
    8448             :             {
    8449             : #define NEW_SECTION(name) \
    8450             :               { ".debug_" #name, section_##name, print_debug_##name##_section }
    8451             :               NEW_SECTION (abbrev),
    8452             :               NEW_SECTION (aranges),
    8453             :               NEW_SECTION (frame),
    8454             :               NEW_SECTION (info),
    8455             :               NEW_SECTION (types),
    8456             :               NEW_SECTION (line),
    8457             :               NEW_SECTION (loc),
    8458             :               NEW_SECTION (pubnames),
    8459             :               NEW_SECTION (str),
    8460             :               NEW_SECTION (macinfo),
    8461             :               NEW_SECTION (macro),
    8462             :               NEW_SECTION (ranges),
    8463             :               { ".eh_frame", section_frame | section_exception,
    8464             :                 print_debug_frame_section },
    8465             :               { ".eh_frame_hdr", section_frame | section_exception,
    8466             :                 print_debug_frame_hdr_section },
    8467             :               { ".gcc_except_table", section_frame | section_exception,
    8468             :                 print_debug_exception_table },
    8469             :               { ".gdb_index", section_gdb_index, print_gdb_index_section }
    8470             :             };
    8471        1331 :           const int ndebug_sections = (sizeof (debug_sections)
    8472             :                                        / sizeof (debug_sections[0]));
    8473        1331 :           const char *name = elf_strptr (ebl->elf, shstrndx,
    8474        1331 :                                          shdr->sh_name);
    8475        1331 :           if (name == NULL)
    8476           0 :             continue;
    8477             : 
    8478             :           int n;
    8479       15367 :           for (n = 0; n < ndebug_sections; ++n)
    8480       15955 :             if (strcmp (name, debug_sections[n].name) == 0
    8481       15429 :                 || (name[0] == '.' && name[1] == 'z'
    8482         358 :                     && debug_sections[n].name[1] == 'd'
    8483         358 :                     && strcmp (&name[2], &debug_sections[n].name[1]) == 0)
    8484             :                 )
    8485             :               {
    8486        1176 :                 if ((print_debug_sections | implicit_debug_sections)
    8487         588 :                     & debug_sections[n].bitmask)
    8488         324 :                   debug_sections[n].fp (dwflmod, ebl, ehdr, scn, shdr, dbg);
    8489             :                 break;
    8490             :               }
    8491             :         }
    8492             :     }
    8493             : 
    8494          89 :   reset_listptr (&known_loclistptr);
    8495          89 :   reset_listptr (&known_rangelistptr);
    8496          89 : }
    8497             : 
    8498             : 
    8499             : #define ITEM_INDENT             4
    8500             : #define WRAP_COLUMN             75
    8501             : 
    8502             : /* Print "NAME: FORMAT", wrapping when output text would make the line
    8503             :    exceed WRAP_COLUMN.  Unpadded numbers look better for the core items
    8504             :    but this function is also used for registers which should be printed
    8505             :    aligned.  Fortunately registers output uses fixed fields width (such
    8506             :    as %11d) for the alignment.
    8507             : 
    8508             :    Line breaks should not depend on the particular values although that
    8509             :    may happen in some cases of the core items.  */
    8510             : 
    8511             : static unsigned int
    8512             : __attribute__ ((format (printf, 6, 7)))
    8513         761 : print_core_item (unsigned int colno, char sep, unsigned int wrap,
    8514             :                  size_t name_width, const char *name, const char *format, ...)
    8515             : {
    8516         761 :   size_t len = strlen (name);
    8517         761 :   if (name_width < len)
    8518         368 :     name_width = len;
    8519             : 
    8520             :   char *out;
    8521             :   va_list ap;
    8522         761 :   va_start (ap, format);
    8523         761 :   int out_len = vasprintf (&out, format, ap);
    8524         761 :   va_end (ap);
    8525         761 :   if (out_len == -1)
    8526           0 :     error (EXIT_FAILURE, 0, _("memory exhausted"));
    8527             : 
    8528         761 :   size_t n = name_width + sizeof ": " - 1 + out_len;
    8529             : 
    8530         761 :   if (colno == 0)
    8531             :     {
    8532          48 :       printf ("%*s", ITEM_INDENT, "");
    8533          48 :       colno = ITEM_INDENT + n;
    8534             :     }
    8535         713 :   else if (colno + 2 + n < wrap)
    8536             :     {
    8537         866 :       printf ("%c ", sep);
    8538         433 :       colno += 2 + n;
    8539             :     }
    8540             :   else
    8541             :     {
    8542         280 :       printf ("\n%*s", ITEM_INDENT, "");
    8543         280 :       colno = ITEM_INDENT + n;
    8544             :     }
    8545             : 
    8546        1522 :   printf ("%s: %*s%s", name, (int) (name_width - len), "", out);
    8547             : 
    8548         761 :   free (out);
    8549             : 
    8550         761 :   return colno;
    8551             : }
    8552             : 
    8553             : static const void *
    8554         838 : convert (Elf *core, Elf_Type type, uint_fast16_t count,
    8555             :          void *value, const void *data, size_t size)
    8556             : {
    8557        1676 :   Elf_Data valuedata =
    8558             :     {
    8559             :       .d_type = type,
    8560             :       .d_buf = value,
    8561         838 :       .d_size = size ?: gelf_fsize (core, type, count, EV_CURRENT),
    8562             :       .d_version = EV_CURRENT,
    8563             :     };
    8564         838 :   Elf_Data indata =
    8565             :     {
    8566             :       .d_type = type,
    8567             :       .d_buf = (void *) data,
    8568             :       .d_size = valuedata.d_size,
    8569             :       .d_version = EV_CURRENT,
    8570             :     };
    8571             : 
    8572        1676 :   Elf_Data *d = (gelf_getclass (core) == ELFCLASS32
    8573        1676 :                  ? elf32_xlatetom : elf64_xlatetom)
    8574         838 :     (&valuedata, &indata, elf_getident (core, NULL)[EI_DATA]);
    8575         838 :   if (d == NULL)
    8576           0 :     error (EXIT_FAILURE, 0,
    8577           0 :            gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
    8578             : 
    8579         838 :   return data + indata.d_size;
    8580             : }
    8581             : 
    8582             : typedef uint8_t GElf_Byte;
    8583             : 
    8584             : static unsigned int
    8585         371 : handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
    8586             :                   unsigned int colno, size_t *repeated_size)
    8587             : {
    8588         371 :   uint_fast16_t count = item->count ?: 1;
    8589             :   /* Ebl_Core_Item count is always a small number.
    8590             :      Make sure the backend didn't put in some large bogus value.  */
    8591          56 :   assert (count < 128);
    8592             : 
    8593             : #define TYPES                                                                 \
    8594             :   DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8);                         \
    8595             :   DO_TYPE (HALF, Half, "0x%.4" PRIx16, "%" PRId16);                       \
    8596             :   DO_TYPE (WORD, Word, "0x%.8" PRIx32, "%" PRId32);                       \
    8597             :   DO_TYPE (SWORD, Sword, "%" PRId32, "%" PRId32);                         \
    8598             :   DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64);                            \
    8599             :   DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64)
    8600             : 
    8601             : #define DO_TYPE(NAME, Name, hex, dec) GElf_##Name Name
    8602             :   typedef union { TYPES; } value_t;
    8603         371 :   void *data = alloca (count * sizeof (value_t));
    8604             : #undef DO_TYPE
    8605             : 
    8606             : #define DO_TYPE(NAME, Name, hex, dec) \
    8607             :     GElf_##Name *value_##Name __attribute__((unused)) = data
    8608         371 :   TYPES;
    8609             : #undef DO_TYPE
    8610             : 
    8611         371 :   size_t size = gelf_fsize (core, item->type, count, EV_CURRENT);
    8612         371 :   size_t convsize = size;
    8613         371 :   if (repeated_size != NULL)
    8614             :     {
    8615           1 :       if (*repeated_size > size && (item->format == 'b' || item->format == 'B'))
    8616             :         {
    8617           0 :           data = alloca (*repeated_size);
    8618           0 :           count *= *repeated_size / size;
    8619           0 :           convsize = count * size;
    8620           0 :           *repeated_size -= convsize;
    8621             :         }
    8622           1 :       else if (item->count != 0 || item->format != '\n')
    8623           0 :         *repeated_size -= size;
    8624             :     }
    8625             : 
    8626         371 :   convert (core, item->type, count, data, desc + item->offset, convsize);
    8627             : 
    8628         371 :   Elf_Type type = item->type;
    8629         371 :   if (type == ELF_T_ADDR)
    8630           0 :     type = gelf_getclass (core) == ELFCLASS32 ? ELF_T_WORD : ELF_T_XWORD;
    8631             : 
    8632         371 :   switch (item->format)
    8633             :     {
    8634         175 :     case 'd':
    8635         175 :       assert (count == 1);
    8636         175 :       switch (type)
    8637             :         {
    8638             : #define DO_TYPE(NAME, Name, hex, dec)                                         \
    8639             :           case ELF_T_##NAME:                                                  \
    8640             :             colno = print_core_item (colno, ',', WRAP_COLUMN,                 \
    8641             :                                      0, item->name, dec, value_##Name[0]); \
    8642             :             break
    8643          24 :           TYPES;
    8644             : #undef DO_TYPE
    8645           0 :         default:
    8646           0 :           abort ();
    8647             :         }
    8648             :       break;
    8649             : 
    8650         109 :     case 'x':
    8651         109 :       assert (count == 1);
    8652         109 :       switch (type)
    8653             :         {
    8654             : #define DO_TYPE(NAME, Name, hex, dec)                                         \
    8655             :           case ELF_T_##NAME:                                                  \
    8656             :             colno = print_core_item (colno, ',', WRAP_COLUMN,                 \
    8657             :                                      0, item->name, hex, value_##Name[0]);      \
    8658             :             break
    8659           0 :           TYPES;
    8660             : #undef DO_TYPE
    8661           0 :         default:
    8662           0 :           abort ();
    8663             :         }
    8664             :       break;
    8665             : 
    8666          20 :     case 'b':
    8667             :     case 'B':
    8668          20 :       assert (size % sizeof (unsigned int) == 0);
    8669          20 :       unsigned int nbits = count * size * 8;
    8670          20 :       unsigned int pop = 0;
    8671          50 :       for (const unsigned int *i = data; (void *) i < data + count * size; ++i)
    8672          30 :         pop += __builtin_popcount (*i);
    8673          20 :       bool negate = pop > nbits / 2;
    8674          20 :       const unsigned int bias = item->format == 'b';
    8675             : 
    8676          40 :       {
    8677          20 :         char printed[(negate ? nbits - pop : pop) * 16 + 1];
    8678          20 :         char *p = printed;
    8679          20 :         *p = '\0';
    8680             : 
    8681             :         if (BYTE_ORDER != LITTLE_ENDIAN && size > sizeof (unsigned int))
    8682             :           {
    8683             :             assert (size == sizeof (unsigned int) * 2);
    8684             :             for (unsigned int *i = data;
    8685             :                  (void *) i < data + count * size; i += 2)
    8686             :               {
    8687             :                 unsigned int w = i[1];
    8688             :                 i[1] = i[0];
    8689             :                 i[0] = w;
    8690             :               }
    8691             :           }
    8692             : 
    8693          20 :         unsigned int lastbit = 0;
    8694          20 :         unsigned int run = 0;
    8695          70 :         for (const unsigned int *i = data;
    8696          30 :              (void *) i < data + count * size; ++i)
    8697             :           {
    8698          30 :             unsigned int bit = ((void *) i - data) * 8;
    8699          30 :             unsigned int w = negate ? ~*i : *i;
    8700          30 :             while (w != 0)
    8701             :               {
    8702             :                 /* Note that a right shift equal to (or greater than)
    8703             :                    the number of bits of w is undefined behaviour.  In
    8704             :                    particular when the least significant bit is bit 32
    8705             :                    (w = 0x8000000) then w >>= n is undefined.  So
    8706             :                    explicitly handle that case separately.  */
    8707           0 :                 unsigned int n = ffs (w);
    8708           0 :                 if (n < sizeof (w) * 8)
    8709           0 :                   w >>= n;
    8710             :                 else
    8711             :                   w = 0;
    8712           0 :                 bit += n;
    8713             : 
    8714           0 :                 if (lastbit != 0 && lastbit + 1 == bit)
    8715           0 :                   ++run;
    8716             :                 else
    8717             :                   {
    8718           0 :                     if (lastbit == 0)
    8719           0 :                       p += sprintf (p, "%u", bit - bias);
    8720           0 :                     else if (run == 0)
    8721           0 :                       p += sprintf (p, ",%u", bit - bias);
    8722             :                     else
    8723           0 :                       p += sprintf (p, "-%u,%u", lastbit - bias, bit - bias);
    8724             :                     run = 0;
    8725             :                   }
    8726             : 
    8727             :                 lastbit = bit;
    8728             :               }
    8729             :           }
    8730          20 :         if (lastbit > 0 && run > 0 && lastbit + 1 != nbits)
    8731           0 :           p += sprintf (p, "-%u", lastbit - bias);
    8732             : 
    8733          20 :         colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
    8734             :                                  negate ? "~<%s>" : "<%s>", printed);
    8735             :       }
    8736          20 :       break;
    8737             : 
    8738          40 :     case 'T':
    8739             :     case (char) ('T'|0x80):
    8740          40 :       assert (count == 2);
    8741             :       Dwarf_Word sec;
    8742             :       Dwarf_Word usec;
    8743          40 :       switch (type)
    8744             :         {
    8745             : #define DO_TYPE(NAME, Name, hex, dec)                                         \
    8746             :           case ELF_T_##NAME:                                                  \
    8747             :             sec = value_##Name[0];                                            \
    8748             :             usec = value_##Name[1];                                           \
    8749             :             break
    8750           0 :           TYPES;
    8751             : #undef DO_TYPE
    8752           0 :         default:
    8753           0 :           abort ();
    8754             :         }
    8755          40 :       if (unlikely (item->format == (char) ('T'|0x80)))
    8756             :         {
    8757             :           /* This is a hack for an ill-considered 64-bit ABI where
    8758             :              tv_usec is actually a 32-bit field with 32 bits of padding
    8759             :              rounding out struct timeval.  We've already converted it as
    8760             :              a 64-bit field.  For little-endian, this just means the
    8761             :              high half is the padding; it's presumably zero, but should
    8762             :              be ignored anyway.  For big-endian, it means the 32-bit
    8763             :              field went into the high half of USEC.  */
    8764             :           GElf_Ehdr ehdr_mem;
    8765           0 :           GElf_Ehdr *ehdr = gelf_getehdr (core, &ehdr_mem);
    8766           0 :           if (likely (ehdr->e_ident[EI_DATA] == ELFDATA2MSB))
    8767           0 :             usec >>= 32;
    8768             :           else
    8769           0 :             usec &= UINT32_MAX;
    8770             :         }
    8771          40 :       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
    8772             :                                "%" PRIu64 ".%.6" PRIu64, sec, usec);
    8773          40 :       break;
    8774             : 
    8775           8 :     case 'c':
    8776           8 :       assert (count == 1);
    8777           8 :       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
    8778           8 :                                "%c", value_Byte[0]);
    8779           8 :       break;
    8780             : 
    8781          16 :     case 's':
    8782          16 :       colno = print_core_item (colno, ',', WRAP_COLUMN, 0, item->name,
    8783             :                                "%.*s", (int) count, value_Byte);
    8784          16 :       break;
    8785             : 
    8786           1 :     case '\n':
    8787             :       /* This is a list of strings separated by '\n'.  */
    8788           1 :       assert (item->count == 0);
    8789           1 :       assert (repeated_size != NULL);
    8790           1 :       assert (item->name == NULL);
    8791           1 :       if (unlikely (item->offset >= *repeated_size))
    8792             :         break;
    8793             : 
    8794           1 :       const char *s = desc + item->offset;
    8795           1 :       size = *repeated_size - item->offset;
    8796           1 :       *repeated_size = 0;
    8797          49 :       while (size > 0)
    8798             :         {
    8799          48 :           const char *eol = memchr (s, '\n', size);
    8800          48 :           int len = size;
    8801          48 :           if (eol != NULL)
    8802          47 :             len = eol - s;
    8803          48 :           printf ("%*s%.*s\n", ITEM_INDENT, "", len, s);
    8804          48 :           if (eol == NULL)
    8805             :             break;
    8806          47 :           size -= eol + 1 - s;
    8807          47 :           s = eol + 1;
    8808             :         }
    8809             : 
    8810             :       colno = WRAP_COLUMN;
    8811             :       break;
    8812             : 
    8813             :     case 'h':
    8814             :       break;
    8815             : 
    8816           0 :     default:
    8817           0 :       error (0, 0, "XXX not handling format '%c' for %s",
    8818             :              item->format, item->name);
    8819             :       break;
    8820             :     }
    8821             : 
    8822             : #undef TYPES
    8823             : 
    8824         371 :   return colno;
    8825             : }
    8826             : 
    8827             : 
    8828             : /* Sort items by group, and by layout offset within each group.  */
    8829             : static int
    8830         827 : compare_core_items (const void *a, const void *b)
    8831             : {
    8832         827 :   const Ebl_Core_Item *const *p1 = a;
    8833         827 :   const Ebl_Core_Item *const *p2 = b;
    8834         827 :   const Ebl_Core_Item *item1 = *p1;
    8835         827 :   const Ebl_Core_Item *item2 = *p2;
    8836             : 
    8837         827 :   return ((item1->group == item2->group ? 0
    8838         827 :            : strcmp (item1->group, item2->group))
    8839         391 :           ?: (int) item1->offset - (int) item2->offset);
    8840             : }
    8841             : 
    8842             : /* Sort item groups by layout offset of the first item in the group.  */
    8843             : static int
    8844         126 : compare_core_item_groups (const void *a, const void *b)
    8845             : {
    8846         126 :   const Ebl_Core_Item *const *const *p1 = a;
    8847         126 :   const Ebl_Core_Item *const *const *p2 = b;
    8848         126 :   const Ebl_Core_Item *const *group1 = *p1;
    8849         126 :   const Ebl_Core_Item *const *group2 = *p2;
    8850         126 :   const Ebl_Core_Item *item1 = *group1;
    8851         126 :   const Ebl_Core_Item *item2 = *group2;
    8852             : 
    8853         126 :   return (int) item1->offset - (int) item2->offset;
    8854             : }
    8855             : 
    8856             : static unsigned int
    8857          35 : handle_core_items (Elf *core, const void *desc, size_t descsz,
    8858             :                    const Ebl_Core_Item *items, size_t nitems)
    8859             : {
    8860          35 :   if (nitems == 0)
    8861             :     return 0;
    8862          32 :   unsigned int colno = 0;
    8863             : 
    8864             :   /* FORMAT '\n' makes sense to be present only as a single item as it
    8865             :      processes all the data of a note.  FORMATs 'b' and 'B' have a special case
    8866             :      if present as a single item but they can be also processed with other
    8867             :      items below.  */
    8868          32 :   if (nitems == 1 && (items[0].format == '\n' || items[0].format == 'b'
    8869           8 :                       || items[0].format == 'B'))
    8870             :     {
    8871           1 :       assert (items[0].offset == 0);
    8872           1 :       size_t size = descsz;
    8873           1 :       colno = handle_core_item (core, items, desc, colno, &size);
    8874             :       /* If SIZE is not zero here there is some remaining data.  But we do not
    8875             :          know how to process it anyway.  */
    8876             :       return colno;
    8877             :     }
    8878         362 :   for (size_t i = 0; i < nitems; ++i)
    8879         362 :     assert (items[i].format != '\n');
    8880             : 
    8881             :   /* Sort to collect the groups together.  */
    8882          31 :   const Ebl_Core_Item *sorted_items[nitems];
    8883         393 :   for (size_t i = 0; i < nitems; ++i)
    8884         362 :     sorted_items[i] = &items[i];
    8885          31 :   qsort (sorted_items, nitems, sizeof sorted_items[0], &compare_core_items);
    8886             : 
    8887             :   /* Collect the unique groups and sort them.  */
    8888          31 :   const Ebl_Core_Item **groups[nitems];
    8889          31 :   groups[0] = &sorted_items[0];
    8890          31 :   size_t ngroups = 1;
    8891         362 :   for (size_t i = 1; i < nitems; ++i)
    8892         331 :     if (sorted_items[i]->group != sorted_items[i - 1]->group
    8893          68 :         && strcmp (sorted_items[i]->group, sorted_items[i - 1]->group))
    8894          68 :       groups[ngroups++] = &sorted_items[i];
    8895          31 :   qsort (groups, ngroups, sizeof groups[0], &compare_core_item_groups);
    8896             : 
    8897             :   /* Write out all the groups.  */
    8898          31 :   const void *last = desc;
    8899             :   do
    8900             :     {
    8901         134 :       for (size_t i = 0; i < ngroups; ++i)
    8902             :         {
    8903         572 :           for (const Ebl_Core_Item **item = groups[i];
    8904         471 :                (item < &sorted_items[nitems]
    8905         438 :                 && ((*item)->group == groups[i][0]->group
    8906          68 :                     || !strcmp ((*item)->group, groups[i][0]->group)));
    8907         370 :                ++item)
    8908         370 :             colno = handle_core_item (core, *item, desc, colno, NULL);
    8909             : 
    8910             :           /* Force a line break at the end of the group.  */
    8911         101 :           colno = WRAP_COLUMN;
    8912             :         }
    8913             : 
    8914          33 :       if (descsz == 0)
    8915             :         break;
    8916             : 
    8917             :       /* This set of items consumed a certain amount of the note's data.
    8918             :          If there is more data there, we have another unit of the same size.
    8919             :          Loop to print that out too.  */
    8920          19 :       const Ebl_Core_Item *item = &items[nitems - 1];
    8921          38 :       size_t eltsz = item->offset + gelf_fsize (core, item->type,
    8922          19 :                                                 item->count ?: 1, EV_CURRENT);
    8923             : 
    8924          19 :       int reps = -1;
    8925             :       do
    8926             :         {
    8927          19 :           ++reps;
    8928          19 :           desc += eltsz;
    8929          19 :           descsz -= eltsz;
    8930             :         }
    8931          19 :       while (descsz >= eltsz && !memcmp (desc, last, eltsz));
    8932             : 
    8933          19 :       if (reps == 1)
    8934             :         {
    8935             :           /* For just one repeat, print it unabridged twice.  */
    8936             :           desc -= eltsz;
    8937             :           descsz += eltsz;
    8938             :         }
    8939          19 :       else if (reps > 1)
    8940           0 :         printf (gettext ("\n%*s... <repeats %u more times> ..."),
    8941             :                 ITEM_INDENT, "", reps);
    8942             : 
    8943          19 :       last = desc;
    8944             :     }
    8945          19 :   while (descsz > 0);
    8946             : 
    8947             :   return colno;
    8948             : }
    8949             : 
    8950             : static unsigned int
    8951             : handle_bit_registers (const Ebl_Register_Location *regloc, const void *desc,
    8952             :                       unsigned int colno)
    8953             : {
    8954           0 :   desc += regloc->offset;
    8955             : 
    8956           0 :   abort ();                     /* XXX */
    8957             :   return colno;
    8958             : }
    8959             : 
    8960             : 
    8961             : static unsigned int
    8962         161 : handle_core_register (Ebl *ebl, Elf *core, int maxregname,
    8963             :                       const Ebl_Register_Location *regloc, const void *desc,
    8964             :                       unsigned int colno)
    8965             : {
    8966         161 :   if (regloc->bits % 8 != 0)
    8967           0 :     return handle_bit_registers (regloc, desc, colno);
    8968             : 
    8969         161 :   desc += regloc->offset;
    8970             : 
    8971         554 :   for (int reg = regloc->regno; reg < regloc->regno + regloc->count; ++reg)
    8972             :     {
    8973             :       char name[REGNAMESZ];
    8974             :       int bits;
    8975             :       int type;
    8976         393 :       register_info (ebl, reg, regloc, name, &bits, &type);
    8977             : 
    8978             : #define TYPES                                                                 \
    8979             :       BITS (8, BYTE, "%4" PRId8, "0x%.2" PRIx8);                          \
    8980             :       BITS (16, HALF, "%6" PRId16, "0x%.4" PRIx16);                       \
    8981             :       BITS (32, WORD, "%11" PRId32, " 0x%.8" PRIx32);                             \
    8982             :       BITS (64, XWORD, "%20" PRId64, "  0x%.16" PRIx64)
    8983             : 
    8984             : #define BITS(bits, xtype, sfmt, ufmt)                           \
    8985             :       uint##bits##_t b##bits; int##bits##_t b##bits##s
    8986             :       union { TYPES; uint64_t b128[2]; } value;
    8987             : #undef  BITS
    8988             : 
    8989         393 :       switch (type)
    8990             :         {
    8991         305 :         case DW_ATE_unsigned:
    8992             :         case DW_ATE_signed:
    8993             :         case DW_ATE_address:
    8994         305 :           switch (bits)
    8995             :             {
    8996             : #define BITS(bits, xtype, sfmt, ufmt)                                         \
    8997             :             case bits:                                                        \
    8998             :               desc = convert (core, ELF_T_##xtype, 1, &value, desc, 0);           \
    8999             :               if (type == DW_ATE_signed)                                      \
    9000             :                 colno = print_core_item (colno, ' ', WRAP_COLUMN,             \
    9001             :                                          maxregname, name,                    \
    9002             :                                          sfmt, value.b##bits##s);             \
    9003             :               else                                                            \
    9004             :                 colno = print_core_item (colno, ' ', WRAP_COLUMN,             \
    9005             :                                          maxregname, name,                    \
    9006             :                                          ufmt, value.b##bits);                \
    9007             :               break
    9008             : 
    9009           0 :             TYPES;
    9010             : 
    9011          48 :             case 128:
    9012          48 :               assert (type == DW_ATE_unsigned);
    9013          48 :               desc = convert (core, ELF_T_XWORD, 2, &value, desc, 0);
    9014          48 :               int be = elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB;
    9015          96 :               colno = print_core_item (colno, ' ', WRAP_COLUMN,
    9016             :                                        maxregname, name,
    9017             :                                        "0x%.16" PRIx64 "%.16" PRIx64,
    9018          48 :                                        value.b128[!be], value.b128[be]);
    9019          48 :               break;
    9020             : 
    9021           0 :             default:
    9022           0 :               abort ();
    9023             : #undef  BITS
    9024             :             }
    9025             :           break;
    9026             : 
    9027          88 :         default:
    9028             :           /* Print each byte in hex, the whole thing in native byte order.  */
    9029          88 :           assert (bits % 8 == 0);
    9030          88 :           const uint8_t *bytes = desc;
    9031          88 :           desc += bits / 8;
    9032          88 :           char hex[bits / 4 + 1];
    9033          88 :           hex[bits / 4] = '\0';
    9034          88 :           int incr = 1;
    9035          88 :           if (elf_getident (core, NULL)[EI_DATA] == ELFDATA2LSB)
    9036             :             {
    9037          48 :               bytes += bits / 8 - 1;
    9038          48 :               incr = -1;
    9039             :             }
    9040          88 :           size_t idx = 0;
    9041         872 :           for (char *h = hex; bits > 0; bits -= 8, idx += incr)
    9042             :             {
    9043         784 :               *h++ = "0123456789abcdef"[bytes[idx] >> 4];
    9044         784 :               *h++ = "0123456789abcdef"[bytes[idx] & 0xf];
    9045             :             }
    9046          88 :           colno = print_core_item (colno, ' ', WRAP_COLUMN,
    9047             :                                    maxregname, name, "0x%s", hex);
    9048             :           break;
    9049             :         }
    9050         393 :       desc += regloc->pad;
    9051             : 
    9052             : #undef TYPES
    9053             :     }
    9054             : 
    9055             :   return colno;
    9056             : }
    9057             : 
    9058             : 
    9059             : struct register_info
    9060             : {
    9061             :   const Ebl_Register_Location *regloc;
    9062             :   const char *set;
    9063             :   char name[REGNAMESZ];
    9064             :   int regno;
    9065             :   int bits;
    9066             :   int type;
    9067             : };
    9068             : 
    9069             : static int
    9070             : register_bitpos (const struct register_info *r)
    9071             : {
    9072        1916 :   return (r->regloc->offset * 8
    9073        3832 :           + ((r->regno - r->regloc->regno)
    9074        1916 :              * (r->regloc->bits + r->regloc->pad * 8)));
    9075             : }
    9076             : 
    9077             : static int
    9078         987 : compare_sets_by_info (const struct register_info *r1,
    9079             :                       const struct register_info *r2)
    9080             : {
    9081         987 :   return ((int) r2->bits - (int) r1->bits
    9082        2903 :           ?: register_bitpos (r1) - register_bitpos (r2));
    9083             : }
    9084             : 
    9085             : /* Sort registers by set, and by size and layout offset within each set.  */
    9086             : static int
    9087        4489 : compare_registers (const void *a, const void *b)
    9088             : {
    9089        4489 :   const struct register_info *r1 = a;
    9090        4489 :   const struct register_info *r2 = b;
    9091             : 
    9092             :   /* Unused elements sort last.  */
    9093        4489 :   if (r1->regloc == NULL)
    9094        3278 :     return r2->regloc == NULL ? 0 : 1;
    9095        1211 :   if (r2->regloc == NULL)
    9096             :     return -1;
    9097             : 
    9098        1046 :   return ((r1->set == r2->set ? 0 : strcmp (r1->set, r2->set))
    9099          79 :           ?: compare_sets_by_info (r1, r2));
    9100             : }
    9101             : 
    9102             : /* Sort register sets by layout offset of the first register in the set.  */
    9103             : static int
    9104          20 : compare_register_sets (const void *a, const void *b)
    9105             : {
    9106          20 :   const struct register_info *const *p1 = a;
    9107          20 :   const struct register_info *const *p2 = b;
    9108          20 :   return compare_sets_by_info (*p1, *p2);
    9109             : }
    9110             : 
    9111             : static unsigned int
    9112          35 : handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
    9113             :                        const Ebl_Register_Location *reglocs, size_t nregloc)
    9114             : {
    9115          35 :   if (nregloc == 0)
    9116             :     return 0;
    9117             : 
    9118          17 :   ssize_t maxnreg = ebl_register_info (ebl, 0, NULL, 0, NULL, NULL, NULL, NULL);
    9119          17 :   if (maxnreg <= 0)
    9120             :     {
    9121           0 :       for (size_t i = 0; i < nregloc; ++i)
    9122           0 :         if (maxnreg < reglocs[i].regno + reglocs[i].count)
    9123           0 :           maxnreg = reglocs[i].regno + reglocs[i].count;
    9124           0 :       assert (maxnreg > 0);
    9125             :     }
    9126             : 
    9127          17 :   struct register_info regs[maxnreg];
    9128          34 :   memset (regs, 0, sizeof regs);
    9129             : 
    9130             :   /* Sort to collect the sets together.  */
    9131          17 :   int maxreg = 0;
    9132         178 :   for (size_t i = 0; i < nregloc; ++i)
    9133         715 :     for (int reg = reglocs[i].regno;
    9134         554 :          reg < reglocs[i].regno + reglocs[i].count;
    9135         393 :          ++reg)
    9136             :       {
    9137         393 :         assert (reg < maxnreg);
    9138         393 :         if (reg > maxreg)
    9139         199 :           maxreg = reg;
    9140         393 :         struct register_info *info = &regs[reg];
    9141         393 :         info->regloc = &reglocs[i];
    9142         393 :         info->regno = reg;
    9143         786 :         info->set = register_info (ebl, reg, &reglocs[i],
    9144         393 :                                    info->name, &info->bits, &info->type);
    9145             :       }
    9146          17 :   qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers);
    9147             : 
    9148             :   /* Collect the unique sets and sort them.  */
    9149         802 :   inline bool same_set (const struct register_info *a,
    9150             :                         const struct register_info *b)
    9151             :   {
    9152        1604 :     return (a < &regs[maxnreg] && a->regloc != NULL
    9153         802 :             && b < &regs[maxnreg] && b->regloc != NULL
    9154         785 :             && a->bits == b->bits
    9155        1569 :             && (a->set == b->set || !strcmp (a->set, b->set)));
    9156             :   }
    9157          17 :   struct register_info *sets[maxreg + 1];
    9158          17 :   sets[0] = &regs[0];
    9159          17 :   size_t nsets = 1;
    9160        1247 :   for (int i = 1; i <= maxreg; ++i)
    9161        1230 :     if (regs[i].regloc != NULL && !same_set (&regs[i], &regs[i - 1]))
    9162          16 :       sets[nsets++] = &regs[i];
    9163          17 :   qsort (sets, nsets, sizeof sets[0], &compare_register_sets);
    9164             : 
    9165             :   /* Write out all the sets.  */
    9166          17 :   unsigned int colno = 0;
    9167          50 :   for (size_t i = 0; i < nsets; ++i)
    9168             :     {
    9169             :       /* Find the longest name of a register in this set.  */
    9170          33 :       size_t maxname = 0;
    9171             :       const struct register_info *end;
    9172         426 :       for (end = sets[i]; same_set (sets[i], end); ++end)
    9173             :         {
    9174         393 :           size_t len = strlen (end->name);
    9175         393 :           if (len > maxname)
    9176          50 :             maxname = len;
    9177             :         }
    9178             : 
    9179         194 :       for (const struct register_info *reg = sets[i];
    9180             :            reg < end;
    9181         161 :            reg += reg->regloc->count ?: 1)
    9182         161 :         colno = handle_core_register (ebl, core, maxname,
    9183             :                                       reg->regloc, desc, colno);
    9184             : 
    9185             :       /* Force a line break at the end of the group.  */
    9186          33 :       colno = WRAP_COLUMN;
    9187             :     }
    9188             : 
    9189             :   return colno;
    9190             : }
    9191             : 
    9192             : static void
    9193           8 : handle_auxv_note (Ebl *ebl, Elf *core, GElf_Word descsz, GElf_Off desc_pos)
    9194             : {
    9195           8 :   Elf_Data *data = elf_getdata_rawchunk (core, desc_pos, descsz, ELF_T_AUXV);
    9196           8 :   if (data == NULL)
    9197           0 :   elf_error:
    9198           0 :     error (EXIT_FAILURE, 0,
    9199           0 :            gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
    9200             : 
    9201           8 :   const size_t nauxv = descsz / gelf_fsize (core, ELF_T_AUXV, 1, EV_CURRENT);
    9202         158 :   for (size_t i = 0; i < nauxv; ++i)
    9203             :     {
    9204             :       GElf_auxv_t av_mem;
    9205         150 :       GElf_auxv_t *av = gelf_getauxv (data, i, &av_mem);
    9206         150 :       if (av == NULL)
    9207             :         goto elf_error;
    9208             : 
    9209             :       const char *name;
    9210             :       const char *fmt;
    9211         150 :       if (ebl_auxv_info (ebl, av->a_type, &name, &fmt) == 0)
    9212             :         {
    9213             :           /* Unknown type.  */
    9214           0 :           if (av->a_un.a_val == 0)
    9215           0 :             printf ("    %" PRIu64 "\n", av->a_type);
    9216             :           else
    9217           0 :             printf ("    %" PRIu64 ": %#" PRIx64 "\n",
    9218             :                     av->a_type, av->a_un.a_val);
    9219             :         }
    9220             :       else
    9221         150 :         switch (fmt[0])
    9222             :           {
    9223           8 :           case '\0':            /* Normally zero.  */
    9224           8 :             if (av->a_un.a_val == 0)
    9225             :               {
    9226           8 :                 printf ("    %s\n", name);
    9227             :                 break;
    9228             :               }
    9229             :             /* Fall through */
    9230             :           case 'x':             /* hex */
    9231             :           case 'p':             /* address */
    9232             :           case 's':             /* address of string */
    9233          66 :             printf ("    %s: %#" PRIx64 "\n", name, av->a_un.a_val);
    9234             :             break;
    9235          72 :           case 'u':
    9236          72 :             printf ("    %s: %" PRIu64 "\n", name, av->a_un.a_val);
    9237             :             break;
    9238           0 :           case 'd':
    9239           0 :             printf ("    %s: %" PRId64 "\n", name, av->a_un.a_val);
    9240             :             break;
    9241             : 
    9242           4 :           case 'b':
    9243           8 :             printf ("    %s: %#" PRIx64 "  ", name, av->a_un.a_val);
    9244           4 :             GElf_Xword bit = 1;
    9245           4 :             const char *pfx = "<";
    9246         110 :             for (const char *p = fmt + 1; *p != 0; p = strchr (p, '\0') + 1)
    9247             :               {
    9248         106 :                 if (av->a_un.a_val & bit)
    9249             :                   {
    9250          77 :                     printf ("%s%s", pfx, p);
    9251          77 :                     pfx = " ";
    9252             :                   }
    9253         106 :                 bit <<= 1;
    9254             :               }
    9255             :             printf (">\n");
    9256             :             break;
    9257             : 
    9258           0 :           default:
    9259           0 :             abort ();
    9260             :           }
    9261             :     }
    9262           8 : }
    9263             : 
    9264             : static bool
    9265             : buf_has_data (unsigned char const *ptr, unsigned char const *end, size_t sz)
    9266             : {
    9267         162 :   return ptr < end && (size_t) (end - ptr) >= sz;
    9268             : }
    9269             : 
    9270             : static bool
    9271          15 : buf_read_int (Elf *core, unsigned char const **ptrp, unsigned char const *end,
    9272             :               int *retp)
    9273             : {
    9274          30 :   if (! buf_has_data (*ptrp, end, 4))
    9275             :     return false;
    9276             : 
    9277          15 :   *ptrp = convert (core, ELF_T_WORD, 1, retp, *ptrp, 4);
    9278          15 :   return true;
    9279             : }
    9280             : 
    9281             : static bool
    9282         147 : buf_read_ulong (Elf *core, unsigned char const **ptrp, unsigned char const *end,
    9283             :                 uint64_t *retp)
    9284             : {
    9285         147 :   size_t sz = gelf_fsize (core, ELF_T_ADDR, 1, EV_CURRENT);
    9286         294 :   if (! buf_has_data (*ptrp, end, sz))
    9287             :     return false;
    9288             : 
    9289             :   union
    9290             :   {
    9291             :     uint64_t u64;
    9292             :     uint32_t u32;
    9293             :   } u;
    9294             : 
    9295         147 :   *ptrp = convert (core, ELF_T_ADDR, 1, &u, *ptrp, sz);
    9296             : 
    9297         147 :   if (sz == 4)
    9298          93 :     *retp = u.u32;
    9299             :   else
    9300          54 :     *retp = u.u64;
    9301             :   return true;
    9302             : }
    9303             : 
    9304             : static void
    9305           5 : handle_siginfo_note (Elf *core, GElf_Word descsz, GElf_Off desc_pos)
    9306             : {
    9307           5 :   Elf_Data *data = elf_getdata_rawchunk (core, desc_pos, descsz, ELF_T_BYTE);
    9308           5 :   if (data == NULL)
    9309           0 :     error (EXIT_FAILURE, 0,
    9310           0 :            gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
    9311             : 
    9312           5 :   unsigned char const *ptr = data->d_buf;
    9313           5 :   unsigned char const *const end = data->d_buf + data->d_size;
    9314             : 
    9315             :   /* Siginfo head is three ints: signal number, error number, origin
    9316             :      code.  */
    9317             :   int si_signo, si_errno, si_code;
    9318           5 :   if (! buf_read_int (core, &ptr, end, &si_signo)
    9319           5 :       || ! buf_read_int (core, &ptr, end, &si_errno)
    9320           5 :       || ! buf_read_int (core, &ptr, end, &si_code))
    9321             :     {
    9322           0 :     fail:
    9323           0 :       printf ("    Not enough data in NT_SIGINFO note.\n");
    9324           0 :       return;
    9325             :     }
    9326             : 
    9327             :   /* Next is a pointer-aligned union of structures.  On 64-bit
    9328             :      machines, that implies a word of padding.  */
    9329           5 :   if (gelf_getclass (core) == ELFCLASS64)
    9330           2 :     ptr += 4;
    9331             : 
    9332          10 :   printf ("    si_signo: %d, si_errno: %d, si_code: %d\n",
    9333             :           si_signo, si_errno, si_code);
    9334             : 
    9335           5 :   if (si_code > 0)
    9336           5 :     switch (si_signo)
    9337             :       {
    9338           5 :       case SIGILL:
    9339             :       case SIGFPE:
    9340             :       case SIGSEGV:
    9341             :       case SIGBUS:
    9342             :         {
    9343             :           uint64_t addr;
    9344           5 :           if (! buf_read_ulong (core, &ptr, end, &addr))
    9345             :             goto fail;
    9346          10 :           printf ("    fault address: %#" PRIx64 "\n", addr);
    9347           5 :           break;
    9348             :         }
    9349             :       default:
    9350             :         ;
    9351             :       }
    9352           0 :   else if (si_code == SI_USER)
    9353             :     {
    9354             :       int pid, uid;
    9355           0 :       if (! buf_read_int (core, &ptr, end, &pid)
    9356           0 :           || ! buf_read_int (core, &ptr, end, &uid))
    9357             :         goto fail;
    9358           0 :       printf ("    sender PID: %d, sender UID: %d\n", pid, uid);
    9359             :     }
    9360             : }
    9361             : 
    9362             : static void
    9363           5 : handle_file_note (Elf *core, GElf_Word descsz, GElf_Off desc_pos)
    9364             : {
    9365           5 :   Elf_Data *data = elf_getdata_rawchunk (core, desc_pos, descsz, ELF_T_BYTE);
    9366           5 :   if (data == NULL)
    9367           0 :     error (EXIT_FAILURE, 0,
    9368           0 :            gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
    9369             : 
    9370           5 :   unsigned char const *ptr = data->d_buf;
    9371           5 :   unsigned char const *const end = data->d_buf + data->d_size;
    9372             : 
    9373             :   uint64_t count, page_size;
    9374           5 :   if (! buf_read_ulong (core, &ptr, end, &count)
    9375           5 :       || ! buf_read_ulong (core, &ptr, end, &page_size))
    9376             :     {
    9377           0 :     fail:
    9378           0 :       printf ("    Not enough data in NT_FILE note.\n");
    9379           0 :       return;
    9380             :     }
    9381             : 
    9382           5 :   size_t addrsize = gelf_fsize (core, ELF_T_ADDR, 1, EV_CURRENT);
    9383           5 :   uint64_t maxcount = (size_t) (end - ptr) / (3 * addrsize);
    9384           5 :   if (count > maxcount)
    9385             :     goto fail;
    9386             : 
    9387             :   /* Where file names are stored.  */
    9388           5 :   unsigned char const *const fstart = ptr + 3 * count * addrsize;
    9389           5 :   char const *fptr = (char *) fstart;
    9390             : 
    9391          10 :   printf ("    %" PRId64 " files:\n", count);
    9392          49 :   for (uint64_t i = 0; i < count; ++i)
    9393             :     {
    9394             :       uint64_t mstart, mend, moffset;
    9395          44 :       if (! buf_read_ulong (core, &ptr, fstart, &mstart)
    9396          44 :           || ! buf_read_ulong (core, &ptr, fstart, &mend)
    9397          44 :           || ! buf_read_ulong (core, &ptr, fstart, &moffset))
    9398             :         goto fail;
    9399             : 
    9400          44 :       const char *fnext = memchr (fptr, '\0', (char *) end - fptr);
    9401          44 :       if (fnext == NULL)
    9402             :         goto fail;
    9403             : 
    9404          88 :       int ct = printf ("      %08" PRIx64 "-%08" PRIx64
    9405             :                        " %08" PRIx64 " %" PRId64,
    9406             :                        mstart, mend, moffset * page_size, mend - mstart);
    9407          88 :       printf ("%*s%s\n", ct > 50 ? 3 : 53 - ct, "", fptr);
    9408             : 
    9409          44 :       fptr = fnext + 1;
    9410             :     }
    9411             : }
    9412             : 
    9413             : static void
    9414          36 : handle_core_note (Ebl *ebl, const GElf_Nhdr *nhdr,
    9415             :                   const char *name, const void *desc)
    9416             : {
    9417             :   GElf_Word regs_offset;
    9418             :   size_t nregloc;
    9419             :   const Ebl_Register_Location *reglocs;
    9420             :   size_t nitems;
    9421             :   const Ebl_Core_Item *items;
    9422             : 
    9423          36 :   if (! ebl_core_note (ebl, nhdr, name,
    9424             :                        &regs_offset, &nregloc, &reglocs, &nitems, &items))
    9425           1 :     return;
    9426             : 
    9427             :   /* Pass 0 for DESCSZ when there are registers in the note,
    9428             :      so that the ITEMS array does not describe the whole thing.
    9429             :      For non-register notes, the actual descsz might be a multiple
    9430             :      of the unit size, not just exactly the unit size.  */
    9431          88 :   unsigned int colno = handle_core_items (ebl->elf, desc,
    9432          53 :                                           nregloc == 0 ? nhdr->n_descsz : 0,
    9433             :                                           items, nitems);
    9434          35 :   if (colno != 0)
    9435             :     putchar_unlocked ('\n');
    9436             : 
    9437          35 :   colno = handle_core_registers (ebl, ebl->elf, desc + regs_offset,
    9438             :                                  reglocs, nregloc);
    9439          35 :   if (colno != 0)
    9440             :     putchar_unlocked ('\n');
    9441             : }
    9442             : 
    9443             : static void
    9444          42 : handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
    9445             :                    GElf_Off start, Elf_Data *data)
    9446             : {
    9447          42 :   fputs_unlocked (gettext ("  Owner          Data size  Type\n"), stdout);
    9448             : 
    9449          42 :   if (data == NULL)
    9450             :     goto bad_note;
    9451             : 
    9452             :   size_t offset = 0;
    9453             :   GElf_Nhdr nhdr;
    9454             :   size_t name_offset;
    9455             :   size_t desc_offset;
    9456         130 :   while (offset < data->d_size
    9457          88 :          && (offset = gelf_getnote (data, offset,
    9458             :                                     &nhdr, &name_offset, &desc_offset)) > 0)
    9459             :     {
    9460          88 :       const char *name = nhdr.n_namesz == 0 ? "" : data->d_buf + name_offset;
    9461          88 :       const char *desc = data->d_buf + desc_offset;
    9462             : 
    9463             :       char buf[100];
    9464             :       char buf2[100];
    9465         352 :       printf (gettext ("  %-13.*s  %9" PRId32 "  %s\n"),
    9466          88 :               (int) nhdr.n_namesz, name, nhdr.n_descsz,
    9467          88 :               ehdr->e_type == ET_CORE
    9468          54 :               ? ebl_core_note_type_name (ebl, nhdr.n_type,
    9469             :                                          buf, sizeof (buf))
    9470          34 :               : ebl_object_note_type_name (ebl, name, nhdr.n_type,
    9471             :                                            buf2, sizeof (buf2)));
    9472             : 
    9473             :       /* Filter out invalid entries.  */
    9474             :       if (memchr (name, '\0', nhdr.n_namesz) != NULL
    9475             :           /* XXX For now help broken Linux kernels.  */
    9476             :           || 1)
    9477             :         {
    9478          88 :           if (ehdr->e_type == ET_CORE)
    9479             :             {
    9480          54 :               if (nhdr.n_type == NT_AUXV
    9481           8 :                   && (nhdr.n_namesz == 4 /* Broken old Linux kernels.  */
    9482           8 :                       || (nhdr.n_namesz == 5 && name[4] == '\0'))
    9483           8 :                   && !memcmp (name, "CORE", 4))
    9484           8 :                 handle_auxv_note (ebl, ebl->elf, nhdr.n_descsz,
    9485             :                                   start + desc_offset);
    9486          46 :               else if (nhdr.n_namesz == 5 && strcmp (name, "CORE") == 0)
    9487          34 :                 switch (nhdr.n_type)
    9488             :                   {
    9489           5 :                   case NT_SIGINFO:
    9490           5 :                     handle_siginfo_note (ebl->elf, nhdr.n_descsz,
    9491             :                                          start + desc_offset);
    9492             :                     break;
    9493             : 
    9494           5 :                   case NT_FILE:
    9495           5 :                     handle_file_note (ebl->elf, nhdr.n_descsz,
    9496             :                                       start + desc_offset);
    9497             :                     break;
    9498             : 
    9499          24 :                   default:
    9500          24 :                     handle_core_note (ebl, &nhdr, name, desc);
    9501             :                   }
    9502             :               else
    9503          12 :                 handle_core_note (ebl, &nhdr, name, desc);
    9504             :             }
    9505             :           else
    9506          34 :             ebl_object_note (ebl, name, nhdr.n_type, nhdr.n_descsz, desc);
    9507             :         }
    9508             :     }
    9509             : 
    9510          42 :   if (offset == data->d_size)
    9511          42 :     return;
    9512             : 
    9513           0 :  bad_note:
    9514           0 :   error (EXIT_FAILURE, 0,
    9515           0 :          gettext ("cannot get content of note section: %s"),
    9516             :          elf_errmsg (-1));
    9517             : }
    9518             : 
    9519             : static void
    9520          42 : handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
    9521             : {
    9522             :   /* If we have section headers, just look for SHT_NOTE sections.
    9523             :      In a debuginfo file, the program headers are not reliable.  */
    9524          42 :   if (shnum != 0)
    9525             :     {
    9526             :       /* Get the section header string table index.  */
    9527             :       size_t shstrndx;
    9528          33 :       if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
    9529             :         error (EXIT_FAILURE, 0,
    9530           0 :                gettext ("cannot get section header string table index"));
    9531             : 
    9532             :       Elf_Scn *scn = NULL;
    9533         919 :       while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    9534             :         {
    9535             :           GElf_Shdr shdr_mem;
    9536         886 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    9537             : 
    9538         886 :           if (shdr == NULL || shdr->sh_type != SHT_NOTE)
    9539             :             /* Not what we are looking for.  */
    9540         853 :             continue;
    9541             : 
    9542          99 :           printf (gettext ("\
    9543             : \nNote section [%2zu] '%s' of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"),
    9544             :                   elf_ndxscn (scn),
    9545          33 :                   elf_strptr (ebl->elf, shstrndx, shdr->sh_name),
    9546             :                   shdr->sh_size, shdr->sh_offset);
    9547             : 
    9548          33 :           handle_notes_data (ebl, ehdr, shdr->sh_offset,
    9549             :                              elf_getdata (scn, NULL));
    9550             :         }
    9551             :       return;
    9552             :     }
    9553             : 
    9554             :   /* We have to look through the program header to find the note
    9555             :      sections.  There can be more than one.  */
    9556         102 :   for (size_t cnt = 0; cnt < phnum; ++cnt)
    9557             :     {
    9558             :       GElf_Phdr mem;
    9559         102 :       GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem);
    9560             : 
    9561         102 :       if (phdr == NULL || phdr->p_type != PT_NOTE)
    9562             :         /* Not what we are looking for.  */
    9563          93 :         continue;
    9564             : 
    9565          18 :       printf (gettext ("\
    9566             : \nNote segment of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"),
    9567             :               phdr->p_filesz, phdr->p_offset);
    9568             : 
    9569          18 :       handle_notes_data (ebl, ehdr, phdr->p_offset,
    9570             :                          elf_getdata_rawchunk (ebl->elf,
    9571           9 :                                                phdr->p_offset, phdr->p_filesz,
    9572             :                                                ELF_T_NHDR));
    9573             :     }
    9574             : }
    9575             : 
    9576             : 
    9577             : static void
    9578           5 : hex_dump (const uint8_t *data, size_t len)
    9579             : {
    9580           5 :   size_t pos = 0;
    9581          31 :   while (pos < len)
    9582             :     {
    9583          21 :       printf ("  0x%08zx ", pos);
    9584             : 
    9585          21 :       const size_t chunk = MIN (len - pos, 16);
    9586             : 
    9587         342 :       for (size_t i = 0; i < chunk; ++i)
    9588         321 :         if (i % 4 == 3)
    9589          80 :           printf ("%02x ", data[pos + i]);
    9590             :         else
    9591         241 :           printf ("%02x", data[pos + i]);
    9592             : 
    9593          21 :       if (chunk < 16)
    9594           1 :         printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk + 3) / 4), "");
    9595             : 
    9596         321 :       for (size_t i = 0; i < chunk; ++i)
    9597             :         {
    9598         321 :           unsigned char b = data[pos + i];
    9599         642 :           printf ("%c", isprint (b) ? b : '.');
    9600             :         }
    9601             : 
    9602          21 :       putchar ('\n');
    9603          21 :       pos += chunk;
    9604             :     }
    9605           5 : }
    9606             : 
    9607             : static void
    9608           5 : dump_data_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
    9609             : {
    9610           5 :   if (shdr->sh_size == 0 || shdr->sh_type == SHT_NOBITS)
    9611           0 :     printf (gettext ("\nSection [%zu] '%s' has no data to dump.\n"),
    9612             :             elf_ndxscn (scn), name);
    9613             :   else
    9614             :     {
    9615           5 :       if (print_decompress)
    9616             :         {
    9617             :           /* We try to decompress the section, but keep the old shdr around
    9618             :              so we can show both the original shdr size and the uncompressed
    9619             :              data size.   */
    9620           4 :           if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    9621             :             {
    9622           2 :               if (elf_compress (scn, 0, 0) < 0)
    9623           0 :                 printf ("WARNING: %s [%zd]\n",
    9624             :                         gettext ("Couldn't uncompress section"),
    9625             :                         elf_ndxscn (scn));
    9626             :             }
    9627           2 :           else if (strncmp (name, ".zdebug", strlen (".zdebug")) == 0)
    9628             :             {
    9629           2 :               if (elf_compress_gnu (scn, 0, 0) < 0)
    9630           0 :                 printf ("WARNING: %s [%zd]\n",
    9631             :                         gettext ("Couldn't uncompress section"),
    9632             :                         elf_ndxscn (scn));
    9633             :             }
    9634             :         }
    9635             : 
    9636           5 :       Elf_Data *data = elf_rawdata (scn, NULL);
    9637           5 :       if (data == NULL)
    9638           0 :         error (0, 0, gettext ("cannot get data for section [%zu] '%s': %s"),
    9639             :                elf_ndxscn (scn), name, elf_errmsg (-1));
    9640             :       else
    9641             :         {
    9642           5 :           if (data->d_size == shdr->sh_size)
    9643           1 :             printf (gettext ("\nHex dump of section [%zu] '%s', %" PRIu64
    9644             :                              " bytes at offset %#0" PRIx64 ":\n"),
    9645             :                     elf_ndxscn (scn), name,
    9646             :                     shdr->sh_size, shdr->sh_offset);
    9647             :           else
    9648           4 :             printf (gettext ("\nHex dump of section [%zu] '%s', %" PRIu64
    9649             :                              " bytes (%zd uncompressed) at offset %#0"
    9650             :                              PRIx64 ":\n"),
    9651             :                     elf_ndxscn (scn), name,
    9652             :                     shdr->sh_size, data->d_size, shdr->sh_offset);
    9653           5 :           hex_dump (data->d_buf, data->d_size);
    9654             :         }
    9655             :     }
    9656           5 : }
    9657             : 
    9658             : static void
    9659          75 : print_string_section (Elf_Scn *scn, const GElf_Shdr *shdr, const char *name)
    9660             : {
    9661          75 :   if (shdr->sh_size == 0 || shdr->sh_type == SHT_NOBITS)
    9662           0 :     printf (gettext ("\nSection [%zu] '%s' has no strings to dump.\n"),
    9663             :             elf_ndxscn (scn), name);
    9664             :   else
    9665             :     {
    9666          75 :       if (print_decompress)
    9667             :         {
    9668             :           /* We try to decompress the section, but keep the old shdr around
    9669             :              so we can show both the original shdr size and the uncompressed
    9670             :              data size.  */
    9671           1 :           if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    9672             :             {
    9673           0 :               if (elf_compress (scn, 0, 0) < 0)
    9674           0 :                 printf ("WARNING: %s [%zd]\n",
    9675             :                         gettext ("Couldn't uncompress section"),
    9676             :                         elf_ndxscn (scn));
    9677             :             }
    9678           1 :           else if (strncmp (name, ".zdebug", strlen (".zdebug")) == 0)
    9679             :             {
    9680           1 :               if (elf_compress_gnu (scn, 0, 0) < 0)
    9681           0 :                 printf ("WARNING: %s [%zd]\n",
    9682             :                         gettext ("Couldn't uncompress section"),
    9683             :                         elf_ndxscn (scn));
    9684             :             }
    9685             :         }
    9686             : 
    9687          75 :       Elf_Data *data = elf_rawdata (scn, NULL);
    9688          75 :       if (data == NULL)
    9689           0 :         error (0, 0, gettext ("cannot get data for section [%zu] '%s': %s"),
    9690             :                elf_ndxscn (scn), name, elf_errmsg (-1));
    9691             :       else
    9692             :         {
    9693          75 :           if (data->d_size == shdr->sh_size)
    9694          74 :             printf (gettext ("\nString section [%zu] '%s' contains %" PRIu64
    9695             :                              " bytes at offset %#0" PRIx64 ":\n"),
    9696             :                     elf_ndxscn (scn), name,
    9697             :                     shdr->sh_size, shdr->sh_offset);
    9698             :           else
    9699           1 :             printf (gettext ("\nString section [%zu] '%s' contains %" PRIu64
    9700             :                              " bytes (%zd uncompressed) at offset %#0"
    9701             :                              PRIx64 ":\n"),
    9702             :                     elf_ndxscn (scn), name,
    9703             :                     shdr->sh_size, data->d_size, shdr->sh_offset);
    9704             : 
    9705          75 :           const char *start = data->d_buf;
    9706          75 :           const char *const limit = start + data->d_size;
    9707             :           do
    9708             :             {
    9709       16349 :               const char *end = memchr (start, '\0', limit - start);
    9710       16349 :               const size_t pos = start - (const char *) data->d_buf;
    9711       16349 :               if (unlikely (end == NULL))
    9712             :                 {
    9713           0 :                   printf ("  [%6zx]- %.*s\n",
    9714             :                           pos, (int) (limit - start), start);
    9715             :                   break;
    9716             :                 }
    9717       16349 :               printf ("  [%6zx]  %s\n", pos, start);
    9718       16349 :               start = end + 1;
    9719       16349 :             } while (start < limit);
    9720             :         }
    9721             :     }
    9722          75 : }
    9723             : 
    9724             : static void
    9725          38 : for_each_section_argument (Elf *elf, const struct section_argument *list,
    9726             :                            void (*dump) (Elf_Scn *scn, const GElf_Shdr *shdr,
    9727             :                                          const char *name))
    9728             : {
    9729             :   /* Get the section header string table index.  */
    9730             :   size_t shstrndx;
    9731          38 :   if (elf_getshdrstrndx (elf, &shstrndx) < 0)
    9732             :     error (EXIT_FAILURE, 0,
    9733           0 :            gettext ("cannot get section header string table index"));
    9734             : 
    9735         102 :   for (const struct section_argument *a = list; a != NULL; a = a->next)
    9736             :     {
    9737             :       Elf_Scn *scn;
    9738             :       GElf_Shdr shdr_mem;
    9739         102 :       const char *name = NULL;
    9740             : 
    9741         102 :       char *endp = NULL;
    9742         102 :       unsigned long int shndx = strtoul (a->arg, &endp, 0);
    9743         102 :       if (endp != a->arg && *endp == '\0')
    9744             :         {
    9745           0 :           scn = elf_getscn (elf, shndx);
    9746           0 :           if (scn == NULL)
    9747             :             {
    9748           0 :               error (0, 0, gettext ("\nsection [%lu] does not exist"), shndx);
    9749           0 :               continue;
    9750             :             }
    9751             : 
    9752           0 :           if (gelf_getshdr (scn, &shdr_mem) == NULL)
    9753           0 :             error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
    9754             :                    elf_errmsg (-1));
    9755           0 :           name = elf_strptr (elf, shstrndx, shdr_mem.sh_name);
    9756             :         }
    9757             :       else
    9758             :         {
    9759             :           /* Need to look up the section by name.  */
    9760             :           scn = NULL;
    9761             :           bool found = false;
    9762        2778 :           while ((scn = elf_nextscn (elf, scn)) != NULL)
    9763             :             {
    9764        2676 :               if (gelf_getshdr (scn, &shdr_mem) == NULL)
    9765           0 :                 continue;
    9766        2676 :               name = elf_strptr (elf, shstrndx, shdr_mem.sh_name);
    9767        2676 :               if (name == NULL)
    9768           0 :                 continue;
    9769        2676 :               if (!strcmp (name, a->arg))
    9770             :                 {
    9771          80 :                   found = true;
    9772          80 :                   (*dump) (scn, &shdr_mem, name);
    9773             :                 }
    9774             :             }
    9775             : 
    9776         102 :           if (unlikely (!found) && !a->implicit)
    9777           0 :             error (0, 0, gettext ("\nsection '%s' does not exist"), a->arg);
    9778             :         }
    9779             :     }
    9780          38 : }
    9781             : 
    9782             : static void
    9783             : dump_data (Ebl *ebl)
    9784             : {
    9785           5 :   for_each_section_argument (ebl->elf, dump_data_sections, &dump_data_section);
    9786             : }
    9787             : 
    9788             : static void
    9789             : dump_strings (Ebl *ebl)
    9790             : {
    9791          33 :   for_each_section_argument (ebl->elf, string_sections, &print_string_section);
    9792             : }
    9793             : 
    9794             : static void
    9795           0 : print_strings (Ebl *ebl)
    9796             : {
    9797             :   /* Get the section header string table index.  */
    9798             :   size_t shstrndx;
    9799           0 :   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
    9800             :     error (EXIT_FAILURE, 0,
    9801           0 :            gettext ("cannot get section header string table index"));
    9802             : 
    9803             :   Elf_Scn *scn;
    9804             :   GElf_Shdr shdr_mem;
    9805             :   const char *name;
    9806             :   scn = NULL;
    9807           0 :   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    9808             :     {
    9809           0 :       if (gelf_getshdr (scn, &shdr_mem) == NULL)
    9810           0 :         continue;
    9811             : 
    9812           0 :       if (shdr_mem.sh_type != SHT_PROGBITS
    9813           0 :           || !(shdr_mem.sh_flags & SHF_STRINGS))
    9814           0 :         continue;
    9815             : 
    9816           0 :       name = elf_strptr (ebl->elf, shstrndx, shdr_mem.sh_name);
    9817           0 :       if (name == NULL)
    9818           0 :         continue;
    9819             : 
    9820           0 :       print_string_section (scn, &shdr_mem, name);
    9821             :     }
    9822           0 : }
    9823             : 
    9824             : static void
    9825           2 : dump_archive_index (Elf *elf, const char *fname)
    9826             : {
    9827             :   size_t narsym;
    9828           2 :   const Elf_Arsym *arsym = elf_getarsym (elf, &narsym);
    9829           2 :   if (arsym == NULL)
    9830             :     {
    9831           0 :       int result = elf_errno ();
    9832           0 :       if (unlikely (result != ELF_E_NO_INDEX))
    9833           0 :         error (EXIT_FAILURE, 0,
    9834           0 :                gettext ("cannot get symbol index of archive '%s': %s"),
    9835             :                fname, elf_errmsg (result));
    9836             :       else
    9837           0 :         printf (gettext ("\nArchive '%s' has no symbol index\n"), fname);
    9838           0 :       return;
    9839             :     }
    9840             : 
    9841           4 :   printf (gettext ("\nIndex of archive '%s' has %zu entries:\n"),
    9842             :           fname, narsym);
    9843             : 
    9844           2 :   size_t as_off = 0;
    9845          11 :   for (const Elf_Arsym *s = arsym; s < &arsym[narsym - 1]; ++s)
    9846             :     {
    9847           9 :       if (s->as_off != as_off)
    9848             :         {
    9849           6 :           as_off = s->as_off;
    9850             : 
    9851           6 :           Elf *subelf = NULL;
    9852           6 :           if (unlikely (elf_rand (elf, as_off) == 0)
    9853           6 :               || unlikely ((subelf = elf_begin (-1, ELF_C_READ_MMAP, elf))
    9854             :                            == NULL))
    9855             : #if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 7)
    9856             :             while (1)
    9857             : #endif
    9858           0 :               error (EXIT_FAILURE, 0,
    9859           0 :                      gettext ("cannot extract member at offset %zu in '%s': %s"),
    9860             :                      as_off, fname, elf_errmsg (-1));
    9861             : 
    9862           6 :           const Elf_Arhdr *h = elf_getarhdr (subelf);
    9863             : 
    9864          12 :           printf (gettext ("Archive member '%s' contains:\n"), h->ar_name);
    9865             : 
    9866           6 :           elf_end (subelf);
    9867             :         }
    9868             : 
    9869          18 :       printf ("\t%s\n", s->as_name);
    9870             :     }
    9871             : }
    9872             : 
    9873             : #include "debugpred.h"

Generated by: LCOV version 1.12