Home | History | Annotate | Download | only in src
      1 /* Print size information from ELF file.
      2    Copyright (C) 2000-2007,2009,2012 Red Hat, Inc.
      3    This file is part of Red Hat elfutils.
      4    Written by Ulrich Drepper <drepper (at) redhat.com>, 2000.
      5 
      6    Red Hat elfutils is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by the
      8    Free Software Foundation; version 2 of the License.
      9 
     10    Red Hat elfutils is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13    General Public License for more details.
     14 
     15    You should have received a copy of the GNU General Public License along
     16    with Red Hat elfutils; if not, write to the Free Software Foundation,
     17    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
     18 
     19    Red Hat elfutils is an included package of the Open Invention Network.
     20    An included package of the Open Invention Network is a package for which
     21    Open Invention Network licensees cross-license their patents.  No patent
     22    license is granted, either expressly or impliedly, by designation as an
     23    included package.  Should you wish to participate in the Open Invention
     24    Network licensing program, please visit www.openinventionnetwork.com
     25    <http://www.openinventionnetwork.com>.  */
     26 
     27 #ifdef HAVE_CONFIG_H
     28 # include <config.h>
     29 #endif
     30 
     31 #include <argp.h>
     32 #include <error.h>
     33 #include <fcntl.h>
     34 #include <gelf.h>
     35 #include <inttypes.h>
     36 #include <libelf.h>
     37 #include <libintl.h>
     38 #include <locale.h>
     39 #include <mcheck.h>
     40 #include <stdbool.h>
     41 #include <stdio.h>
     42 #include <stdio_ext.h>
     43 #include <stdlib.h>
     44 #include <string.h>
     45 #include <unistd.h>
     46 #include <sys/param.h>
     47 
     48 #include <system.h>
     49 
     50 
     51 /* Name and version of program.  */
     52 static void print_version (FILE *stream, struct argp_state *state);
     53 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
     54 
     55 /* Bug report address.  */
     56 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
     57 
     58 
     59 /* Values for the parameters which have no short form.  */
     60 #define OPT_FORMAT	0x100
     61 #define OPT_RADIX	0x101
     62 
     63 /* Definitions of arguments for argp functions.  */
     64 static const struct argp_option options[] =
     65 {
     66   { NULL, 0, NULL, 0, N_("Output format:"), 0 },
     67   { "format", OPT_FORMAT, "FORMAT", 0,
     68     N_("Use the output format FORMAT.  FORMAT can be `bsd' or `sysv'.  "
     69        "The default is `bsd'"), 0 },
     70   { NULL, 'A', NULL, 0, N_("Same as `--format=sysv'"), 0 },
     71   { NULL, 'B', NULL, 0, N_("Same as `--format=bsd'"), 0 },
     72   { "radix", OPT_RADIX, "RADIX", 0, N_("Use RADIX for printing symbol values"),
     73     0},
     74   { NULL, 'd', NULL, 0, N_("Same as `--radix=10'"), 0 },
     75   { NULL, 'o', NULL, 0, N_("Same as `--radix=8'"), 0 },
     76   { NULL, 'x', NULL, 0, N_("Same as `--radix=16'"), 0 },
     77   { NULL, 'f', NULL, 0,
     78     N_("Similar to `--format=sysv' output but in one line"), 0 },
     79 
     80   { NULL, 0, NULL, 0, N_("Output options:"), 0 },
     81   { NULL, 'F', NULL, 0,
     82     N_("Print size and permission flags for loadable segments"), 0 },
     83   { "totals", 't', NULL, 0, N_("Display the total sizes (bsd only)"), 0 },
     84   { NULL, 0, NULL, 0, NULL, 0 }
     85 };
     86 
     87 /* Short description of program.  */
     88 static const char doc[] = N_("\
     89 List section sizes of FILEs (a.out by default).");
     90 
     91 /* Strings for arguments in help texts.  */
     92 static const char args_doc[] = N_("[FILE...]");
     93 
     94 /* Prototype for option handler.  */
     95 static error_t parse_opt (int key, char *arg, struct argp_state *state);
     96 
     97 /* Data structure to communicate with argp functions.  */
     98 static struct argp argp =
     99 {
    100   options, parse_opt, args_doc, doc, NULL, NULL, NULL
    101 };
    102 
    103 
    104 /* Print symbols in file named FNAME.  */
    105 static int process_file (const char *fname);
    106 
    107 /* Handle content of archive.  */
    108 static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname);
    109 
    110 /* Handle ELF file.  */
    111 static void handle_elf (Elf *elf, const char *fullname, const char *fname);
    112 
    113 /* Show total size.  */
    114 static void show_bsd_totals (void);
    115 
    116 #define INTERNAL_ERROR(fname) \
    117   error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"),      \
    118 	 fname, __LINE__, PACKAGE_VERSION, __DATE__, elf_errmsg (-1))
    119 
    120 
    121 /* User-selectable options.  */
    122 
    123 /* The selected output format.  */
    124 static enum
    125 {
    126   format_bsd = 0,
    127   format_sysv,
    128   format_sysv_one_line,
    129   format_segments
    130 } format;
    131 
    132 /* Radix for printed numbers.  */
    133 static enum
    134 {
    135   radix_decimal = 0,
    136   radix_hex,
    137   radix_octal
    138 } radix;
    139 
    140 
    141 /* Mapping of radix and binary class to length.  */
    142 static const int length_map[2][3] =
    143 {
    144   [ELFCLASS32 - 1] =
    145   {
    146     [radix_hex] = 8,
    147     [radix_decimal] = 10,
    148     [radix_octal] = 11
    149   },
    150   [ELFCLASS64 - 1] =
    151   {
    152     [radix_hex] = 16,
    153     [radix_decimal] = 20,
    154     [radix_octal] = 22
    155   }
    156 };
    157 
    158 /* True if total sizes should be printed.  */
    159 static bool totals;
    160 /* To print the total sizes in a reasonable format remember the higest
    161    "class" of ELF binaries processed.  */
    162 static int totals_class;
    163 
    164 
    165 int
    166 main (int argc, char *argv[])
    167 {
    168   int remaining;
    169   int result = 0;
    170 
    171   /* Make memory leak detection possible.  */
    172   mtrace ();
    173 
    174   /* We use no threads here which can interfere with handling a stream.  */
    175   __fsetlocking (stdin, FSETLOCKING_BYCALLER);
    176   __fsetlocking (stdout, FSETLOCKING_BYCALLER);
    177   __fsetlocking (stderr, FSETLOCKING_BYCALLER);
    178 
    179   /* Set locale.  */
    180   setlocale (LC_ALL, "");
    181 
    182   /* Make sure the message catalog can be found.  */
    183   bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
    184 
    185   /* Initialize the message catalog.  */
    186   textdomain (PACKAGE_TARNAME);
    187 
    188   /* Parse and process arguments.  */
    189   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
    190 
    191 
    192   /* Tell the library which version we are expecting.  */
    193   elf_version (EV_CURRENT);
    194 
    195   if (remaining == argc)
    196     /* The user didn't specify a name so we use a.out.  */
    197     result = process_file ("a.out");
    198   else
    199     /* Process all the remaining files.  */
    200     do
    201       result |= process_file (argv[remaining]);
    202     while (++remaining < argc);
    203 
    204   /* Print the total sizes but only if the output format is BSD and at
    205      least one file has been correctly read (i.e., we recognized the
    206      class).  */
    207   if (totals && format == format_bsd && totals_class != 0)
    208     show_bsd_totals ();
    209 
    210   return result;
    211 }
    212 
    213 
    214 /* Print the version information.  */
    215 static void
    216 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
    217 {
    218   fprintf (stream, "size (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
    219   fprintf (stream, gettext ("\
    220 Copyright (C) %s Red Hat, Inc.\n\
    221 This is free software; see the source for copying conditions.  There is NO\n\
    222 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
    223 "), "2012");
    224   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
    225 }
    226 
    227 
    228 /* Handle program arguments.  */
    229 static error_t
    230 parse_opt (int key, char *arg,
    231 	   struct argp_state *state __attribute__ ((unused)))
    232 {
    233   switch (key)
    234     {
    235     case 'd':
    236       radix = radix_decimal;
    237       break;
    238 
    239     case 'f':
    240       format = format_sysv_one_line;
    241       break;
    242 
    243     case 'o':
    244       radix = radix_octal;
    245       break;
    246 
    247     case 'x':
    248       radix = radix_hex;
    249       break;
    250 
    251     case 'A':
    252       format = format_sysv;
    253       break;
    254 
    255     case 'B':
    256       format = format_bsd;
    257       break;
    258 
    259     case 'F':
    260       format = format_segments;
    261       break;
    262 
    263     case OPT_FORMAT:
    264       if (strcmp (arg, "bsd") == 0 || strcmp (arg, "berkeley") == 0)
    265 	format = format_bsd;
    266       else if (likely (strcmp (arg, "sysv") == 0))
    267 	format = format_sysv;
    268       else
    269 	error (EXIT_FAILURE, 0, gettext ("Invalid format: %s"), arg);
    270       break;
    271 
    272     case OPT_RADIX:
    273       if (strcmp (arg, "x") == 0 || strcmp (arg, "16") == 0)
    274 	radix = radix_hex;
    275       else if (strcmp (arg, "d") == 0 || strcmp (arg, "10") == 0)
    276 	radix = radix_decimal;
    277       else if (strcmp (arg, "o") == 0 || strcmp (arg, "8") == 0)
    278 	radix = radix_octal;
    279       else
    280 	error (EXIT_FAILURE, 0, gettext ("Invalid radix: %s"), arg);
    281       break;
    282 
    283     case 't':
    284       totals = true;
    285       break;
    286 
    287     default:
    288       return ARGP_ERR_UNKNOWN;
    289     }
    290   return 0;
    291 }
    292 
    293 
    294 /* Open the file and determine the type.  */
    295 static int
    296 process_file (const char *fname)
    297 {
    298   int fd = open (fname, O_RDONLY);
    299   if (unlikely (fd == -1))
    300     {
    301       error (0, errno, gettext ("cannot open '%s'"), fname);
    302       return 1;
    303     }
    304 
    305   /* Now get the ELF descriptor.  */
    306   Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
    307   if (likely (elf != NULL))
    308     {
    309       if (elf_kind (elf) == ELF_K_ELF)
    310 	{
    311 	  handle_elf (elf, NULL, fname);
    312 
    313 	  if (unlikely (elf_end (elf) != 0))
    314 	    INTERNAL_ERROR (fname);
    315 
    316 	  if (unlikely (close (fd) != 0))
    317 	    error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
    318 
    319 	  return 0;
    320 	}
    321       else if (likely (elf_kind (elf) == ELF_K_AR))
    322 	{
    323 	  int result = handle_ar (fd, elf, NULL, fname);
    324 
    325 	  if (unlikely  (close (fd) != 0))
    326 	    error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
    327 
    328 	  return result;
    329 	}
    330 
    331       /* We cannot handle this type.  Close the descriptor anyway.  */
    332       if (unlikely (elf_end (elf) != 0))
    333 	INTERNAL_ERROR (fname);
    334     }
    335 
    336   if (unlikely (close (fd) != 0))
    337     error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
    338 
    339   error (0, 0, gettext ("%s: file format not recognized"), fname);
    340 
    341   return 1;
    342 }
    343 
    344 
    345 /* Print the BSD-style header.  This is done exactly once.  */
    346 static void
    347 print_header (Elf *elf)
    348 {
    349   static int done;
    350 
    351   if (! done)
    352     {
    353       int ddigits = length_map[gelf_getclass (elf) - 1][radix_decimal];
    354       int xdigits = length_map[gelf_getclass (elf) - 1][radix_hex];
    355 
    356       printf ("%*s %*s %*s %*s %*s %s\n",
    357 	      ddigits - 2, sgettext ("bsd|text"),
    358 	      ddigits - 2, sgettext ("bsd|data"),
    359 	      ddigits - 2, sgettext ("bsd|bss"),
    360 	      ddigits - 2, sgettext ("bsd|dec"),
    361 	      xdigits - 2, sgettext ("bsd|hex"),
    362 	      sgettext ("bsd|filename"));
    363 
    364       done = 1;
    365     }
    366 }
    367 
    368 
    369 static int
    370 handle_ar (int fd, Elf *elf, const char *prefix, const char *fname)
    371 {
    372   size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
    373   size_t fname_len = strlen (fname) + 1;
    374   char new_prefix[prefix_len + 1 + fname_len];
    375   char *cp = new_prefix;
    376 
    377   /* Create the full name of the file.  */
    378   if (prefix != NULL)
    379     {
    380       cp = mempcpy (cp, prefix, prefix_len);
    381       *cp++ = ':';
    382     }
    383   memcpy (cp, fname, fname_len);
    384 
    385   /* Process all the files contained in the archive.  */
    386   int result = 0;
    387   Elf *subelf;
    388   Elf_Cmd cmd = ELF_C_READ_MMAP;
    389   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
    390     {
    391       /* The the header for this element.  */
    392       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
    393 
    394       if (elf_kind (subelf) == ELF_K_ELF)
    395 	handle_elf (subelf, new_prefix, arhdr->ar_name);
    396       else if (likely (elf_kind (subelf) == ELF_K_AR))
    397 	result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name);
    398       /* else signal error??? */
    399 
    400       /* Get next archive element.  */
    401       cmd = elf_next (subelf);
    402       if (unlikely (elf_end (subelf) != 0))
    403 	INTERNAL_ERROR (fname);
    404     }
    405 
    406   if (unlikely (elf_end (elf) != 0))
    407     INTERNAL_ERROR (fname);
    408 
    409   return result;
    410 }
    411 
    412 
    413 /* Show sizes in SysV format.  */
    414 static void
    415 show_sysv (Elf *elf, const char *prefix, const char *fname,
    416 	   const char *fullname)
    417 {
    418   int maxlen = 10;
    419   const int digits = length_map[gelf_getclass (elf) - 1][radix];
    420 
    421   /* Get the section header string table index.  */
    422   size_t shstrndx;
    423   if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0))
    424     error (EXIT_FAILURE, 0,
    425 	   gettext ("cannot get section header string table index"));
    426 
    427   /* First round over the sections: determine the longest section name.  */
    428   Elf_Scn *scn = NULL;
    429   while ((scn = elf_nextscn (elf, scn)) != NULL)
    430     {
    431       GElf_Shdr shdr_mem;
    432       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    433 
    434       if (shdr == NULL)
    435 	INTERNAL_ERROR (fullname);
    436 
    437       /* Ignore all sections which are not used at runtime.  */
    438       if ((shdr->sh_flags & SHF_ALLOC) != 0)
    439 	maxlen = MAX (maxlen,
    440 		      (int) strlen (elf_strptr (elf, shstrndx,
    441 						shdr->sh_name)));
    442     }
    443 
    444   fputs_unlocked (fname, stdout);
    445   if (prefix != NULL)
    446     printf (gettext (" (ex %s)"), prefix);
    447   printf (":\n%-*s %*s %*s\n",
    448 	  maxlen, sgettext ("sysv|section"),
    449 	  digits - 2, sgettext ("sysv|size"),
    450 	  digits, sgettext ("sysv|addr"));
    451 
    452   const char *fmtstr;
    453   if (radix == radix_hex)
    454     fmtstr = "%-*s %*" PRIx64 " %*" PRIx64 "\n";
    455   else if (radix == radix_decimal)
    456     fmtstr = "%-*s %*" PRId64 " %*" PRId64 "\n";
    457   else
    458     fmtstr = "%-*s %*" PRIo64 " %*" PRIo64 "\n";
    459 
    460   /* Iterate over all sections.  */
    461   GElf_Off total = 0;
    462   while ((scn = elf_nextscn (elf, scn)) != NULL)
    463     {
    464       GElf_Shdr shdr_mem;
    465       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    466 
    467       /* Ignore all sections which are not used at runtime.  */
    468       if ((shdr->sh_flags & SHF_ALLOC) != 0)
    469 	{
    470 	  printf (fmtstr,
    471 		  maxlen, elf_strptr (elf, shstrndx, shdr->sh_name),
    472 		  digits - 2, shdr->sh_size,
    473 		  digits, shdr->sh_addr);
    474 
    475 	  total += shdr->sh_size;
    476 	}
    477     }
    478 
    479   if (radix == radix_hex)
    480     printf ("%-*s %*" PRIx64 "\n\n\n", maxlen, sgettext ("sysv|Total"),
    481 	    digits - 2, total);
    482   else if (radix == radix_decimal)
    483     printf ("%-*s %*" PRId64 "\n\n\n", maxlen, sgettext ("sysv|Total"),
    484 	    digits - 2, total);
    485   else
    486     printf ("%-*s %*" PRIo64 "\n\n\n", maxlen, sgettext ("sysv|Total"),
    487 	    digits - 2, total);
    488 }
    489 
    490 
    491 /* Show sizes in SysV format in one line.  */
    492 static void
    493 show_sysv_one_line (Elf *elf)
    494 {
    495   /* Get the section header string table index.  */
    496   size_t shstrndx;
    497   if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0))
    498     error (EXIT_FAILURE, 0,
    499 	   gettext ("cannot get section header string table index"));
    500 
    501   const char *fmtstr;
    502   if (radix == radix_hex)
    503     fmtstr = "%" PRIx64 "(%s)";
    504   else if (radix == radix_decimal)
    505     fmtstr = "%" PRId64 "(%s)";
    506   else
    507     fmtstr = "%" PRIo64 "(%s)";
    508 
    509   /* Iterate over all sections.  */
    510   GElf_Off total = 0;
    511   bool first = true;
    512   Elf_Scn *scn = NULL;
    513   while ((scn = elf_nextscn (elf, scn)) != NULL)
    514     {
    515       GElf_Shdr shdr_mem;
    516       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    517 
    518       /* Ignore all sections which are not used at runtime.  */
    519       if ((shdr->sh_flags & SHF_ALLOC) == 0)
    520 	continue;
    521 
    522       if (! first)
    523 	fputs_unlocked (" + ", stdout);
    524       first = false;
    525 
    526       printf (fmtstr, shdr->sh_size,
    527 	      elf_strptr (elf, shstrndx, shdr->sh_name));
    528 
    529       total += shdr->sh_size;
    530     }
    531 
    532   if (radix == radix_hex)
    533     printf (" = %#" PRIx64 "\n", total);
    534   else if (radix == radix_decimal)
    535     printf (" = %" PRId64 "\n", total);
    536   else
    537     printf (" = %" PRIo64 "\n", total);
    538 }
    539 
    540 
    541 /* Variables to add up the sizes of all files.  */
    542 static uintmax_t total_textsize;
    543 static uintmax_t total_datasize;
    544 static uintmax_t total_bsssize;
    545 
    546 
    547 /* Show sizes in BSD format.  */
    548 static void
    549 show_bsd (Elf *elf, const char *prefix, const char *fname,
    550 	  const char *fullname)
    551 {
    552   GElf_Off textsize = 0;
    553   GElf_Off datasize = 0;
    554   GElf_Off bsssize = 0;
    555   const int ddigits = length_map[gelf_getclass (elf) - 1][radix_decimal];
    556   const int xdigits = length_map[gelf_getclass (elf) - 1][radix_hex];
    557 
    558   /* Iterate over all sections.  */
    559   Elf_Scn *scn = NULL;
    560   while ((scn = elf_nextscn (elf, scn)) != NULL)
    561     {
    562       GElf_Shdr shdr_mem;
    563       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    564 
    565       if (shdr == NULL)
    566 	INTERNAL_ERROR (fullname);
    567 
    568       /* Ignore all sections which are not marked as loaded.  */
    569       if ((shdr->sh_flags & SHF_ALLOC) == 0)
    570 	continue;
    571 
    572       if ((shdr->sh_flags & SHF_WRITE) == 0)
    573 	textsize += shdr->sh_size;
    574       else if (shdr->sh_type == SHT_NOBITS)
    575 	bsssize += shdr->sh_size;
    576       else
    577 	datasize += shdr->sh_size;
    578     }
    579 
    580   printf ("%*" PRId64 " %*" PRId64 " %*" PRId64 " %*" PRId64 " %*"
    581 	  PRIx64 " %s",
    582 	  ddigits - 2, textsize,
    583 	  ddigits - 2, datasize,
    584 	  ddigits - 2, bsssize,
    585 	  ddigits - 2, textsize + datasize + bsssize,
    586 	  xdigits - 2, textsize + datasize + bsssize,
    587 	  fname);
    588   if (prefix != NULL)
    589     printf (gettext (" (ex %s)"), prefix);
    590   fputs_unlocked ("\n", stdout);
    591 
    592   total_textsize += textsize;
    593   total_datasize += datasize;
    594   total_bsssize += bsssize;
    595 
    596   totals_class = MAX (totals_class, gelf_getclass (elf));
    597 }
    598 
    599 
    600 /* Show total size.  */
    601 static void
    602 show_bsd_totals (void)
    603 {
    604   int ddigits = length_map[totals_class - 1][radix_decimal];
    605   int xdigits = length_map[totals_class - 1][radix_hex];
    606 
    607   printf ("%*" PRIuMAX " %*" PRIuMAX " %*" PRIuMAX " %*" PRIuMAX " %*"
    608 	  PRIxMAX " %s",
    609 	  ddigits - 2, total_textsize,
    610 	  ddigits - 2, total_datasize,
    611 	  ddigits - 2, total_bsssize,
    612 	  ddigits - 2, total_textsize + total_datasize + total_bsssize,
    613 	  xdigits - 2, total_textsize + total_datasize + total_bsssize,
    614 	  gettext ("(TOTALS)\n"));
    615 }
    616 
    617 
    618 /* Show size and permission of loadable segments.  */
    619 static void
    620 show_segments (Elf *elf, const char *fullname)
    621 {
    622   GElf_Ehdr ehdr_mem;
    623   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
    624   if (ehdr == NULL)
    625     INTERNAL_ERROR (fullname);
    626 
    627   GElf_Off total = 0;
    628   bool first = true;
    629   for (size_t cnt = 0; cnt < ehdr->e_phnum; ++cnt)
    630     {
    631       GElf_Phdr phdr_mem;
    632       GElf_Phdr *phdr;
    633 
    634       phdr = gelf_getphdr (elf, cnt, &phdr_mem);
    635       if (phdr == NULL)
    636 	INTERNAL_ERROR (fullname);
    637 
    638       if (phdr->p_type != PT_LOAD)
    639 	/* Only load segments.  */
    640 	continue;
    641 
    642       if (! first)
    643 	fputs_unlocked (" + ", stdout);
    644       first = false;
    645 
    646       printf (radix == radix_hex ? "%" PRIx64 "(%c%c%c)"
    647 	      : (radix == radix_decimal ? "%" PRId64 "(%c%c%c)"
    648 		 : "%" PRIo64 "(%c%c%c)"),
    649 	      phdr->p_memsz,
    650 	      (phdr->p_flags & PF_R) == 0 ? '-' : 'r',
    651 	      (phdr->p_flags & PF_W) == 0 ? '-' : 'w',
    652 	      (phdr->p_flags & PF_X) == 0 ? '-' : 'x');
    653 
    654       total += phdr->p_memsz;
    655     }
    656 
    657   if (radix == radix_hex)
    658     printf (" = %#" PRIx64 "\n", total);
    659   else if (radix == radix_decimal)
    660     printf (" = %" PRId64 "\n", total);
    661   else
    662     printf (" = %" PRIo64 "\n", total);
    663 }
    664 
    665 
    666 static void
    667 handle_elf (Elf *elf, const char *prefix, const char *fname)
    668 {
    669   size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
    670   size_t fname_len = strlen (fname) + 1;
    671   char fullname[prefix_len + 1 + fname_len];
    672   char *cp = fullname;
    673 
    674   /* Create the full name of the file.  */
    675   if (prefix != NULL)
    676     {
    677       cp = mempcpy (cp, prefix, prefix_len);
    678       *cp++ = ':';
    679     }
    680   memcpy (cp, fname, fname_len);
    681 
    682   if (format == format_sysv)
    683     show_sysv (elf, prefix, fname, fullname);
    684   else if (format == format_sysv_one_line)
    685     show_sysv_one_line (elf);
    686   else if (format == format_segments)
    687     show_segments (elf, fullname);
    688   else
    689     {
    690       print_header (elf);
    691 
    692       show_bsd (elf, prefix, fname, fullname);
    693     }
    694 }
    695 
    696 
    697 #include "debugpred.h"
    698