LCOV - code coverage report
Current view: top level - src - readelf.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 2815 4006 70.3 %
Date: 2017-05-05 10:17:09 Functions: 100 108 92.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.12