Branch data Line data Source code
1 : : /* Print information from ELF file in human-readable form.
2 : : Copyright (C) 2005, 2006, 2007, 2009, 2011, 2012, 2014, 2015 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Written by Ulrich Drepper <drepper@redhat.com>, 2005.
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 <fcntl.h>
25 : : #include <inttypes.h>
26 : : #include <locale.h>
27 : : #include <stdbool.h>
28 : : #include <stdio.h>
29 : : #include <stdio_ext.h>
30 : : #include <stdlib.h>
31 : : #include <string.h>
32 : : #include <unistd.h>
33 : :
34 : : #include <libeu.h>
35 : : #include <system.h>
36 : : #include <color.h>
37 : : #include <printversion.h>
38 : : #include "../libebl/libeblP.h"
39 : :
40 : :
41 : : /* Name and version of program. */
42 : : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
43 : :
44 : : /* Bug report address. */
45 : : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
46 : :
47 : :
48 : : /* Definitions of arguments for argp functions. */
49 : : static const struct argp_option options[] =
50 : : {
51 : : { NULL, 0, NULL, 0, N_("Mode selection:"), 0 },
52 : : { "reloc", 'r', NULL, 0, N_("Display relocation information."), 0 },
53 : : { "full-contents", 's', NULL, 0,
54 : : N_("Display the full contents of all sections requested"), 0 },
55 : : { "disassemble", 'd', NULL, 0,
56 : : N_("Display assembler code of executable sections"), 0 },
57 : :
58 : : { NULL, 0, NULL, 0, N_("Output content selection:"), 0 },
59 : : { "section", 'j', "NAME", 0,
60 : : N_("Only display information for section NAME."), 0 },
61 : :
62 : : { NULL, 0, NULL, 0, NULL, 0 }
63 : : };
64 : :
65 : : /* Short description of program. */
66 : : static const char doc[] = N_("\
67 : : Show information from FILEs (a.out by default).");
68 : :
69 : : /* Strings for arguments in help texts. */
70 : : static const char args_doc[] = N_("[FILE...]");
71 : :
72 : : /* Prototype for option handler. */
73 : : static error_t parse_opt (int key, char *arg, struct argp_state *state);
74 : :
75 : : /* Parser children. */
76 : : static struct argp_child argp_children[] =
77 : : {
78 : : { &color_argp, 0, N_("Output formatting"), 2 },
79 : : { NULL, 0, NULL, 0}
80 : : };
81 : :
82 : : /* Data structure to communicate with argp functions. */
83 : : static const struct argp argp =
84 : : {
85 : : options, parse_opt, args_doc, doc, argp_children, NULL, NULL
86 : : };
87 : :
88 : :
89 : : /* Print symbols in file named FNAME. */
90 : : static int process_file (const char *fname, bool more_than_one);
91 : :
92 : : /* Handle content of archive. */
93 : : static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
94 : : const char *suffix);
95 : :
96 : : /* Handle ELF file. */
97 : : static int handle_elf (Elf *elf, const char *prefix, const char *fname,
98 : : const char *suffix);
99 : :
100 : :
101 : : #define INTERNAL_ERROR(fname) \
102 : : error_exit (0, _("%s: INTERNAL ERROR %d (%s): %s"), \
103 : : fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1))
104 : :
105 : :
106 : : /* List of sections which should be used. */
107 : : static struct section_list
108 : : {
109 : : bool is_name;
110 : : union
111 : : {
112 : : const char *name;
113 : : uint32_t scnndx;
114 : : };
115 : : struct section_list *next;
116 : : } *section_list;
117 : :
118 : :
119 : : /* If true print archive index. */
120 : : static bool print_relocs;
121 : :
122 : : /* If true print full contents of requested sections. */
123 : : static bool print_full_content;
124 : :
125 : : /* If true print disassembled output.. */
126 : : static bool print_disasm;
127 : :
128 : :
129 : : int
130 : 10 : main (int argc, char *argv[])
131 : : {
132 : : /* We use no threads here which can interfere with handling a stream. */
133 : 10 : (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
134 : 10 : (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
135 : 10 : (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
136 : :
137 : : /* Set locale. */
138 : 10 : (void) setlocale (LC_ALL, "");
139 : :
140 : : /* Make sure the message catalog can be found. */
141 : 10 : (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
142 : :
143 : : /* Initialize the message catalog. */
144 : 10 : (void) textdomain (PACKAGE_TARNAME);
145 : :
146 : : /* Parse and process arguments. */
147 : 10 : int remaining;
148 : 10 : (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
149 : :
150 : : /* Tell the library which version we are expecting. */
151 : 10 : (void) elf_version (EV_CURRENT);
152 : :
153 : 10 : int result = 0;
154 [ - + ]: 10 : if (remaining == argc)
155 : : /* The user didn't specify a name so we use a.out. */
156 : 0 : result = process_file ("a.out", false);
157 : : else
158 : : {
159 : : /* Process all the remaining files. */
160 : 10 : const bool more_than_one = remaining + 1 < argc;
161 : :
162 : 10 : do
163 : 10 : result |= process_file (argv[remaining], more_than_one);
164 [ - + ]: 10 : while (++remaining < argc);
165 : : }
166 : :
167 : 10 : return result;
168 : : }
169 : :
170 : :
171 : : /* Handle program arguments. */
172 : : static error_t
173 : 60 : parse_opt (int key, char *arg,
174 : : struct argp_state *state __attribute__ ((unused)))
175 : : {
176 : : /* True if any of the control options is set. */
177 : 60 : static bool any_control_option;
178 : :
179 [ - + + - : 60 : switch (key)
+ + ]
180 : : {
181 : 0 : case 'j':
182 : : {
183 : 0 : struct section_list *newp = xmalloc (sizeof (*newp));
184 : 0 : char *endp;
185 : 0 : newp->scnndx = strtoul (arg, &endp, 0);
186 [ # # ]: 0 : if (*endp == 0)
187 : 0 : newp->is_name = false;
188 : : else
189 : : {
190 : 0 : newp->name = arg;
191 : 0 : newp->is_name = true;
192 : : }
193 : 0 : newp->next = section_list;
194 : 0 : section_list = newp;
195 : : }
196 : 0 : any_control_option = true;
197 : 0 : break;
198 : :
199 : 8 : case 'd':
200 : 8 : print_disasm = true;
201 : 8 : any_control_option = true;
202 : 8 : break;
203 : :
204 : 2 : case 'r':
205 : 2 : print_relocs = true;
206 : 2 : any_control_option = true;
207 : 2 : break;
208 : :
209 : 0 : case 's':
210 : 0 : print_full_content = true;
211 : 0 : any_control_option = true;
212 : 0 : break;
213 : :
214 : 10 : case ARGP_KEY_FINI:
215 [ - + ]: 10 : if (! any_control_option)
216 : : {
217 : 0 : fputs (_("No operation specified.\n"), stderr);
218 : 0 : argp_help (&argp, stderr, ARGP_HELP_SEE,
219 : : program_invocation_short_name);
220 : 0 : exit (EXIT_FAILURE);
221 : : }
222 : : /* We only use this for checking the number of arguments, we don't
223 : : actually want to consume them. */
224 : : FALLTHROUGH;
225 : : default:
226 : : return ARGP_ERR_UNKNOWN;
227 : : }
228 : : return 0;
229 : : }
230 : :
231 : :
232 : : /* Open the file and determine the type. */
233 : : static int
234 : 10 : process_file (const char *fname, bool more_than_one)
235 : : {
236 : : /* Open the file. */
237 : 10 : int fd = open (fname, O_RDONLY);
238 [ - + ]: 10 : if (fd == -1)
239 : : {
240 : 0 : error (0, errno, _("cannot open %s"), fname);
241 : 0 : return 1;
242 : : }
243 : :
244 : : /* Now get the ELF descriptor. */
245 : 10 : Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
246 [ + - ]: 10 : if (elf != NULL)
247 : : {
248 [ + - ]: 10 : if (elf_kind (elf) == ELF_K_ELF)
249 : : {
250 [ + - ]: 20 : int result = handle_elf (elf, more_than_one ? "" : NULL,
251 : : fname, NULL);
252 : :
253 [ - + ]: 10 : if (elf_end (elf) != 0)
254 : 0 : INTERNAL_ERROR (fname);
255 : :
256 [ - + ]: 10 : if (close (fd) != 0)
257 : 0 : error_exit (errno, _("while close `%s'"), fname);
258 : :
259 : : return result;
260 : : }
261 [ # # ]: 0 : else if (elf_kind (elf) == ELF_K_AR)
262 : : {
263 : 0 : int result = handle_ar (fd, elf, NULL, fname, NULL);
264 : :
265 [ # # ]: 0 : if (elf_end (elf) != 0)
266 : 0 : INTERNAL_ERROR (fname);
267 : :
268 [ # # ]: 0 : if (close (fd) != 0)
269 : 0 : error_exit (errno, _("while close `%s'"), fname);
270 : :
271 : : return result;
272 : : }
273 : :
274 : : /* We cannot handle this type. Close the descriptor anyway. */
275 [ # # ]: 0 : if (elf_end (elf) != 0)
276 : 0 : INTERNAL_ERROR (fname);
277 : : }
278 : :
279 : 0 : error (0, 0, _("%s: File format not recognized"), fname);
280 : :
281 : 0 : return 1;
282 : : }
283 : :
284 : :
285 : : static int
286 : 0 : handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
287 : : const char *suffix)
288 : 0 : {
289 : 0 : size_t fname_len = strlen (fname) + 1;
290 [ # # ]: 0 : size_t prefix_len = prefix != NULL ? strlen (prefix) : 0;
291 : 0 : char new_prefix[prefix_len + fname_len + 2];
292 [ # # ]: 0 : size_t suffix_len = suffix != NULL ? strlen (suffix) : 0;
293 : 0 : char new_suffix[suffix_len + 2];
294 : 0 : Elf *subelf;
295 : 0 : Elf_Cmd cmd = ELF_C_READ_MMAP;
296 : 0 : int result = 0;
297 : :
298 : 0 : char *cp = new_prefix;
299 [ # # ]: 0 : if (prefix != NULL)
300 : 0 : cp = stpcpy (cp, prefix);
301 [ # # ]: 0 : cp = stpcpy (cp, fname);
302 : 0 : stpcpy (cp, "[");
303 : :
304 : 0 : cp = new_suffix;
305 [ # # ]: 0 : if (suffix != NULL)
306 : 0 : cp = stpcpy (cp, suffix);
307 : 0 : stpcpy (cp, "]");
308 : :
309 : : /* Process all the files contained in the archive. */
310 [ # # ]: 0 : while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
311 : : {
312 : : /* The the header for this element. */
313 : 0 : Elf_Arhdr *arhdr = elf_getarhdr (subelf);
314 : :
315 : : /* Skip over the index entries. */
316 [ # # ]: 0 : if (strcmp (arhdr->ar_name, "/") != 0
317 [ # # ]: 0 : && strcmp (arhdr->ar_name, "//") != 0)
318 : : {
319 [ # # ]: 0 : if (elf_kind (subelf) == ELF_K_ELF)
320 : 0 : result |= handle_elf (subelf, new_prefix, arhdr->ar_name,
321 : : new_suffix);
322 [ # # ]: 0 : else if (elf_kind (subelf) == ELF_K_AR)
323 : 0 : result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name,
324 : : new_suffix);
325 : : else
326 : : {
327 : 0 : error (0, 0, _("%s%s%s: file format not recognized"),
328 : : new_prefix, arhdr->ar_name, new_suffix);
329 : 0 : result = 1;
330 : : }
331 : : }
332 : :
333 : : /* Get next archive element. */
334 : 0 : cmd = elf_next (subelf);
335 [ # # ]: 0 : if (elf_end (subelf) != 0)
336 : 0 : INTERNAL_ERROR (fname);
337 : : }
338 : :
339 : 0 : return result;
340 : : }
341 : :
342 : :
343 : : static void
344 : 36 : show_relocs_x (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *symdata,
345 : : Elf_Data *xndxdata, size_t symstrndx, size_t shstrndx,
346 : : GElf_Addr r_offset, GElf_Xword r_info, GElf_Sxword r_addend)
347 : : {
348 : 36 : int elfclass = gelf_getclass (ebl->elf);
349 : 36 : char buf[128];
350 : :
351 [ + - ]: 36 : printf ("%0*" PRIx64 " %-20s ",
352 : : elfclass == ELFCLASS32 ? 8 : 16, r_offset,
353 : : ebl_reloc_type_name (ebl, GELF_R_TYPE (r_info), buf, sizeof (buf)));
354 : :
355 : 36 : Elf32_Word xndx;
356 : 36 : GElf_Sym symmem;
357 : 36 : GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (r_info),
358 : : &symmem, &xndx);
359 : :
360 [ - + ]: 36 : if (sym == NULL)
361 : 0 : printf ("<%s %ld>",
362 : : _("INVALID SYMBOL"), (long int) GELF_R_SYM (r_info));
363 [ + + ]: 36 : else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
364 : 20 : printf ("%s",
365 : 20 : elf_strptr (ebl->elf, symstrndx, sym->st_name));
366 : : else
367 : : {
368 : 16 : GElf_Shdr destshdr_mem;
369 : 16 : GElf_Shdr *destshdr;
370 : 16 : destshdr = gelf_getshdr (elf_getscn (ebl->elf,
371 [ + - ]: 16 : sym->st_shndx == SHN_XINDEX
372 : 0 : ? xndx : sym->st_shndx),
373 : : &destshdr_mem);
374 : :
375 [ - + ]: 16 : if (shdr == NULL || destshdr == NULL)
376 : 0 : printf ("<%s %ld>",
377 : : _("INVALID SECTION"),
378 [ # # ]: 0 : (long int) (sym->st_shndx == SHN_XINDEX
379 : 0 : ? xndx : sym->st_shndx));
380 : : else
381 : 16 : printf ("%s",
382 : 16 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
383 : : }
384 : :
385 [ - + ]: 36 : if (r_addend != 0)
386 : : {
387 : 0 : char sign = '+';
388 [ # # ]: 0 : if (r_addend < 0)
389 : : {
390 : 0 : sign = '-';
391 : 0 : r_addend = -r_addend;
392 : : }
393 : 0 : printf ("%c%#" PRIx64, sign, r_addend);
394 : : }
395 : 36 : putchar ('\n');
396 : 36 : }
397 : :
398 : :
399 : : static void
400 : 10 : show_relocs_rel (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data,
401 : : Elf_Data *symdata, Elf_Data *xndxdata, size_t symstrndx,
402 : : size_t shstrndx)
403 : : {
404 : 10 : size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_REL, 1, EV_CURRENT);
405 : 10 : int nentries = shdr->sh_size / sh_entsize;
406 : :
407 [ + + ]: 46 : for (int cnt = 0; cnt < nentries; ++cnt)
408 : : {
409 : 36 : GElf_Rel relmem;
410 : 36 : GElf_Rel *rel;
411 : :
412 : 36 : rel = gelf_getrel (data, cnt, &relmem);
413 [ + - ]: 36 : if (rel != NULL)
414 : 36 : show_relocs_x (ebl, shdr, symdata, xndxdata, symstrndx, shstrndx,
415 : : rel->r_offset, rel->r_info, 0);
416 : : }
417 : 10 : }
418 : :
419 : :
420 : : static void
421 : 0 : show_relocs_rela (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data,
422 : : Elf_Data *symdata, Elf_Data *xndxdata, size_t symstrndx,
423 : : size_t shstrndx)
424 : : {
425 : 0 : size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_RELA, 1, EV_CURRENT);
426 : 0 : int nentries = shdr->sh_size / sh_entsize;
427 : :
428 [ # # ]: 0 : for (int cnt = 0; cnt < nentries; ++cnt)
429 : : {
430 : 0 : GElf_Rela relmem;
431 : 0 : GElf_Rela *rel;
432 : :
433 : 0 : rel = gelf_getrela (data, cnt, &relmem);
434 [ # # ]: 0 : if (rel != NULL)
435 : 0 : show_relocs_x (ebl, shdr, symdata, xndxdata, symstrndx, shstrndx,
436 : : rel->r_offset, rel->r_info, rel->r_addend);
437 : : }
438 : 0 : }
439 : :
440 : :
441 : : static bool
442 : 18 : section_match (Elf *elf, uint32_t scnndx, GElf_Shdr *shdr, size_t shstrndx)
443 : : {
444 [ - + ]: 18 : if (section_list == NULL)
445 : : return true;
446 : :
447 : 0 : struct section_list *runp = section_list;
448 : 0 : const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
449 : :
450 : 0 : do
451 : : {
452 [ # # ]: 0 : if (runp->is_name)
453 : : {
454 [ # # # # ]: 0 : if (name && strcmp (runp->name, name) == 0)
455 : : return true;
456 : : }
457 : : else
458 : : {
459 [ # # ]: 0 : if (runp->scnndx == scnndx)
460 : : return true;
461 : : }
462 : :
463 : 0 : runp = runp->next;
464 : : }
465 [ # # ]: 0 : while (runp != NULL);
466 : :
467 : : return false;
468 : : }
469 : :
470 : :
471 : : static int
472 : 2 : show_relocs (Ebl *ebl, const char *fname, uint32_t shstrndx)
473 : : {
474 : 2 : int elfclass = gelf_getclass (ebl->elf);
475 : :
476 : 2 : Elf_Scn *scn = NULL;
477 [ + + ]: 36 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
478 : : {
479 : 34 : GElf_Shdr shdr_mem;
480 : 34 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
481 : :
482 [ - + ]: 34 : if (shdr == NULL)
483 : 0 : INTERNAL_ERROR (fname);
484 : :
485 [ + + ]: 34 : if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
486 : : {
487 [ - + ]: 10 : if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
488 : 0 : continue;
489 : :
490 : 10 : GElf_Shdr destshdr_mem;
491 : 10 : GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf,
492 : 10 : shdr->sh_info),
493 : : &destshdr_mem);
494 [ - + ]: 10 : if (unlikely (destshdr == NULL))
495 : 0 : continue;
496 : :
497 [ + - ]: 20 : printf (_("\nRELOCATION RECORDS FOR [%s]:\n"
498 : : "%-*s TYPE VALUE\n"),
499 : 10 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
500 : : elfclass == ELFCLASS32 ? 8 : 16, _("OFFSET"));
501 : :
502 : : /* Get the data of the section. */
503 : 10 : Elf_Data *data = elf_getdata (scn, NULL);
504 [ - + ]: 10 : if (data == NULL)
505 : 0 : continue;
506 : :
507 : : /* Get the symbol table information. */
508 : 10 : Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
509 : 10 : GElf_Shdr symshdr_mem;
510 : 10 : GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
511 : 10 : Elf_Data *symdata = elf_getdata (symscn, NULL);
512 [ - + ]: 10 : if (unlikely (symshdr == NULL || symdata == NULL))
513 : 0 : continue;
514 : :
515 : : /* Search for the optional extended section index table. */
516 : 180 : Elf_Data *xndxdata = NULL;
517 : : Elf_Scn *xndxscn = NULL;
518 [ + + ]: 180 : while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL)
519 : : {
520 : 170 : GElf_Shdr xndxshdr_mem;
521 : 170 : GElf_Shdr *xndxshdr;
522 : :
523 : 170 : xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
524 [ + - - + ]: 170 : if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
525 [ # # ]: 0 : && xndxshdr->sh_link == elf_ndxscn (symscn))
526 : : {
527 : : /* Found it. */
528 : 0 : xndxdata = elf_getdata (xndxscn, NULL);
529 : 0 : break;
530 : : }
531 : : }
532 : :
533 [ + - ]: 10 : if (shdr->sh_type == SHT_REL)
534 : 10 : show_relocs_rel (ebl, shdr, data, symdata, xndxdata,
535 : 10 : symshdr->sh_link, shstrndx);
536 : : else
537 : 0 : show_relocs_rela (ebl, shdr, data, symdata, xndxdata,
538 : 0 : symshdr->sh_link, shstrndx);
539 : :
540 : 10 : putchar ('\n');
541 : : }
542 : : }
543 : :
544 : 2 : return 0;
545 : : }
546 : :
547 : :
548 : : static int
549 : 0 : show_full_content (Ebl *ebl, const char *fname, uint32_t shstrndx)
550 : : {
551 : 0 : Elf_Scn *scn = NULL;
552 [ # # ]: 0 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
553 : : {
554 : 0 : GElf_Shdr shdr_mem;
555 : 0 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
556 : :
557 [ # # ]: 0 : if (shdr == NULL)
558 : 0 : INTERNAL_ERROR (fname);
559 : :
560 [ # # # # ]: 0 : if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0)
561 : : {
562 [ # # ]: 0 : if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
563 : 0 : continue;
564 : :
565 : 0 : printf (_("Contents of section %s:\n"),
566 : 0 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
567 : :
568 : : /* Get the data of the section. */
569 : 0 : Elf_Data *data = elf_getdata (scn, NULL);
570 [ # # ]: 0 : if (data == NULL)
571 : 0 : continue;
572 : :
573 : 0 : unsigned char *cp = data->d_buf;
574 : 0 : size_t cnt;
575 [ # # ]: 0 : for (cnt = 0; cnt + 16 < data->d_size; cp += 16, cnt += 16)
576 : : {
577 : 0 : printf (" %04zx ", cnt);
578 : :
579 [ # # ]: 0 : for (size_t inner = 0; inner < 16; inner += 4)
580 : 0 : printf ("%02hhx%02hhx%02hhx%02hhx ",
581 : 0 : cp[inner], cp[inner + 1], cp[inner + 2],
582 : 0 : cp[inner + 3]);
583 [ # # ]: 0 : fputc_unlocked (' ', stdout);
584 : :
585 [ # # ]: 0 : for (size_t inner = 0; inner < 16; ++inner)
586 [ # # # # ]: 0 : fputc_unlocked (isascii (cp[inner]) && isprint (cp[inner])
587 : : ? cp[inner] : '.', stdout);
588 [ # # ]: 0 : fputc_unlocked ('\n', stdout);
589 : : }
590 : :
591 : 0 : printf (" %04zx ", cnt);
592 : :
593 : 0 : size_t remaining = data->d_size - cnt;
594 : 0 : size_t inner;
595 [ # # ]: 0 : for (inner = 0; inner + 4 <= remaining; inner += 4)
596 : 0 : printf ("%02hhx%02hhx%02hhx%02hhx ",
597 : 0 : cp[inner], cp[inner + 1], cp[inner + 2], cp[inner + 3]);
598 : :
599 [ # # ]: 0 : for (; inner < remaining; ++inner)
600 : 0 : printf ("%02hhx", cp[inner]);
601 : :
602 [ # # ]: 0 : for (inner = 2 * (16 - inner) + (16 - inner + 3) / 4 + 1; inner > 0;
603 : 0 : --inner)
604 [ # # ]: 0 : fputc_unlocked (' ', stdout);
605 : :
606 [ # # ]: 0 : for (inner = 0; inner < remaining; ++inner)
607 [ # # # # ]: 0 : fputc_unlocked (isascii (cp[inner]) && isprint (cp[inner])
608 : : ? cp[inner] : '.', stdout);
609 [ # # ]: 0 : fputc_unlocked ('\n', stdout);
610 : :
611 [ # # ]: 0 : fputc_unlocked ('\n', stdout);
612 : : }
613 : : }
614 : :
615 : 0 : return 0;
616 : : }
617 : :
618 : :
619 : : struct disasm_info
620 : : {
621 : : GElf_Addr addr;
622 : : const uint8_t *cur;
623 : : const uint8_t *last_end;
624 : : const char *address_color;
625 : : const char *bytes_color;
626 : : };
627 : :
628 : :
629 : : // XXX This is not the preferred output for all architectures. Needs
630 : : // XXX customization, too.
631 : : static int
632 : 39402 : disasm_output (char *buf, size_t buflen, void *arg)
633 : : {
634 : 39402 : struct disasm_info *info = (struct disasm_info *) arg;
635 : :
636 [ - + ]: 39402 : if (info->address_color != NULL)
637 : 39402 : printf ("%s%8" PRIx64 "%s: ",
638 : 0 : info->address_color, (uint64_t) info->addr, color_off);
639 : : else
640 : 39402 : printf ("%8" PRIx64 ": ", (uint64_t) info->addr);
641 : :
642 [ - + ]: 39402 : if (info->bytes_color != NULL)
643 : 0 : fputs_unlocked (info->bytes_color, stdout);
644 : : size_t cnt;
645 [ + + ]: 216786 : for (cnt = 0; cnt < (size_t) MIN (info->cur - info->last_end, 8); ++cnt)
646 : 177384 : printf (" %02" PRIx8, info->last_end[cnt]);
647 [ - + ]: 39402 : if (info->bytes_color != NULL)
648 : 0 : fputs_unlocked (color_off, stdout);
649 : :
650 : 78804 : printf ("%*s %.*s\n",
651 : 39402 : (int) (8 - cnt) * 3 + 1, "", (int) buflen, buf);
652 : :
653 : 39402 : info->addr += cnt;
654 : :
655 : : /* We limit the number of bytes printed before the mnemonic to 8.
656 : : Print the rest on a separate, following line. */
657 [ + + ]: 39402 : if (info->cur - info->last_end > 8)
658 : : {
659 [ - + ]: 906 : if (info->address_color != NULL)
660 : 0 : printf ("%s%8" PRIx64 "%s: ",
661 : : info->address_color, (uint64_t) info->addr, color_off);
662 : : else
663 : 906 : printf ("%8" PRIx64 ": ", (uint64_t) info->addr);
664 : :
665 [ - + ]: 906 : if (info->bytes_color != NULL)
666 : 0 : fputs_unlocked (info->bytes_color, stdout);
667 [ + + ]: 2602 : for (; cnt < (size_t) (info->cur - info->last_end); ++cnt)
668 : 1696 : printf (" %02" PRIx8, info->last_end[cnt]);
669 [ - + ]: 906 : if (info->bytes_color != NULL)
670 : 0 : fputs_unlocked (color_off, stdout);
671 [ - + ]: 906 : putchar_unlocked ('\n');
672 : 906 : info->addr += info->cur - info->last_end - 8;
673 : : }
674 : :
675 : 39402 : info->last_end = info->cur;
676 : :
677 : 39402 : return 0;
678 : : }
679 : :
680 : :
681 : : static int
682 : 8 : show_disasm (Ebl *ebl, const char *fname, uint32_t shstrndx)
683 : : {
684 : 8 : DisasmCtx_t *ctx = disasm_begin (ebl, ebl->elf, NULL /* XXX TODO */);
685 [ + - ]: 8 : if (ctx == NULL)
686 : 0 : error_exit (0, _("cannot disassemble"));
687 : :
688 : : Elf_Scn *scn = NULL;
689 [ + + ]: 44 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
690 : : {
691 : 36 : GElf_Shdr shdr_mem;
692 : 36 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
693 : :
694 [ - + ]: 36 : if (shdr == NULL)
695 : 0 : INTERNAL_ERROR (fname);
696 : :
697 [ + + + + ]: 36 : if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0
698 [ + - ]: 8 : && (shdr->sh_flags & SHF_EXECINSTR) != 0)
699 : : {
700 [ - + ]: 8 : if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
701 : 0 : continue;
702 : :
703 : 8 : Elf_Data *data = elf_getdata (scn, NULL);
704 [ - + ]: 8 : if (data == NULL)
705 : 0 : continue;
706 : :
707 : 8 : printf ("Disassembly of section %s:\n\n",
708 : 8 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
709 : :
710 : 8 : struct disasm_info info;
711 : 8 : info.addr = shdr->sh_addr;
712 : 8 : info.last_end = info.cur = data->d_buf;
713 : 8 : char *fmt;
714 [ - + ]: 8 : if (color_mode)
715 : : {
716 : 0 : info.address_color = color_address;
717 : 0 : info.bytes_color = color_bytes;
718 : :
719 : 0 : fmt = xasprintf ("%s%%7m %s%%.1o,%s%%.2o,%s%%.3o,,%s%%.4o%s%%.5o%%34a %s%%l",
720 [ # # ]: 0 : color_mnemonic ?: "",
721 [ # # ]: 0 : color_operand1 ?: "",
722 [ # # ]: 0 : color_operand2 ?: "",
723 [ # # ]: 0 : color_operand3 ?: "",
724 [ # # ]: 0 : color_operand4 ?: "",
725 [ # # ]: 0 : color_operand5 ?: "",
726 [ # # ]: 0 : color_label ?: "");
727 : : }
728 : : else
729 : : {
730 : 8 : info.address_color = info.bytes_color = NULL;
731 : :
732 : 8 : fmt = "%7m %.1o,%.2o,%.3o,%.4o,%.5o%34a %l";
733 : : }
734 : :
735 : 8 : disasm_cb (ctx, &info.cur, info.cur + data->d_size, info.addr,
736 : : fmt, disasm_output, &info, NULL /* XXX */);
737 : :
738 [ - + ]: 8 : if (color_mode)
739 : 0 : free (fmt);
740 : : }
741 : : }
742 : :
743 : 8 : (void) disasm_end (ctx);
744 : :
745 : 8 : return 0;
746 : : }
747 : :
748 : :
749 : : static int
750 : 10 : handle_elf (Elf *elf, const char *prefix, const char *fname,
751 : : const char *suffix)
752 : 10 : {
753 : :
754 : : /* Get the backend for this object file type. */
755 : 10 : Ebl *ebl = ebl_openbackend (elf);
756 [ - + ]: 10 : if (ebl == NULL)
757 : 0 : error_exit (0, _("cannot create backend for elf file"));
758 : :
759 [ + + ]: 20 : printf ("%s: elf%d-%s\n\n",
760 : 10 : fname, gelf_getclass (elf) == ELFCLASS32 ? 32 : 64,
761 : : ebl_backend_name (ebl));
762 : :
763 : : /* Create the full name of the file. */
764 [ - + ]: 10 : size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
765 [ - + ]: 10 : size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
766 : 10 : size_t fname_len = strlen (fname) + 1;
767 : 10 : char fullname[prefix_len + 1 + fname_len + suffix_len];
768 : 10 : char *cp = fullname;
769 [ - + ]: 10 : if (prefix != NULL)
770 : 0 : cp = mempcpy (cp, prefix, prefix_len);
771 [ - + ]: 10 : cp = mempcpy (cp, fname, fname_len);
772 [ - + ]: 10 : if (suffix != NULL)
773 : 0 : memcpy (cp - 1, suffix, suffix_len + 1);
774 : :
775 : : /* Get the section header string table index. */
776 : 10 : size_t shstrndx;
777 [ - + ]: 10 : if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
778 : 0 : error_exit (0, _("cannot get section header string table index"));
779 : :
780 : 10 : int result = 0;
781 [ + + ]: 10 : if (print_disasm)
782 : 8 : result = show_disasm (ebl, fullname, shstrndx);
783 [ + + + - ]: 10 : if (print_relocs && !print_disasm)
784 : 2 : result = show_relocs (ebl, fullname, shstrndx);
785 [ - + ]: 10 : if (print_full_content)
786 : 0 : result = show_full_content (ebl, fullname, shstrndx);
787 : :
788 : : /* Close the ELF backend library descriptor. */
789 : 10 : ebl_closebackend (ebl);
790 : :
791 : 10 : return result;
792 : : }
793 : :
794 : :
795 : : #include "debugpred.h"
|