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 (arhdr != NULL
317 [ # # ]: 0 : && strcmp (arhdr->ar_name, "/") != 0
318 [ # # ]: 0 : && strcmp (arhdr->ar_name, "//") != 0)
319 : : {
320 [ # # ]: 0 : if (elf_kind (subelf) == ELF_K_ELF)
321 : 0 : result |= handle_elf (subelf, new_prefix, arhdr->ar_name,
322 : : new_suffix);
323 [ # # ]: 0 : else if (elf_kind (subelf) == ELF_K_AR)
324 : 0 : result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name,
325 : : new_suffix);
326 : : else
327 : : {
328 : 0 : error (0, 0, _("%s%s%s: file format not recognized"),
329 : : new_prefix, arhdr->ar_name, new_suffix);
330 : 0 : result = 1;
331 : : }
332 : : }
333 : :
334 : : /* Get next archive element. */
335 : 0 : cmd = elf_next (subelf);
336 [ # # ]: 0 : if (elf_end (subelf) != 0)
337 : 0 : INTERNAL_ERROR (fname);
338 : : }
339 : :
340 : 0 : return result;
341 : : }
342 : :
343 : :
344 : : static void
345 : 36 : show_relocs_x (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *symdata,
346 : : Elf_Data *xndxdata, size_t symstrndx, size_t shstrndx,
347 : : GElf_Addr r_offset, GElf_Xword r_info, GElf_Sxword r_addend)
348 : : {
349 : 36 : int elfclass = gelf_getclass (ebl->elf);
350 : 36 : char buf[128];
351 : :
352 [ + - ]: 36 : printf ("%0*" PRIx64 " %-20s ",
353 : : elfclass == ELFCLASS32 ? 8 : 16, r_offset,
354 : : ebl_reloc_type_name (ebl, GELF_R_TYPE (r_info), buf, sizeof (buf)));
355 : :
356 : 36 : Elf32_Word xndx;
357 : 36 : GElf_Sym symmem;
358 : 36 : GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (r_info),
359 : : &symmem, &xndx);
360 : :
361 [ - + ]: 36 : if (sym == NULL)
362 : 0 : printf ("<%s %ld>",
363 : : _("INVALID SYMBOL"), (long int) GELF_R_SYM (r_info));
364 [ + + ]: 36 : else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
365 : 20 : printf ("%s",
366 : 20 : elf_strptr (ebl->elf, symstrndx, sym->st_name));
367 : : else
368 : : {
369 : 16 : GElf_Shdr destshdr_mem;
370 : 16 : GElf_Shdr *destshdr;
371 : 16 : destshdr = gelf_getshdr (elf_getscn (ebl->elf,
372 [ + - ]: 16 : sym->st_shndx == SHN_XINDEX
373 : 0 : ? xndx : sym->st_shndx),
374 : : &destshdr_mem);
375 : :
376 [ - + ]: 16 : if (shdr == NULL || destshdr == NULL)
377 : 0 : printf ("<%s %ld>",
378 : : _("INVALID SECTION"),
379 [ # # ]: 0 : (long int) (sym->st_shndx == SHN_XINDEX
380 : 0 : ? xndx : sym->st_shndx));
381 : : else
382 : 16 : printf ("%s",
383 : 16 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
384 : : }
385 : :
386 [ - + ]: 36 : if (r_addend != 0)
387 : : {
388 : 0 : char sign = '+';
389 [ # # ]: 0 : if (r_addend < 0)
390 : : {
391 : 0 : sign = '-';
392 : 0 : r_addend = -r_addend;
393 : : }
394 : 0 : printf ("%c%#" PRIx64, sign, r_addend);
395 : : }
396 : 36 : putchar ('\n');
397 : 36 : }
398 : :
399 : :
400 : : static void
401 : 10 : show_relocs_rel (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data,
402 : : Elf_Data *symdata, Elf_Data *xndxdata, size_t symstrndx,
403 : : size_t shstrndx)
404 : : {
405 : 10 : size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_REL, 1, EV_CURRENT);
406 : 10 : int nentries = shdr->sh_size / sh_entsize;
407 : :
408 [ + + ]: 46 : for (int cnt = 0; cnt < nentries; ++cnt)
409 : : {
410 : 36 : GElf_Rel relmem;
411 : 36 : GElf_Rel *rel;
412 : :
413 : 36 : rel = gelf_getrel (data, cnt, &relmem);
414 [ + - ]: 36 : if (rel != NULL)
415 : 36 : show_relocs_x (ebl, shdr, symdata, xndxdata, symstrndx, shstrndx,
416 : : rel->r_offset, rel->r_info, 0);
417 : : }
418 : 10 : }
419 : :
420 : :
421 : : static void
422 : 0 : show_relocs_rela (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data,
423 : : Elf_Data *symdata, Elf_Data *xndxdata, size_t symstrndx,
424 : : size_t shstrndx)
425 : : {
426 : 0 : size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_RELA, 1, EV_CURRENT);
427 : 0 : int nentries = shdr->sh_size / sh_entsize;
428 : :
429 [ # # ]: 0 : for (int cnt = 0; cnt < nentries; ++cnt)
430 : : {
431 : 0 : GElf_Rela relmem;
432 : 0 : GElf_Rela *rel;
433 : :
434 : 0 : rel = gelf_getrela (data, cnt, &relmem);
435 [ # # ]: 0 : if (rel != NULL)
436 : 0 : show_relocs_x (ebl, shdr, symdata, xndxdata, symstrndx, shstrndx,
437 : : rel->r_offset, rel->r_info, rel->r_addend);
438 : : }
439 : 0 : }
440 : :
441 : :
442 : : static bool
443 : 18 : section_match (Elf *elf, uint32_t scnndx, GElf_Shdr *shdr, size_t shstrndx)
444 : : {
445 [ - + ]: 18 : if (section_list == NULL)
446 : : return true;
447 : :
448 : 0 : struct section_list *runp = section_list;
449 : 0 : const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
450 : :
451 : 0 : do
452 : : {
453 [ # # ]: 0 : if (runp->is_name)
454 : : {
455 [ # # # # ]: 0 : if (name && strcmp (runp->name, name) == 0)
456 : : return true;
457 : : }
458 : : else
459 : : {
460 [ # # ]: 0 : if (runp->scnndx == scnndx)
461 : : return true;
462 : : }
463 : :
464 : 0 : runp = runp->next;
465 : : }
466 [ # # ]: 0 : while (runp != NULL);
467 : :
468 : : return false;
469 : : }
470 : :
471 : :
472 : : static int
473 : 2 : show_relocs (Ebl *ebl, const char *fname, uint32_t shstrndx)
474 : : {
475 : 2 : int elfclass = gelf_getclass (ebl->elf);
476 : :
477 : 2 : Elf_Scn *scn = NULL;
478 [ + + ]: 36 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
479 : : {
480 : 34 : GElf_Shdr shdr_mem;
481 : 34 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
482 : :
483 [ - + ]: 34 : if (shdr == NULL)
484 : 0 : INTERNAL_ERROR (fname);
485 : :
486 [ + + ]: 34 : if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
487 : : {
488 [ - + ]: 10 : if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
489 : 0 : continue;
490 : :
491 : 10 : GElf_Shdr destshdr_mem;
492 : 10 : GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf,
493 : 10 : shdr->sh_info),
494 : : &destshdr_mem);
495 [ - + ]: 10 : if (unlikely (destshdr == NULL))
496 : 0 : continue;
497 : :
498 [ + - ]: 20 : printf (_("\nRELOCATION RECORDS FOR [%s]:\n"
499 : : "%-*s TYPE VALUE\n"),
500 : 10 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
501 : : elfclass == ELFCLASS32 ? 8 : 16, _("OFFSET"));
502 : :
503 : : /* Get the data of the section. */
504 : 10 : Elf_Data *data = elf_getdata (scn, NULL);
505 [ - + ]: 10 : if (data == NULL)
506 : 0 : continue;
507 : :
508 : : /* Get the symbol table information. */
509 : 10 : Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
510 : 10 : GElf_Shdr symshdr_mem;
511 : 10 : GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
512 : 10 : Elf_Data *symdata = elf_getdata (symscn, NULL);
513 [ - + ]: 10 : if (unlikely (symshdr == NULL || symdata == NULL))
514 : 0 : continue;
515 : :
516 : : /* Search for the optional extended section index table. */
517 : 180 : Elf_Data *xndxdata = NULL;
518 : : Elf_Scn *xndxscn = NULL;
519 [ + + ]: 180 : while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL)
520 : : {
521 : 170 : GElf_Shdr xndxshdr_mem;
522 : 170 : GElf_Shdr *xndxshdr;
523 : :
524 : 170 : xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
525 [ + - - + ]: 170 : if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
526 [ # # ]: 0 : && xndxshdr->sh_link == elf_ndxscn (symscn))
527 : : {
528 : : /* Found it. */
529 : 0 : xndxdata = elf_getdata (xndxscn, NULL);
530 : 0 : break;
531 : : }
532 : : }
533 : :
534 [ + - ]: 10 : if (shdr->sh_type == SHT_REL)
535 : 10 : show_relocs_rel (ebl, shdr, data, symdata, xndxdata,
536 : 10 : symshdr->sh_link, shstrndx);
537 : : else
538 : 0 : show_relocs_rela (ebl, shdr, data, symdata, xndxdata,
539 : 0 : symshdr->sh_link, shstrndx);
540 : :
541 : 10 : putchar ('\n');
542 : : }
543 : : }
544 : :
545 : 2 : return 0;
546 : : }
547 : :
548 : :
549 : : static int
550 : 0 : show_full_content (Ebl *ebl, const char *fname, uint32_t shstrndx)
551 : : {
552 : 0 : Elf_Scn *scn = NULL;
553 [ # # ]: 0 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
554 : : {
555 : 0 : GElf_Shdr shdr_mem;
556 : 0 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
557 : :
558 [ # # ]: 0 : if (shdr == NULL)
559 : 0 : INTERNAL_ERROR (fname);
560 : :
561 [ # # # # ]: 0 : if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0)
562 : : {
563 [ # # ]: 0 : if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
564 : 0 : continue;
565 : :
566 : 0 : printf (_("Contents of section %s:\n"),
567 : 0 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
568 : :
569 : : /* Get the data of the section. */
570 : 0 : Elf_Data *data = elf_getdata (scn, NULL);
571 [ # # ]: 0 : if (data == NULL)
572 : 0 : continue;
573 : :
574 : 0 : unsigned char *cp = data->d_buf;
575 : 0 : size_t cnt;
576 [ # # ]: 0 : for (cnt = 0; cnt + 16 < data->d_size; cp += 16, cnt += 16)
577 : : {
578 : 0 : printf (" %04zx ", cnt);
579 : :
580 [ # # ]: 0 : for (size_t inner = 0; inner < 16; inner += 4)
581 : 0 : printf ("%02hhx%02hhx%02hhx%02hhx ",
582 : 0 : cp[inner], cp[inner + 1], cp[inner + 2],
583 : 0 : cp[inner + 3]);
584 : 0 : fputc (' ', stdout);
585 : :
586 [ # # ]: 0 : for (size_t inner = 0; inner < 16; ++inner)
587 [ # # # # ]: 0 : fputc (isascii (cp[inner]) && isprint (cp[inner])
588 : : ? cp[inner] : '.', stdout);
589 : 0 : fputc ('\n', stdout);
590 : : }
591 : :
592 : 0 : printf (" %04zx ", cnt);
593 : :
594 : 0 : size_t remaining = data->d_size - cnt;
595 : 0 : size_t inner;
596 [ # # ]: 0 : for (inner = 0; inner + 4 <= remaining; inner += 4)
597 : 0 : printf ("%02hhx%02hhx%02hhx%02hhx ",
598 : 0 : cp[inner], cp[inner + 1], cp[inner + 2], cp[inner + 3]);
599 : :
600 [ # # ]: 0 : for (; inner < remaining; ++inner)
601 : 0 : printf ("%02hhx", cp[inner]);
602 : :
603 [ # # ]: 0 : for (inner = 2 * (16 - inner) + (16 - inner + 3) / 4 + 1; inner > 0;
604 : 0 : --inner)
605 : 0 : fputc (' ', stdout);
606 : :
607 [ # # ]: 0 : for (inner = 0; inner < remaining; ++inner)
608 [ # # # # ]: 0 : fputc (isascii (cp[inner]) && isprint (cp[inner])
609 : : ? cp[inner] : '.', stdout);
610 : 0 : fputc ('\n', stdout);
611 : :
612 : 0 : fputc ('\n', stdout);
613 : : }
614 : : }
615 : :
616 : 0 : return 0;
617 : : }
618 : :
619 : :
620 : : struct disasm_info
621 : : {
622 : : GElf_Addr addr;
623 : : const uint8_t *cur;
624 : : const uint8_t *last_end;
625 : : const char *address_color;
626 : : const char *bytes_color;
627 : : };
628 : :
629 : :
630 : : // XXX This is not the preferred output for all architectures. Needs
631 : : // XXX customization, too.
632 : : static int
633 : 39402 : disasm_output (char *buf, size_t buflen, void *arg)
634 : : {
635 : 39402 : struct disasm_info *info = (struct disasm_info *) arg;
636 : :
637 [ - + ]: 39402 : if (info->address_color != NULL)
638 : 39402 : printf ("%s%8" PRIx64 "%s: ",
639 : 0 : info->address_color, (uint64_t) info->addr, color_off);
640 : : else
641 : 39402 : printf ("%8" PRIx64 ": ", (uint64_t) info->addr);
642 : :
643 [ - + ]: 39402 : if (info->bytes_color != NULL)
644 : 0 : fputs (info->bytes_color, stdout);
645 : : size_t cnt;
646 [ + + ]: 216786 : for (cnt = 0; cnt < (size_t) MIN (info->cur - info->last_end, 8); ++cnt)
647 : 177384 : printf (" %02" PRIx8, info->last_end[cnt]);
648 [ - + ]: 39402 : if (info->bytes_color != NULL)
649 : 0 : fputs (color_off, stdout);
650 : :
651 : 78804 : printf ("%*s %.*s\n",
652 : 39402 : (int) (8 - cnt) * 3 + 1, "", (int) buflen, buf);
653 : :
654 : 39402 : info->addr += cnt;
655 : :
656 : : /* We limit the number of bytes printed before the mnemonic to 8.
657 : : Print the rest on a separate, following line. */
658 [ + + ]: 39402 : if (info->cur - info->last_end > 8)
659 : : {
660 [ - + ]: 906 : if (info->address_color != NULL)
661 : 0 : printf ("%s%8" PRIx64 "%s: ",
662 : : info->address_color, (uint64_t) info->addr, color_off);
663 : : else
664 : 906 : printf ("%8" PRIx64 ": ", (uint64_t) info->addr);
665 : :
666 [ - + ]: 906 : if (info->bytes_color != NULL)
667 : 0 : fputs (info->bytes_color, stdout);
668 [ + + ]: 2602 : for (; cnt < (size_t) (info->cur - info->last_end); ++cnt)
669 : 1696 : printf (" %02" PRIx8, info->last_end[cnt]);
670 [ - + ]: 906 : if (info->bytes_color != NULL)
671 : 0 : fputs (color_off, stdout);
672 : 906 : putchar ('\n');
673 : 906 : info->addr += info->cur - info->last_end - 8;
674 : : }
675 : :
676 : 39402 : info->last_end = info->cur;
677 : :
678 : 39402 : return 0;
679 : : }
680 : :
681 : :
682 : : static int
683 : 8 : show_disasm (Ebl *ebl, const char *fname, uint32_t shstrndx)
684 : : {
685 : 8 : DisasmCtx_t *ctx = disasm_begin (ebl, ebl->elf, NULL /* XXX TODO */);
686 [ + - ]: 8 : if (ctx == NULL)
687 : 0 : error_exit (0, _("cannot disassemble"));
688 : :
689 : : Elf_Scn *scn = NULL;
690 [ + + ]: 44 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
691 : : {
692 : 36 : GElf_Shdr shdr_mem;
693 : 36 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
694 : :
695 [ - + ]: 36 : if (shdr == NULL)
696 : 0 : INTERNAL_ERROR (fname);
697 : :
698 [ + + + + ]: 36 : if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0
699 [ + - ]: 8 : && (shdr->sh_flags & SHF_EXECINSTR) != 0)
700 : : {
701 [ - + ]: 8 : if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
702 : 0 : continue;
703 : :
704 : 8 : Elf_Data *data = elf_getdata (scn, NULL);
705 [ - + ]: 8 : if (data == NULL)
706 : 0 : continue;
707 : :
708 : 8 : printf ("Disassembly of section %s:\n\n",
709 : 8 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
710 : :
711 : 8 : struct disasm_info info;
712 : 8 : info.addr = shdr->sh_addr;
713 : 8 : info.last_end = info.cur = data->d_buf;
714 : 8 : char *fmt;
715 [ - + ]: 8 : if (color_mode)
716 : : {
717 : 0 : info.address_color = color_address;
718 : 0 : info.bytes_color = color_bytes;
719 : :
720 : 0 : fmt = xasprintf ("%s%%7m %s%%.1o,%s%%.2o,%s%%.3o,,%s%%.4o%s%%.5o%%34a %s%%l",
721 [ # # ]: 0 : color_mnemonic ?: "",
722 [ # # ]: 0 : color_operand1 ?: "",
723 [ # # ]: 0 : color_operand2 ?: "",
724 [ # # ]: 0 : color_operand3 ?: "",
725 [ # # ]: 0 : color_operand4 ?: "",
726 [ # # ]: 0 : color_operand5 ?: "",
727 [ # # ]: 0 : color_label ?: "");
728 : : }
729 : : else
730 : : {
731 : 8 : info.address_color = info.bytes_color = NULL;
732 : :
733 : 8 : fmt = "%7m %.1o,%.2o,%.3o,%.4o,%.5o%34a %l";
734 : : }
735 : :
736 : 8 : disasm_cb (ctx, &info.cur, info.cur + data->d_size, info.addr,
737 : : fmt, disasm_output, &info, NULL /* XXX */);
738 : :
739 [ - + ]: 8 : if (color_mode)
740 : 0 : free (fmt);
741 : : }
742 : : }
743 : :
744 : 8 : (void) disasm_end (ctx);
745 : :
746 : 8 : return 0;
747 : : }
748 : :
749 : :
750 : : static int
751 : 10 : handle_elf (Elf *elf, const char *prefix, const char *fname,
752 : : const char *suffix)
753 : 10 : {
754 : :
755 : : /* Get the backend for this object file type. */
756 : 10 : Ebl *ebl = ebl_openbackend (elf);
757 [ - + ]: 10 : if (ebl == NULL)
758 : 0 : error_exit (0, _("cannot create backend for elf file"));
759 : :
760 [ + + ]: 20 : printf ("%s: elf%d-%s\n\n",
761 : 10 : fname, gelf_getclass (elf) == ELFCLASS32 ? 32 : 64,
762 : : ebl_backend_name (ebl));
763 : :
764 : : /* Create the full name of the file. */
765 [ - + ]: 10 : size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
766 [ - + ]: 10 : size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
767 : 10 : size_t fname_len = strlen (fname) + 1;
768 : 10 : char fullname[prefix_len + 1 + fname_len + suffix_len];
769 : 10 : char *cp = fullname;
770 [ - + ]: 10 : if (prefix != NULL)
771 : 0 : cp = mempcpy (cp, prefix, prefix_len);
772 [ - + ]: 10 : cp = mempcpy (cp, fname, fname_len);
773 [ - + ]: 10 : if (suffix != NULL)
774 : 0 : memcpy (cp - 1, suffix, suffix_len + 1);
775 : :
776 : : /* Get the section header string table index. */
777 : 10 : size_t shstrndx;
778 [ - + ]: 10 : if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
779 : 0 : error_exit (0, _("cannot get section header string table index"));
780 : :
781 : 10 : int result = 0;
782 [ + + ]: 10 : if (print_disasm)
783 : 8 : result = show_disasm (ebl, fullname, shstrndx);
784 [ + + + - ]: 10 : if (print_relocs && !print_disasm)
785 : 2 : result = show_relocs (ebl, fullname, shstrndx);
786 [ - + ]: 10 : if (print_full_content)
787 : 0 : result = show_full_content (ebl, fullname, shstrndx);
788 : :
789 : : /* Close the ELF backend library descriptor. */
790 : 10 : ebl_closebackend (ebl);
791 : :
792 : 10 : return result;
793 : : }
794 : :
795 : :
796 : : #include "debugpred.h"
|