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