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 <libintl.h>
27 : #include <locale.h>
28 : #include <stdbool.h>
29 : #include <stdio.h>
30 : #include <stdio_ext.h>
31 : #include <stdlib.h>
32 : #include <string.h>
33 : #include <unistd.h>
34 :
35 : #include <libeu.h>
36 : #include <system.h>
37 : #include <color.h>
38 : #include <printversion.h>
39 : #include "../libebl/libeblP.h"
40 :
41 :
42 : /* Name and version of program. */
43 : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
44 :
45 : /* Bug report address. */
46 : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
47 :
48 :
49 : /* Definitions of arguments for argp functions. */
50 : static const struct argp_option options[] =
51 : {
52 : { NULL, 0, NULL, 0, N_("Mode selection:"), 0 },
53 : { "reloc", 'r', NULL, 0, N_("Display relocation information."), 0 },
54 : { "full-contents", 's', NULL, 0,
55 : N_("Display the full contents of all sections requested"), 0 },
56 : { "disassemble", 'd', NULL, 0,
57 : N_("Display assembler code of executable sections"), 0 },
58 :
59 : { NULL, 0, NULL, 0, N_("Output content selection:"), 0 },
60 : { "section", 'j', "NAME", 0,
61 : N_("Only display information for section NAME."), 0 },
62 :
63 : { NULL, 0, NULL, 0, NULL, 0 }
64 : };
65 :
66 : /* Short description of program. */
67 : static const char doc[] = N_("\
68 : Show information from FILEs (a.out by default).");
69 :
70 : /* Strings for arguments in help texts. */
71 : static const char args_doc[] = N_("[FILE...]");
72 :
73 : /* Prototype for option handler. */
74 : static error_t parse_opt (int key, char *arg, struct argp_state *state);
75 :
76 : /* Parser children. */
77 : static struct argp_child argp_children[] =
78 : {
79 : { &color_argp, 0, N_("Output formatting"), 2 },
80 : { NULL, 0, NULL, 0}
81 : };
82 :
83 : /* Data structure to communicate with argp functions. */
84 : static const struct argp argp =
85 : {
86 : options, parse_opt, args_doc, doc, argp_children, NULL, NULL
87 : };
88 :
89 :
90 : /* Print symbols in file named FNAME. */
91 : static int process_file (const char *fname, bool more_than_one);
92 :
93 : /* Handle content of archive. */
94 : static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
95 : const char *suffix);
96 :
97 : /* Handle ELF file. */
98 : static int handle_elf (Elf *elf, const char *prefix, const char *fname,
99 : const char *suffix);
100 :
101 :
102 : #define INTERNAL_ERROR(fname) \
103 : error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s): %s"), \
104 : fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1))
105 :
106 :
107 : /* List of sections which should be used. */
108 : static struct section_list
109 : {
110 : bool is_name;
111 : union
112 : {
113 : const char *name;
114 : uint32_t scnndx;
115 : };
116 : struct section_list *next;
117 : } *section_list;
118 :
119 :
120 : /* If true print archive index. */
121 : static bool print_relocs;
122 :
123 : /* If true print full contents of requested sections. */
124 : static bool print_full_content;
125 :
126 : /* If true print disassembled output.. */
127 : static bool print_disasm;
128 :
129 :
130 : int
131 4 : main (int argc, char *argv[])
132 : {
133 : /* We use no threads here which can interfere with handling a stream. */
134 4 : (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
135 4 : (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
136 4 : (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
137 :
138 : /* Set locale. */
139 4 : (void) setlocale (LC_ALL, "");
140 :
141 : /* Make sure the message catalog can be found. */
142 4 : (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
143 :
144 : /* Initialize the message catalog. */
145 4 : (void) textdomain (PACKAGE_TARNAME);
146 :
147 : /* Parse and process arguments. */
148 : int remaining;
149 4 : (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
150 :
151 : /* Tell the library which version we are expecting. */
152 4 : (void) elf_version (EV_CURRENT);
153 :
154 4 : int result = 0;
155 4 : if (remaining == argc)
156 : /* The user didn't specify a name so we use a.out. */
157 0 : result = process_file ("a.out", false);
158 : else
159 : {
160 : /* Process all the remaining files. */
161 4 : const bool more_than_one = remaining + 1 < argc;
162 :
163 : do
164 4 : result |= process_file (argv[remaining], more_than_one);
165 4 : while (++remaining < argc);
166 : }
167 :
168 : return result;
169 : }
170 :
171 :
172 : /* Handle program arguments. */
173 : static error_t
174 24 : parse_opt (int key, char *arg,
175 : struct argp_state *state __attribute__ ((unused)))
176 : {
177 : /* True if any of the control options is set. */
178 : static bool any_control_option;
179 :
180 24 : switch (key)
181 : {
182 0 : case 'j':
183 0 : {
184 0 : struct section_list *newp = xmalloc (sizeof (*newp));
185 : char *endp;
186 0 : newp->scnndx = strtoul (arg, &endp, 0);
187 0 : if (*endp == 0)
188 0 : newp->is_name = false;
189 : else
190 : {
191 0 : newp->name = arg;
192 0 : newp->is_name = true;
193 : }
194 0 : newp->next = section_list;
195 0 : section_list = newp;
196 : }
197 0 : any_control_option = true;
198 0 : break;
199 :
200 3 : case 'd':
201 3 : print_disasm = true;
202 3 : any_control_option = true;
203 3 : break;
204 :
205 1 : case 'r':
206 1 : print_relocs = true;
207 1 : any_control_option = true;
208 1 : break;
209 :
210 0 : case 's':
211 0 : print_full_content = true;
212 0 : any_control_option = true;
213 0 : break;
214 :
215 4 : case ARGP_KEY_FINI:
216 4 : if (! any_control_option)
217 : {
218 0 : fputs (gettext ("No operation specified.\n"), stderr);
219 0 : argp_help (&argp, stderr, ARGP_HELP_SEE,
220 : program_invocation_short_name);
221 0 : exit (EXIT_FAILURE);
222 : }
223 : /* We only use this for checking the number of arguments, we don't
224 : actually want to consume them. */
225 : FALLTHROUGH;
226 : default:
227 : return ARGP_ERR_UNKNOWN;
228 : }
229 : return 0;
230 : }
231 :
232 :
233 : /* Open the file and determine the type. */
234 : static int
235 4 : process_file (const char *fname, bool more_than_one)
236 : {
237 : /* Open the file. */
238 4 : int fd = open (fname, O_RDONLY);
239 4 : if (fd == -1)
240 : {
241 0 : error (0, errno, gettext ("cannot open %s"), fname);
242 0 : return 1;
243 : }
244 :
245 : /* Now get the ELF descriptor. */
246 4 : Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
247 4 : if (elf != NULL)
248 : {
249 4 : if (elf_kind (elf) == ELF_K_ELF)
250 : {
251 4 : int result = handle_elf (elf, more_than_one ? "" : NULL,
252 : fname, NULL);
253 :
254 4 : if (elf_end (elf) != 0)
255 0 : INTERNAL_ERROR (fname);
256 :
257 4 : if (close (fd) != 0)
258 0 : error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname);
259 :
260 : return result;
261 : }
262 0 : else if (elf_kind (elf) == ELF_K_AR)
263 : {
264 0 : int result = handle_ar (fd, elf, NULL, fname, NULL);
265 :
266 0 : if (elf_end (elf) != 0)
267 0 : INTERNAL_ERROR (fname);
268 :
269 0 : if (close (fd) != 0)
270 0 : error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname);
271 :
272 : return result;
273 : }
274 :
275 : /* We cannot handle this type. Close the descriptor anyway. */
276 0 : if (elf_end (elf) != 0)
277 0 : INTERNAL_ERROR (fname);
278 : }
279 :
280 0 : error (0, 0, gettext ("%s: File format not recognized"), fname);
281 :
282 0 : return 1;
283 : }
284 :
285 :
286 : static int
287 0 : handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
288 : const char *suffix)
289 0 : {
290 0 : size_t fname_len = strlen (fname) + 1;
291 0 : size_t prefix_len = prefix != NULL ? strlen (prefix) : 0;
292 0 : char new_prefix[prefix_len + fname_len + 2];
293 0 : size_t suffix_len = suffix != NULL ? strlen (suffix) : 0;
294 0 : char new_suffix[suffix_len + 2];
295 : Elf *subelf;
296 0 : Elf_Cmd cmd = ELF_C_READ_MMAP;
297 0 : int result = 0;
298 :
299 0 : char *cp = new_prefix;
300 0 : if (prefix != NULL)
301 0 : cp = stpcpy (cp, prefix);
302 0 : cp = stpcpy (cp, fname);
303 0 : stpcpy (cp, "[");
304 :
305 0 : cp = new_suffix;
306 0 : if (suffix != NULL)
307 0 : cp = stpcpy (cp, suffix);
308 : stpcpy (cp, "]");
309 :
310 : /* Process all the files contained in the archive. */
311 0 : while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
312 : {
313 : /* The the header for this element. */
314 0 : Elf_Arhdr *arhdr = elf_getarhdr (subelf);
315 :
316 : /* Skip over the index entries. */
317 0 : if (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, gettext ("%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 18 : 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 18 : int elfclass = gelf_getclass (ebl->elf);
350 : 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 : Elf32_Word xndx;
357 : GElf_Sym symmem;
358 18 : GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (r_info),
359 : &symmem, &xndx);
360 :
361 18 : if (sym == NULL)
362 0 : printf ("<%s %ld>",
363 : gettext ("INVALID SYMBOL"), (long int) GELF_R_SYM (r_info));
364 18 : else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
365 10 : printf ("%s",
366 10 : elf_strptr (ebl->elf, symstrndx, sym->st_name));
367 : else
368 : {
369 : GElf_Shdr destshdr_mem;
370 : GElf_Shdr *destshdr;
371 8 : destshdr = gelf_getshdr (elf_getscn (ebl->elf,
372 8 : sym->st_shndx == SHN_XINDEX
373 0 : ? xndx : sym->st_shndx),
374 : &destshdr_mem);
375 :
376 8 : if (shdr == NULL || destshdr == NULL)
377 0 : printf ("<%s %ld>",
378 : gettext ("INVALID SECTION"),
379 0 : (long int) (sym->st_shndx == SHN_XINDEX
380 0 : ? xndx : sym->st_shndx));
381 : else
382 8 : printf ("%s",
383 8 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
384 : }
385 :
386 18 : 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 18 : putchar ('\n');
397 18 : }
398 :
399 :
400 : static void
401 5 : 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 5 : size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_REL, 1, EV_CURRENT);
406 5 : int nentries = shdr->sh_size / sh_entsize;
407 :
408 23 : for (int cnt = 0; cnt < nentries; ++cnt)
409 : {
410 : GElf_Rel relmem;
411 : GElf_Rel *rel;
412 :
413 18 : rel = gelf_getrel (data, cnt, &relmem);
414 18 : if (rel != NULL)
415 18 : show_relocs_x (ebl, shdr, symdata, xndxdata, symstrndx, shstrndx,
416 : rel->r_offset, rel->r_info, 0);
417 : }
418 5 : }
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 : GElf_Rela relmem;
432 : 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 8 : section_match (Elf *elf, uint32_t scnndx, GElf_Shdr *shdr, size_t shstrndx)
444 : {
445 8 : 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 : 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 1 : show_relocs (Ebl *ebl, const char *fname, uint32_t shstrndx)
474 : {
475 1 : int elfclass = gelf_getclass (ebl->elf);
476 :
477 1 : Elf_Scn *scn = NULL;
478 19 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
479 : {
480 : GElf_Shdr shdr_mem;
481 17 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
482 :
483 17 : if (shdr == NULL)
484 0 : INTERNAL_ERROR (fname);
485 :
486 17 : if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
487 : {
488 5 : if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
489 0 : continue;
490 :
491 : GElf_Shdr destshdr_mem;
492 5 : GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf,
493 5 : shdr->sh_info),
494 : &destshdr_mem);
495 5 : if (unlikely (destshdr == NULL))
496 0 : continue;
497 :
498 15 : printf (gettext ("\nRELOCATION RECORDS FOR [%s]:\n"
499 : "%-*s TYPE VALUE\n"),
500 5 : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
501 : elfclass == ELFCLASS32 ? 8 : 16, gettext ("OFFSET"));
502 :
503 : /* Get the data of the section. */
504 5 : Elf_Data *data = elf_getdata (scn, NULL);
505 5 : if (data == NULL)
506 0 : continue;
507 :
508 : /* Get the symbol table information. */
509 5 : Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
510 : GElf_Shdr symshdr_mem;
511 5 : GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
512 5 : Elf_Data *symdata = elf_getdata (symscn, NULL);
513 5 : if (unlikely (symshdr == NULL || symdata == NULL))
514 0 : continue;
515 :
516 : /* Search for the optional extended section index table. */
517 : Elf_Data *xndxdata = NULL;
518 : Elf_Scn *xndxscn = NULL;
519 90 : while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL)
520 : {
521 : GElf_Shdr xndxshdr_mem;
522 : GElf_Shdr *xndxshdr;
523 :
524 85 : xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
525 85 : 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 5 : if (shdr->sh_type == SHT_REL)
535 5 : show_relocs_rel (ebl, shdr, data, symdata, xndxdata,
536 5 : symshdr->sh_link, shstrndx);
537 : else
538 0 : show_relocs_rela (ebl, shdr, data, symdata, xndxdata,
539 0 : symshdr->sh_link, shstrndx);
540 :
541 5 : putchar ('\n');
542 : }
543 : }
544 :
545 1 : return 0;
546 : }
547 :
548 :
549 : static int
550 0 : show_full_content (Ebl *ebl, const char *fname, uint32_t shstrndx)
551 : {
552 : Elf_Scn *scn = NULL;
553 0 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
554 : {
555 : 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 (gettext ("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 : 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_unlocked (' ', stdout);
585 :
586 0 : for (size_t inner = 0; inner < 16; ++inner)
587 0 : fputc_unlocked (isascii (cp[inner]) && isprint (cp[inner])
588 : ? cp[inner] : '.', stdout);
589 0 : fputc_unlocked ('\n', stdout);
590 : }
591 :
592 0 : printf (" %04zx ", cnt);
593 :
594 0 : size_t remaining = data->d_size - cnt;
595 : 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_unlocked (' ', stdout);
606 :
607 0 : for (inner = 0; inner < remaining; ++inner)
608 0 : fputc_unlocked (isascii (cp[inner]) && isprint (cp[inner])
609 : ? cp[inner] : '.', stdout);
610 0 : fputc_unlocked ('\n', stdout);
611 :
612 0 : fputc_unlocked ('\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 19200 : disasm_output (char *buf, size_t buflen, void *arg)
634 : {
635 19200 : struct disasm_info *info = (struct disasm_info *) arg;
636 :
637 19200 : if (info->address_color != NULL)
638 0 : printf ("%s%8" PRIx64 "%s: ",
639 0 : info->address_color, (uint64_t) info->addr, color_off);
640 : else
641 19200 : printf ("%8" PRIx64 ": ", (uint64_t) info->addr);
642 :
643 19200 : if (info->bytes_color != NULL)
644 0 : fputs_unlocked (info->bytes_color, stdout);
645 : size_t cnt;
646 87096 : for (cnt = 0; cnt < (size_t) MIN (info->cur - info->last_end, 8); ++cnt)
647 174192 : printf (" %02" PRIx8, info->last_end[cnt]);
648 19200 : if (info->bytes_color != NULL)
649 0 : fputs_unlocked (color_off, stdout);
650 :
651 57600 : printf ("%*s %.*s\n",
652 19200 : (int) (8 - cnt) * 3 + 1, "", (int) buflen, buf);
653 :
654 19200 : 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 19200 : if (info->cur - info->last_end > 8)
659 : {
660 453 : 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 453 : printf ("%8" PRIx64 ": ", (uint64_t) info->addr);
665 :
666 453 : if (info->bytes_color != NULL)
667 0 : fputs_unlocked (info->bytes_color, stdout);
668 848 : for (; cnt < (size_t) (info->cur - info->last_end); ++cnt)
669 1696 : printf (" %02" PRIx8, info->last_end[cnt]);
670 453 : if (info->bytes_color != NULL)
671 0 : fputs_unlocked (color_off, stdout);
672 453 : putchar_unlocked ('\n');
673 453 : info->addr += info->cur - info->last_end - 8;
674 : }
675 :
676 19200 : info->last_end = info->cur;
677 :
678 19200 : return 0;
679 : }
680 :
681 :
682 : static int
683 3 : show_disasm (Ebl *ebl, const char *fname, uint32_t shstrndx)
684 : {
685 3 : DisasmCtx_t *ctx = disasm_begin (ebl, ebl->elf, NULL /* XXX TODO */);
686 3 : if (ctx == NULL)
687 0 : error (EXIT_FAILURE, 0, gettext ("cannot disassemble"));
688 :
689 : Elf_Scn *scn = NULL;
690 19 : while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
691 : {
692 : GElf_Shdr shdr_mem;
693 16 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
694 :
695 16 : if (shdr == NULL)
696 0 : INTERNAL_ERROR (fname);
697 :
698 16 : if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0
699 3 : && (shdr->sh_flags & SHF_EXECINSTR) != 0)
700 : {
701 3 : if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
702 0 : continue;
703 :
704 3 : Elf_Data *data = elf_getdata (scn, NULL);
705 3 : if (data == NULL)
706 0 : continue;
707 :
708 6 : printf ("Disassembly of section %s:\n\n",
709 3 : elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
710 :
711 : struct disasm_info info;
712 3 : info.addr = shdr->sh_addr;
713 3 : info.last_end = info.cur = data->d_buf;
714 : char *fmt;
715 3 : if (color_mode)
716 : {
717 0 : info.address_color = color_address;
718 0 : info.bytes_color = color_bytes;
719 :
720 0 : if (asprintf (&fmt, "%s%%7m %s%%.1o,%s%%.2o,%s%%.3o%%34a %s%%l",
721 0 : color_mnemonic ?: "",
722 0 : color_operand1 ?: "",
723 0 : color_operand2 ?: "",
724 0 : color_operand3 ?: "",
725 0 : color_label ?: "") < 0)
726 0 : error (EXIT_FAILURE, errno, _("cannot allocate memory"));
727 : }
728 : else
729 : {
730 3 : info.address_color = info.bytes_color = NULL;
731 :
732 3 : fmt = "%7m %.1o,%.2o,%.3o%34a %l";
733 : }
734 :
735 3 : disasm_cb (ctx, &info.cur, info.cur + data->d_size, info.addr,
736 : fmt, disasm_output, &info, NULL /* XXX */);
737 :
738 3 : if (color_mode)
739 0 : free (fmt);
740 : }
741 : }
742 :
743 3 : (void) disasm_end (ctx);
744 :
745 3 : return 0;
746 : }
747 :
748 :
749 : static int
750 4 : handle_elf (Elf *elf, const char *prefix, const char *fname,
751 : const char *suffix)
752 4 : {
753 :
754 : /* Get the backend for this object file type. */
755 4 : Ebl *ebl = ebl_openbackend (elf);
756 :
757 12 : printf ("%s: elf%d-%s\n\n",
758 4 : fname, gelf_getclass (elf) == ELFCLASS32 ? 32 : 64,
759 : ebl_backend_name (ebl));
760 :
761 : /* Create the full name of the file. */
762 4 : size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
763 4 : size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
764 4 : size_t fname_len = strlen (fname) + 1;
765 4 : char fullname[prefix_len + 1 + fname_len + suffix_len];
766 4 : char *cp = fullname;
767 4 : if (prefix != NULL)
768 0 : cp = mempcpy (cp, prefix, prefix_len);
769 4 : cp = mempcpy (cp, fname, fname_len);
770 4 : if (suffix != NULL)
771 0 : memcpy (cp - 1, suffix, suffix_len + 1);
772 :
773 : /* Get the section header string table index. */
774 : size_t shstrndx;
775 4 : if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
776 : error (EXIT_FAILURE, 0,
777 0 : gettext ("cannot get section header string table index"));
778 :
779 4 : int result = 0;
780 4 : if (print_disasm)
781 3 : result = show_disasm (ebl, fullname, shstrndx);
782 4 : if (print_relocs && !print_disasm)
783 1 : result = show_relocs (ebl, fullname, shstrndx);
784 4 : if (print_full_content)
785 0 : result = show_full_content (ebl, fullname, shstrndx);
786 :
787 : /* Close the ELF backend library descriptor. */
788 4 : ebl_closebackend (ebl);
789 :
790 4 : return result;
791 : }
792 :
793 :
794 : #include "debugpred.h"
|