diff options
author | Ulrich Drepper <drepper@gmail.com> | 2012-01-21 18:14:39 -0500 |
---|---|---|
committer | Ulrich Drepper <drepper@gmail.com> | 2012-01-21 18:14:39 -0500 |
commit | c6b3d0c27833c8e0936cb6b8973e8578e3a9421f (patch) | |
tree | a6a9b80d84878e0bfeaf4137dd15e78effbc3162 | |
parent | 5bdee8e7af380c17a3b1d76e3a16764c81fe23c1 (diff) |
Color code output of nm and objdump
-rw-r--r-- | lib/ChangeLog | 7 | ||||
-rw-r--r-- | lib/Makefile.am | 7 | ||||
-rw-r--r-- | lib/color.c | 227 | ||||
-rw-r--r-- | lib/system.h | 34 | ||||
-rw-r--r-- | libcpu/ChangeLog | 5 | ||||
-rw-r--r-- | libcpu/i386_disasm.c | 102 | ||||
-rw-r--r-- | src/ChangeLog | 14 | ||||
-rw-r--r-- | src/nm.c | 94 | ||||
-rw-r--r-- | src/objdump.c | 75 |
9 files changed, 516 insertions, 49 deletions
diff --git a/lib/ChangeLog b/lib/ChangeLog index a6fec309..47e831ea 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,10 @@ +2012-01-21 Ulrich Drepper <drepper@gmail.com> + + * Makefile.am (libeu_a_SOURCES): Add color.c. + * system.h: Declare color_argp. Define color_enum. Declare + color_* variables. + * color.c: New file. + 2011-10-02 Ulrich Drepper <drepper@gmail.com> * system.h: Declare __cxa_demangle. diff --git a/lib/Makefile.am b/lib/Makefile.am index 50d55c56..4ea14361 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to create Makefile.in ## -## Copyright (C) 1996-2010 Red Hat, Inc. +## Copyright (C) 1996-2011 Red Hat, Inc. ## This file is part of Red Hat elfutils. ## ## Red Hat elfutils is free software; you can redistribute it and/or modify @@ -30,8 +30,9 @@ INCLUDES += -I$(srcdir)/../libelf noinst_LIBRARIES = libeu.a -libeu_a_SOURCES = xstrndup.c xmalloc.c next_prime.c \ - crc32.c crc32_file.c md5.c sha1.c +libeu_a_SOURCES = xstrdup.c xstrndup.c xmalloc.c next_prime.c \ + crc32.c crc32_file.c md5.c sha1.c \ + color.c noinst_HEADERS = fixedsizehash.h system.h dynamicsizehash.h list.h md5.h \ sha1.h eu-config.h diff --git a/lib/color.c b/lib/color.c new file mode 100644 index 00000000..ff824485 --- /dev/null +++ b/lib/color.c @@ -0,0 +1,227 @@ +/* Handling of color output. + Copyright (C) 2011 Red Hat, Inc. + This file is part of Red Hat elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2011. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + <http://www.openinventionnetwork.com>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <argp.h> +#include <error.h> +#include <libintl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "system.h" + + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Option values. */ +#define OPT_COLOR 0x100100 + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { "color", OPT_COLOR, "WHEN", OPTION_ARG_OPTIONAL, + N_("colorize the output. WHEN defaults to 'always' or can be 'auto' or 'never'"), 0 }, + + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Parser data structure. */ +const struct argp color_argp = + { + options, parse_opt, NULL, NULL, NULL, NULL, NULL + }; + +/* Coloring mode. */ +enum color_enum color_mode; + +/* Colors to use for the various components. */ +char *color_address = ""; +char *color_bytes = ""; +char *color_mnemonic = ""; +char *color_operand = NULL; +char *color_operand1 = ""; +char *color_operand2 = ""; +char *color_operand3 = ""; +char *color_label = ""; +char *color_undef = ""; +char *color_undef_tls = ""; +char *color_undef_weak = ""; +char *color_symbol = ""; +char *color_tls = ""; +char *color_weak = ""; + +const char color_off[] = "\e[0m"; + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case OPT_COLOR: + if (arg == NULL) + color_mode = color_always; + else + { + static const struct + { + const char str[7]; + enum color_enum mode; + } values[] = + { + { "always", color_always }, + { "yes", color_always }, + { "force", color_always }, + { "never", color_never }, + { "no", color_never }, + { "none", color_never }, + { "auto", color_auto }, + { "tty", color_auto }, + { "if-tty", color_auto } + }; + const int nvalues = sizeof (values) / sizeof (values[0]); + int i; + for (i = 0; i < nvalues; ++i) + if (strcmp (arg, values[i].str) == 0) + { + color_mode = values[i].mode; + if (color_mode == color_auto) + color_mode + = isatty (STDOUT_FILENO) ? color_always : color_never; + break; + } + if (i == nvalues) + { + error (0, 0, dgettext ("elfutils", "\ +%s: invalid argument '%s' for '--color'\n\ +valid arguments are:\n\ + - 'always', 'yes', 'force'\n\ + - 'never', 'no', 'none'\n\ + - 'auto', 'tty', 'if-tty'\n"), + program_invocation_short_name, arg); + argp_help (&color_argp, stderr, ARGP_HELP_SEE, + program_invocation_short_name); + exit (EXIT_FAILURE); + } + } + + if (color_mode == color_always) + { + const char *env = getenv ("ELFUTILS_COLORS"); + if (env != NULL) + { + do + { + const char *start = env; + while (*env != '=' && *env != '\0') + ++env; + if (*env == '=' && env != start) + { + size_t name_len = env - start; + const char *val = ++env; + env = strchrnul (env, ':'); + if (val != env) + { + static const struct + { + unsigned char len; + const char name[sizeof (char *) - 1]; + char **varp; + } known[] = + { +#define E(name, var) { sizeof (#name) - 1, #name, &color_##var } + E (a, address), + E (b, bytes), + E (m, mnemonic), + E (o, operand), + E (o1, operand1), + E (o1, operand2), + E (o1, operand3), + E (l, label), + E (u, undef), + E (ut, undef_tls), + E (uw, undef_weak), + E (sy, symbol), + E (st, tls), + E (sw, weak), + }; + const size_t nknown = (sizeof (known) + / sizeof (known[0])); + + for (size_t i = 0; i < nknown; ++i) + if (name_len == known[i].len + && memcmp (start, known[i].name, name_len) == 0) + { + if (asprintf (known[i].varp, "\e[%.*sm", + (int) (env - val), val) < 0) + error (EXIT_FAILURE, errno, + gettext ("cannot allocate memory")); + break; + } + } + if (*env == ':') + ++env; + } + } + while (*env != '\0'); + + if (color_operand != NULL) + { + if (color_operand1[0] == '\0') + color_operand1 = color_operand; + if (color_operand2[0] == '\0') + color_operand2 = color_operand; + if (color_operand3[0] == '\0') + color_operand3 = color_operand; + } + } +#if 0 + else + { + // XXX Just for testing. + color_address = xstrdup ("\e[38;5;166;1m"); + color_bytes = xstrdup ("\e[38;5;141m"); + color_mnemonic = xstrdup ("\e[38;5;202;1m"); + color_operand1 = xstrdup ("\e[38;5;220m"); + color_operand2 = xstrdup ("\e[38;5;48m"); + color_operand3 = xstrdup ("\e[38;5;112m"); + color_label = xstrdup ("\e[38;5;21m"); + } +#endif + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} diff --git a/lib/system.h b/lib/system.h index 8e32c3a1..3f9f0af5 100644 --- a/lib/system.h +++ b/lib/system.h @@ -49,6 +49,7 @@ #ifndef LIB_SYSTEM_H #define LIB_SYSTEM_H 1 +#include <argp.h> #include <stddef.h> #include <stdint.h> #include <endian.h> @@ -107,4 +108,37 @@ extern int crc32_file (int fd, uint32_t *resp); extern char *__cxa_demangle (const char *mangled_name, char *output_buffer, size_t *length, int *status); + + +/* Color handling. */ + +/* Command line parser. */ +extern const struct argp color_argp; + +/* Coloring mode. */ +enum color_enum + { + color_never = 0, + color_always, + color_auto + } __attribute__ ((packed)); +extern enum color_enum color_mode; + +/* Colors to use for the various components. */ +extern char *color_address; +extern char *color_bytes; +extern char *color_mnemonic; +extern char *color_operand1; +extern char *color_operand2; +extern char *color_operand3; +extern char *color_label; +extern char *color_undef; +extern char *color_undef_tls; +extern char *color_undef_weak; +extern char *color_symbol; +extern char *color_tls; +extern char *color_weak; + +extern const char color_off[]; + #endif /* system.h */ diff --git a/libcpu/ChangeLog b/libcpu/ChangeLog index 52a073ab..76340a13 100644 --- a/libcpu/ChangeLog +++ b/libcpu/ChangeLog @@ -1,3 +1,8 @@ +2012-01-21 Ulrich Drepper <drepper@gmail.com> + + * i386_disasm.c (ADD_NSTRING): Define. + (i386_disasm): Print color codes in the appropriate places. + 2011-10-16 Roland McGrath <roland@hack.frob.com> * Makefile.am (libcpu_i386_a_SOURCES): Add i386_dis.h. diff --git a/libcpu/i386_disasm.c b/libcpu/i386_disasm.c index c6bb0a58..6d58f0ea 100644 --- a/libcpu/i386_disasm.c +++ b/libcpu/i386_disasm.c @@ -1,5 +1,5 @@ /* Disassembler for x86. - Copyright (C) 2007, 2008, 2009 Red Hat, Inc. + Copyright (C) 2007, 2008, 2009, 2011 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2007. @@ -293,11 +293,18 @@ struct output_data #define ADD_STRING(str) \ do { \ + const char *_str0 = (str); \ + size_t _len0 = strlen (_str0); \ + ADD_NSTRING (_str0, _len0); \ + } while (0) + +#define ADD_NSTRING(str, len) \ + do { \ const char *_str = (str); \ - size_t _len = strlen (_str); \ + size_t _len = (len); \ if (unlikely (bufcnt + _len > bufsize)) \ goto enomem; \ - memcpy (buf + bufcnt, str, _len); \ + memcpy (buf + bufcnt, _str, _len); \ bufcnt += _len; \ } while (0) @@ -615,6 +622,10 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, unsigned long string_end_idx = 0; fmt = save_fmt; + const char *deferred_start = NULL; + size_t deferred_len = 0; + // XXX Can we get this from color.c? + static const char color_off[] = "\e[0m"; while (*fmt != '\0') { if (*fmt != '%') @@ -657,6 +668,22 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, goto do_ret; } } + else if (ch == '\e' && *fmt == '[') + { + deferred_start = fmt - 1; + do + ++fmt; + while (*fmt != 'm' && *fmt != '\0'); + + if (*fmt == 'm') + { + deferred_len = ++fmt - deferred_start; + continue; + } + + fmt = deferred_start + 1; + deferred_start = NULL; + } ADD_CHAR (ch); continue; } @@ -672,6 +699,7 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, prec = prec * 10 + (*fmt - '0'); size_t start_idx = bufcnt; + size_t non_printing = 0; switch (*fmt++) { char mnebuf[16]; @@ -796,6 +824,12 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, else str = mnestr.str + mneidx[instrtab[cnt].mnemonic]; + if (deferred_start != NULL) + { + ADD_NSTRING (deferred_start, deferred_len); + non_printing += deferred_len; + } + ADD_STRING (str); switch (instrtab[cnt].suffix) @@ -879,6 +913,12 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, abort (); } + if (deferred_start != NULL) + { + ADD_STRING (color_off); + non_printing += strlen (color_off); + } + string_end_idx = bufcnt; break; @@ -886,6 +926,12 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, if (prec == 1 && instrtab[cnt].fct1 != 0) { /* First parameter. */ + if (deferred_start != NULL) + { + ADD_NSTRING (deferred_start, deferred_len); + non_printing += deferred_len; + } + if (instrtab[cnt].str1 != 0) ADD_STRING (op1_str + op1_str_idx[instrtab[cnt].str1 - 1]); @@ -902,11 +948,23 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, if (r > 0) goto enomem; + if (deferred_start != NULL) + { + ADD_STRING (color_off); + non_printing += strlen (color_off); + } + string_end_idx = bufcnt; } else if (prec == 2 && instrtab[cnt].fct2 != 0) { /* Second parameter. */ + if (deferred_start != NULL) + { + ADD_NSTRING (deferred_start, deferred_len); + non_printing += deferred_len; + } + if (instrtab[cnt].str2 != 0) ADD_STRING (op2_str + op2_str_idx[instrtab[cnt].str2 - 1]); @@ -923,11 +981,23 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, if (r > 0) goto enomem; + if (deferred_start != NULL) + { + ADD_STRING (color_off); + non_printing += strlen (color_off); + } + string_end_idx = bufcnt; } else if (prec == 3 && instrtab[cnt].fct3 != 0) { /* Third parameter. */ + if (deferred_start != NULL) + { + ADD_NSTRING (deferred_start, deferred_len); + non_printing += deferred_len; + } + if (instrtab[cnt].str3 != 0) ADD_STRING (op3_str + op3_str_idx[instrtab[cnt].str3 - 1]); @@ -948,6 +1018,12 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, if (r > 0) goto enomem; + if (deferred_start != NULL) + { + ADD_STRING (color_off); + non_printing += strlen (color_off); + } + string_end_idx = bufcnt; } else @@ -960,12 +1036,18 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, case 'a': /* Pad to requested column. */ - while (bufcnt < (size_t) width) + while (bufcnt - non_printing < (size_t) width) ADD_CHAR (' '); width = 0; break; case 'l': + if (deferred_start != NULL) + { + ADD_NSTRING (deferred_start, deferred_len); + non_printing += deferred_len; + } + if (output_data.labelbuf != NULL && output_data.labelbuf[0] != '\0') { @@ -1005,11 +1087,21 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, output_data.symaddr_use = addr_none; } + if (deferred_start != NULL) + { + ADD_STRING (color_off); + non_printing += strlen (color_off); + } break; + + default: + abort (); } + deferred_start = NULL; + /* Pad according to the specified width. */ - while (bufcnt + prefix_size < start_idx + width) + while (bufcnt + prefix_size - non_printing < start_idx + width) ADD_CHAR (' '); prefix_size = 0; } diff --git a/src/ChangeLog b/src/ChangeLog index b4dcca9b..e9d52208 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,17 @@ +2012-01-21 Ulrich Drepper <drepper@gmail.com> + + * nm.c (argp_children): Define. + (argp): Hook up argp_children. + (handle_ar): Optimize puts call. + (show_symbols_bsd): Use positional parameters to also print color + codes. Don't print STT_FILE symbols. + * objdump.c (options): Improve help text. + (argp_children): Define. + (argp): Hook up argp_children. + (disasm_info): Add elements for color codes. + (disasm_output): Print color codes as well. + (show_disasm): Set up disasm_info data for callback. + 2012-01-20 Roland McGrath <roland@hack.frob.com> * arlib-argp.c (arlib_deterministic_output): Initialize from @@ -118,10 +118,17 @@ static const char args_doc[] = N_("[FILE...]"); /* Prototype for option handler. */ static error_t parse_opt (int key, char *arg, struct argp_state *state); +/* Parser children. */ +static struct argp_child argp_children[] = + { + { &color_argp, 0, N_("Output formatting"), 2 }, + { NULL, 0, NULL, 0} + }; + /* Data structure to communicate with argp functions. */ static struct argp argp = { - options, parse_opt, args_doc, doc, NULL, NULL, NULL + options, parse_opt, args_doc, doc, argp_children, NULL, NULL }; @@ -267,7 +274,7 @@ print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) Copyright (C) %s Red Hat, Inc.\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ -"), "2009"); +"), "2011"); fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); } @@ -458,7 +465,7 @@ handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, Elf_Arhdr *arhdr = NULL; size_t arhdr_off = 0; /* Note: 0 is no valid offset. */ - puts (gettext("\nArchive index:")); + fputs_unlocked (gettext("\nArchive index:\n"), stdout); while (arsym->as_off != 0) { @@ -930,15 +937,15 @@ show_symbols_bsd (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx, static const char *const fmtstrs[] = { - [radix_hex] = "%0*" PRIx64 " %c%s %s\n", - [radix_decimal] = "%*" PRId64 " %c%s %s\n", - [radix_octal] = "%0*" PRIo64 " %c%s %s\n" + [radix_hex] = "%8$s%2$0*1$" PRIx64 "%10$s %9$s%3$c%4$s %5$s", + [radix_decimal] = "%8$s%*" PRId64 "%10$s %9$s%3$c%4$s %5$s", + [radix_octal] = "%8$s%2$0*1$" PRIo64 "%10$s %9$s%3$c%4$s %5$s" }; static const char *const sfmtstrs[] = { - [radix_hex] = "%2$0*1$" PRIx64 " %7$0*6$" PRIx64 " %3$c%4$s %5$s\n", - [radix_decimal] = "%2$*1$" PRId64 " %7$*6$" PRId64 " %3$c%4$s %5$s\n", - [radix_octal] = "%2$0*1$" PRIo64 " %7$0*6$" PRIo64 " %3$c%4$s %5$s\n" + [radix_hex] = "%8$s%2$0*1$" PRIx64 "%10$s %7$0*6$" PRIx64 " %9$s%3$c%4$s %5$s", + [radix_decimal] = "%8$s%2$*1$" PRId64 "%10$s %7$*6$" PRId64 " %9$s%3$c%4$s %5$s", + [radix_octal] = "%8$s%2$0*1$" PRIo64 "%10$s %7$0*6$" PRIo64 " %9$s%3$c%4$s %5$s" }; #ifdef USE_DEMANGLE @@ -959,6 +966,10 @@ show_symbols_bsd (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx, if (symstr[0] == '\0') continue; + /* We do not print the entries for files. */ + if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE) + continue; + #ifdef USE_DEMANGLE /* Demangle if necessary. */ if (demangle) @@ -979,28 +990,53 @@ show_symbols_bsd (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx, putchar_unlocked (':'); } + bool is_tls = GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS; + bool is_weak = GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK; + const char *marker = (mark_special + ? (is_tls ? "@" : (is_weak ? "*" : " ")) : ""); + if (syms[cnt].sym.st_shndx == SHN_UNDEF) - printf ("%*s U%s %s\n", - digits, "", - mark_special - ? (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS - ? "@" - : (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK - ? "*" : " ")) - : "", - symstr); + { + const char *color = ""; + if (color_mode) + { + if (is_tls) + color = color_undef_tls; + else if (is_weak) + color = color_undef_weak; + else + color = color_undef; + } + + printf ("%*s %sU%s %s", digits, "", color, marker, symstr); + } else - printf (print_size ? sfmtstrs[radix] : fmtstrs[radix], - digits, syms[cnt].sym.st_value, - class_type_char (elf, ehdr, &syms[cnt].sym), - mark_special - ? (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS - ? "@" - : (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK - ? "*" : " ")) - : "", - symstr, - digits, (uint64_t) syms[cnt].sym.st_size); + { + const char *color = ""; + if (color_mode) + { + if (is_tls) + color = color_tls; + else if (is_weak) + color = color_weak; + else + color = color_symbol; + } + + printf (print_size && syms[cnt].sym.st_size != 0 + ? sfmtstrs[radix] : fmtstrs[radix], + digits, syms[cnt].sym.st_value, + class_type_char (elf, ehdr, &syms[cnt].sym), marker, + symstr, + digits, (uint64_t) syms[cnt].sym.st_size, + color_mode ? color_address : "", + color, + color_mode ? color_off : ""); + } + + if (color_mode) + fputs_unlocked (color_off, stdout); + putchar_unlocked ('\n'); } #ifdef USE_DEMANGLE diff --git a/src/objdump.c b/src/objdump.c index 1234c794..e683a29f 100644 --- a/src/objdump.c +++ b/src/objdump.c @@ -1,5 +1,5 @@ /* Print information from ELF file in human-readable form. - Copyright (C) 2005, 2006, 2007, 2009 Red Hat, Inc. + Copyright (C) 2005, 2006, 2007, 2009, 2011 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2005. @@ -65,7 +65,7 @@ static const struct argp_option options[] = { "disassemble", 'd', NULL, 0, N_("Display assembler code of executable sections"), 0 }, - { NULL, 0, NULL, 0, N_("Output option selection:"), 0 }, + { NULL, 0, NULL, 0, N_("Output content selection:"), 0 }, { "section", 'j', "NAME", 0, N_("Only display information for section NAME."), 0 }, @@ -82,10 +82,17 @@ static const char args_doc[] = N_("[FILE...]"); /* Prototype for option handler. */ static error_t parse_opt (int key, char *arg, struct argp_state *state); +/* Parser children. */ +static struct argp_child argp_children[] = + { + { &color_argp, 0, N_("Output formatting"), 2 }, + { NULL, 0, NULL, 0} + }; + /* Data structure to communicate with argp functions. */ -static struct argp argp = +static const struct argp argp = { - options, parse_opt, args_doc, doc, NULL, NULL, NULL + options, parse_opt, args_doc, doc, argp_children, NULL, NULL }; @@ -128,6 +135,7 @@ static bool print_full_content; /* If true print disassembled output.. */ static bool print_disasm; + int main (int argc, char *argv[]) { @@ -182,7 +190,7 @@ print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) Copyright (C) %s Red Hat, Inc.\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ -"), "20089"); +"), "2011"); fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); } @@ -499,7 +507,7 @@ show_relocs (Ebl *ebl, const char *fname, uint32_t shstrndx) if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) { - if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx)) + if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx)) continue; GElf_Shdr destshdr_mem; @@ -570,7 +578,7 @@ show_full_content (Ebl *ebl, const char *fname, uint32_t shstrndx) if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0) { - if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx)) + if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx)) continue; printf (gettext ("Contents of section %s:\n"), @@ -632,6 +640,8 @@ struct disasm_info GElf_Addr addr; const uint8_t *cur; const uint8_t *last_end; + const char *address_color; + const char *bytes_color; }; @@ -642,10 +652,20 @@ disasm_output (char *buf, size_t buflen, void *arg) { struct disasm_info *info = (struct disasm_info *) arg; - printf ("%8" PRIx64 ": ", (uint64_t) info->addr); + if (info->address_color != NULL) + printf ("%s%8" PRIx64 "%s: ", + info->address_color, (uint64_t) info->addr, color_off); + else + printf ("%8" PRIx64 ": ", (uint64_t) info->addr); + + if (info->bytes_color != NULL) + fputs_unlocked (info->bytes_color, stdout); size_t cnt; for (cnt = 0; cnt < (size_t) MIN (info->cur - info->last_end, 8); ++cnt) printf (" %02" PRIx8, info->last_end[cnt]); + if (info->bytes_color != NULL) + fputs_unlocked (color_off, stdout); + printf ("%*s %.*s\n", (int) (8 - cnt) * 3 + 1, "", (int) buflen, buf); @@ -655,9 +675,18 @@ disasm_output (char *buf, size_t buflen, void *arg) Print the rest on a separate, following line. */ if (info->cur - info->last_end > 8) { - printf ("%8" PRIx64 ": ", (uint64_t) info->addr); + if (info->address_color != NULL) + printf ("%s%8" PRIx64 "%s: ", + info->address_color, (uint64_t) info->addr, color_off); + else + printf ("%8" PRIx64 ": ", (uint64_t) info->addr); + + if (info->bytes_color != NULL) + fputs_unlocked (info->bytes_color, stdout); for (; cnt < (size_t) (info->cur - info->last_end); ++cnt) printf (" %02" PRIx8, info->last_end[cnt]); + if (info->bytes_color != NULL) + fputs_unlocked (color_off, stdout); putchar_unlocked ('\n'); info->addr += info->cur - info->last_end - 8; } @@ -687,7 +716,7 @@ show_disasm (Ebl *ebl, const char *fname, uint32_t shstrndx) if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0 && (shdr->sh_flags & SHF_EXECINSTR) != 0) { - if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx)) + if (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx)) continue; Elf_Data *data = elf_getdata (scn, NULL); @@ -700,10 +729,32 @@ show_disasm (Ebl *ebl, const char *fname, uint32_t shstrndx) struct disasm_info info; info.addr = shdr->sh_addr; info.last_end = info.cur = data->d_buf; + char *fmt; + if (color_mode) + { + info.address_color = color_address; + info.bytes_color = color_bytes; + + if (asprintf (&fmt, "%s%%7m %s%%.1o,%s%%.2o,%s%%.3o%%34a %s%%l", + color_mnemonic ?: "", + color_operand1 ?: "", + color_operand2 ?: "", + color_operand3 ?: "", + color_label ?: "") < 0) + error (EXIT_FAILURE, errno, _("cannot allocate memory")); + } + else + { + info.address_color = info.bytes_color = NULL; + + fmt = "%7m %.1o,%.2o,%.3o%34a %l"; + } disasm_cb (ctx, &info.cur, info.cur + data->d_size, info.addr, - "%7m %.1o,%.2o,%.3o%34a %l", disasm_output, &info, - NULL /* XXX */); + fmt, disasm_output, &info, NULL /* XXX */); + + if (color_mode) + free (fmt); } } |