• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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
main(int argc,char * argv[])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
print_version(FILE * stream,struct argp_state * state)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
parse_opt(int key,char * arg,struct argp_state * state)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
process_file(const char * fname)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
print_header(Elf * elf)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
handle_ar(int fd,Elf * elf,const char * prefix,const char * fname)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
show_sysv(Elf * elf,const char * prefix,const char * fname,const char * fullname)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
show_sysv_one_line(Elf * elf)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
show_bsd(Elf * elf,const char * prefix,const char * fname,const char * fullname)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
show_bsd_totals(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
show_segments(Elf * elf,const char * fullname)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
handle_elf(Elf * elf,const char * prefix,const char * fname)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