Home | History | Annotate | Download | only in src
      1 /* Print size information from ELF file.
      2    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 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 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
     54 
     55 /* Bug report address.  */
     56 const char *argp_program_bug_address = 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 "), "2008");
    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 	return handle_ar (fd, elf, NULL, fname);
    323 
    324       /* We cannot handle this type.  Close the descriptor anyway.  */
    325       if (unlikely (elf_end (elf) != 0))
    326 	INTERNAL_ERROR (fname);
    327     }
    328 
    329   error (0, 0, gettext ("%s: file format not recognized"), fname);
    330 
    331   return 1;
    332 }
    333 
    334 
    335 /* Print the BSD-style header.  This is done exactly once.  */
    336 static void
    337 print_header (Elf *elf)
    338 {
    339   static int done;
    340 
    341   if (! done)
    342     {
    343       int ddigits = length_map[gelf_getclass (elf) - 1][radix_decimal];
    344       int xdigits = length_map[gelf_getclass (elf) - 1][radix_hex];
    345 
    346       printf ("%*s %*s %*s %*s %*s %s\n",
    347 	      ddigits - 2, sgettext ("bsd|text"),
    348 	      ddigits - 2, sgettext ("bsd|data"),
    349 	      ddigits - 2, sgettext ("bsd|bss"),
    350 	      ddigits - 2, sgettext ("bsd|dec"),
    351 	      xdigits - 2, sgettext ("bsd|hex"),
    352 	      sgettext ("bsd|filename"));
    353 
    354       done = 1;
    355     }
    356 }
    357 
    358 
    359 static int
    360 handle_ar (int fd, Elf *elf, const char *prefix, const char *fname)
    361 {
    362   size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
    363   size_t fname_len = strlen (fname) + 1;
    364   char new_prefix[prefix_len + 1 + fname_len];
    365   char *cp = new_prefix;
    366 
    367   /* Create the full name of the file.  */
    368   if (prefix != NULL)
    369     {
    370       cp = mempcpy (cp, prefix, prefix_len);
    371       *cp++ = ':';
    372     }
    373   memcpy (cp, fname, fname_len);
    374 
    375   /* Process all the files contained in the archive.  */
    376   int result = 0;
    377   Elf *subelf;
    378   Elf_Cmd cmd = ELF_C_READ_MMAP;
    379   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
    380     {
    381       /* The the header for this element.  */
    382       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
    383 
    384       if (elf_kind (subelf) == ELF_K_ELF)
    385 	handle_elf (subelf, new_prefix, arhdr->ar_name);
    386       else if (likely (elf_kind (subelf) == ELF_K_AR))
    387 	result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name);
    388       /* else signal error??? */
    389 
    390       /* Get next archive element.  */
    391       cmd = elf_next (subelf);
    392       if (unlikely (elf_end (subelf) != 0))
    393 	INTERNAL_ERROR (fname);
    394     }
    395 
    396   if (unlikely (elf_end (elf) != 0))
    397     INTERNAL_ERROR (fname);
    398 
    399   if (unlikely  (close (fd) != 0))
    400     error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
    401 
    402   return result;
    403 }
    404 
    405 
    406 /* Show sizes in SysV format.  */
    407 static void
    408 show_sysv (Elf *elf, const char *prefix, const char *fname,
    409 	   const char *fullname)
    410 {
    411   int maxlen = 10;
    412   const int digits = length_map[gelf_getclass (elf) - 1][radix];
    413 
    414   /* Get the section header string table index.  */
    415   size_t shstrndx;
    416   if (unlikely (elf_getshstrndx (elf, &shstrndx) < 0))
    417     error (EXIT_FAILURE, 0,
    418 	   gettext ("cannot get section header string table index"));
    419 
    420   /* First round over the sections: determine the longest section name.  */
    421   Elf_Scn *scn = NULL;
    422   while ((scn = elf_nextscn (elf, scn)) != NULL)
    423     {
    424       GElf_Shdr shdr_mem;
    425       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    426 
    427       if (shdr == NULL)
    428 	INTERNAL_ERROR (fullname);
    429 
    430       /* Ignore all sections which are not used at runtime.  */
    431       if ((shdr->sh_flags & SHF_ALLOC) != 0)
    432 	maxlen = MAX (maxlen,
    433 		      (int) strlen (elf_strptr (elf, shstrndx,
    434 						shdr->sh_name)));
    435     }
    436 
    437   fputs_unlocked (fname, stdout);
    438   if (prefix != NULL)
    439     printf (gettext (" (ex %s)"), prefix);
    440   printf (":\n%-*s %*s %*s\n",
    441 	  maxlen, sgettext ("sysv|section"),
    442 	  digits - 2, sgettext ("sysv|size"),
    443 	  digits, sgettext ("sysv|addr"));
    444 
    445   const char *fmtstr;
    446   if (radix == radix_hex)
    447     fmtstr = "%-*s %*" PRIx64 " %*" PRIx64 "\n";
    448   else if (radix == radix_decimal)
    449     fmtstr = "%-*s %*" PRId64 " %*" PRId64 "\n";
    450   else
    451     fmtstr = "%-*s %*" PRIo64 " %*" PRIo64 "\n";
    452 
    453   /* Iterate over all sections.  */
    454   GElf_Off total = 0;
    455   while ((scn = elf_nextscn (elf, scn)) != NULL)
    456     {
    457       GElf_Shdr shdr_mem;
    458       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    459 
    460       /* Ignore all sections which are not used at runtime.  */
    461       if ((shdr->sh_flags & SHF_ALLOC) != 0)
    462 	{
    463 	  printf (fmtstr,
    464 		  maxlen, elf_strptr (elf, shstrndx, shdr->sh_name),
    465 		  digits - 2, shdr->sh_size,
    466 		  digits, shdr->sh_addr);
    467 
    468 	  total += shdr->sh_size;
    469 	}
    470     }
    471 
    472   if (radix == radix_hex)
    473     printf ("%-*s %*" PRIx64 "\n\n\n", maxlen, sgettext ("sysv|Total"),
    474 	    digits - 2, total);
    475   else if (radix == radix_decimal)
    476     printf ("%-*s %*" PRId64 "\n\n\n", maxlen, sgettext ("sysv|Total"),
    477 	    digits - 2, total);
    478   else
    479     printf ("%-*s %*" PRIo64 "\n\n\n", maxlen, sgettext ("sysv|Total"),
    480 	    digits - 2, total);
    481 }
    482 
    483 
    484 /* Show sizes in SysV format in one line.  */
    485 static void
    486 show_sysv_one_line (Elf *elf)
    487 {
    488   /* Get the section header string table index.  */
    489   size_t shstrndx;
    490   if (unlikely (elf_getshstrndx (elf, &shstrndx) < 0))
    491     error (EXIT_FAILURE, 0,
    492 	   gettext ("cannot get section header string table index"));
    493 
    494   const char *fmtstr;
    495   if (radix == radix_hex)
    496     fmtstr = "%" PRIx64 "(%s)";
    497   else if (radix == radix_decimal)
    498     fmtstr = "%" PRId64 "(%s)";
    499   else
    500     fmtstr = "%" PRIo64 "(%s)";
    501 
    502   /* Iterate over all sections.  */
    503   GElf_Off total = 0;
    504   bool first = true;
    505   Elf_Scn *scn = NULL;
    506   while ((scn = elf_nextscn (elf, scn)) != NULL)
    507     {
    508       GElf_Shdr shdr_mem;
    509       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    510 
    511       /* Ignore all sections which are not used at runtime.  */
    512       if ((shdr->sh_flags & SHF_ALLOC) == 0)
    513 	continue;
    514 
    515       if (! first)
    516 	fputs_unlocked (" + ", stdout);
    517       first = false;
    518 
    519       printf (fmtstr, shdr->sh_size,
    520 	      elf_strptr (elf, shstrndx, shdr->sh_name));
    521 
    522       total += shdr->sh_size;
    523     }
    524 
    525   if (radix == radix_hex)
    526     printf (" = %#" PRIx64 "\n", total);
    527   else if (radix == radix_decimal)
    528     printf (" = %" PRId64 "\n", total);
    529   else
    530     printf (" = %" PRIo64 "\n", total);
    531 }
    532 
    533 
    534 /* Variables to add up the sizes of all files.  */
    535 static uintmax_t total_textsize;
    536 static uintmax_t total_datasize;
    537 static uintmax_t total_bsssize;
    538 
    539 
    540 /* Show sizes in BSD format.  */
    541 static void
    542 show_bsd (Elf *elf, const char *prefix, const char *fname,
    543 	  const char *fullname)
    544 {
    545   GElf_Off textsize = 0;
    546   GElf_Off datasize = 0;
    547   GElf_Off bsssize = 0;
    548   const int ddigits = length_map[gelf_getclass (elf) - 1][radix_decimal];
    549   const int xdigits = length_map[gelf_getclass (elf) - 1][radix_hex];
    550 
    551   /* Iterate over all sections.  */
    552   Elf_Scn *scn = NULL;
    553   while ((scn = elf_nextscn (elf, scn)) != NULL)
    554     {
    555       GElf_Shdr shdr_mem;
    556       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    557 
    558       if (shdr == NULL)
    559 	INTERNAL_ERROR (fullname);
    560 
    561       /* Ignore all sections which are not marked as loaded.  */
    562       if ((shdr->sh_flags & SHF_ALLOC) == 0)
    563 	continue;
    564 
    565       if ((shdr->sh_flags & SHF_WRITE) == 0)
    566 	textsize += shdr->sh_size;
    567       else if (shdr->sh_type == SHT_NOBITS)
    568 	bsssize += shdr->sh_size;
    569       else
    570 	datasize += shdr->sh_size;
    571     }
    572 
    573   printf ("%*" PRId64 " %*" PRId64 " %*" PRId64 " %*" PRId64 " %*"
    574 	  PRIx64 " %s",
    575 	  ddigits - 2, textsize,
    576 	  ddigits - 2, datasize,
    577 	  ddigits - 2, bsssize,
    578 	  ddigits - 2, textsize + datasize + bsssize,
    579 	  xdigits - 2, textsize + datasize + bsssize,
    580 	  fname);
    581   if (prefix != NULL)
    582     printf (gettext (" (ex %s)"), prefix);
    583   fputs_unlocked ("\n", stdout);
    584 
    585   total_textsize += textsize;
    586   total_datasize += datasize;
    587   total_bsssize += bsssize;
    588 
    589   totals_class = MAX (totals_class, gelf_getclass (elf));
    590 }
    591 
    592 
    593 /* Show total size.  */
    594 static void
    595 show_bsd_totals (void)
    596 {
    597   int ddigits = length_map[totals_class - 1][radix_decimal];
    598   int xdigits = length_map[totals_class - 1][radix_hex];
    599 
    600   printf ("%*" PRIuMAX " %*" PRIuMAX " %*" PRIuMAX " %*" PRIuMAX " %*"
    601 	  PRIxMAX " %s",
    602 	  ddigits - 2, total_textsize,
    603 	  ddigits - 2, total_datasize,
    604 	  ddigits - 2, total_bsssize,
    605 	  ddigits - 2, total_textsize + total_datasize + total_bsssize,
    606 	  xdigits - 2, total_textsize + total_datasize + total_bsssize,
    607 	  gettext ("(TOTALS)\n"));
    608 }
    609 
    610 
    611 /* Show size and permission of loadable segments.  */
    612 static void
    613 show_segments (Elf *elf, const char *fullname)
    614 {
    615   GElf_Ehdr ehdr_mem;
    616   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
    617   if (ehdr == NULL)
    618     INTERNAL_ERROR (fullname);
    619 
    620   GElf_Off total = 0;
    621   bool first = true;
    622   for (size_t cnt = 0; cnt < ehdr->e_phnum; ++cnt)
    623     {
    624       GElf_Phdr phdr_mem;
    625       GElf_Phdr *phdr;
    626 
    627       phdr = gelf_getphdr (elf, cnt, &phdr_mem);
    628       if (phdr == NULL)
    629 	INTERNAL_ERROR (fullname);
    630 
    631       if (phdr->p_type != PT_LOAD)
    632 	/* Only load segments.  */
    633 	continue;
    634 
    635       if (! first)
    636 	fputs_unlocked (" + ", stdout);
    637       first = false;
    638 
    639       printf (radix == radix_hex ? "%" PRIx64 "(%c%c%c)"
    640 	      : (radix == radix_decimal ? "%" PRId64 "(%c%c%c)"
    641 		 : "%" PRIo64 "(%c%c%c)"),
    642 	      phdr->p_memsz,
    643 	      (phdr->p_flags & PF_R) == 0 ? '-' : 'r',
    644 	      (phdr->p_flags & PF_W) == 0 ? '-' : 'w',
    645 	      (phdr->p_flags & PF_X) == 0 ? '-' : 'x');
    646 
    647       total += phdr->p_memsz;
    648     }
    649 
    650   if (radix == radix_hex)
    651     printf (" = %#" PRIx64 "\n", total);
    652   else if (radix == radix_decimal)
    653     printf (" = %" PRId64 "\n", total);
    654   else
    655     printf (" = %" PRIo64 "\n", total);
    656 }
    657 
    658 
    659 static void
    660 handle_elf (Elf *elf, const char *prefix, const char *fname)
    661 {
    662   size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
    663   size_t fname_len = strlen (fname) + 1;
    664   char fullname[prefix_len + 1 + fname_len];
    665   char *cp = fullname;
    666 
    667   /* Create the full name of the file.  */
    668   if (prefix != NULL)
    669     {
    670       cp = mempcpy (cp, prefix, prefix_len);
    671       *cp++ = ':';
    672     }
    673   memcpy (cp, fname, fname_len);
    674 
    675   if (format == format_sysv)
    676     show_sysv (elf, prefix, fname, fullname);
    677   else if (format == format_sysv_one_line)
    678     show_sysv_one_line (elf);
    679   else if (format == format_segments)
    680     show_segments (elf, fullname);
    681   else
    682     {
    683       print_header (elf);
    684 
    685       show_bsd (elf, prefix, fname, fullname);
    686     }
    687 }
    688 
    689 
    690 #include "debugpred.h"
    691