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

Generated by: LCOV version 1.12