diff options
author | Roland McGrath <roland@redhat.com> | 2008-08-07 08:39:41 +0000 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2008-08-07 08:39:41 +0000 |
commit | 1d8bb25cac06b5af57f8733e5ea7a068a79edfe0 (patch) | |
tree | f794a75ef8e1f324185d2850e6e4da59323fe9ca /src | |
parent | 9d2f3ee2554185a9df70f434eddc4405a4aff0fa (diff) | |
download | android_external_elfutils-1d8bb25cac06b5af57f8733e5ea7a068a79edfe0.tar.gz android_external_elfutils-1d8bb25cac06b5af57f8733e5ea7a068a79edfe0.tar.bz2 android_external_elfutils-1d8bb25cac06b5af57f8733e5ea7a068a79edfe0.zip |
src/
(find_symbol): Likewise.
Convert plain number, or handle strings like "(section)+offset"
or "symbol+offset".
Diffstat (limited to 'src')
-rw-r--r-- | src/ChangeLog | 27 | ||||
-rw-r--r-- | src/addr2line.c | 148 | ||||
-rw-r--r-- | src/readelf.c | 151 |
3 files changed, 272 insertions, 54 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 94444c58..4ef23a22 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,30 @@ +2008-08-07 Roland McGrath <roland@redhat.com> + + * addr2line.c (main): Pass string to handle_address. + (see_one_module): New function, subroutine of handle_address. + (find_symbol): Likewise. + (handle_address): Take string argument rather than address. + Convert plain number, or handle strings like "(section)+offset" + or "symbol+offset". + +2008-08-01 Roland McGrath <roland@redhat.com> + + * readelf.c (handle_core_item): Handle 'B' type for 1-origin bitset. + For 'b' and 'B', print <x-y,z> or ~<x,y-z> rather than 1/0 string. + + * readelf.c (convert): Take new argument SIZE. + (handle_core_register, handle_core_item): Update callers. + (handle_core_item): Take new arg REPEATED_SIZE. + (handle_core_items): Special case for a singleton item, + let handle_core_item handle repeats if it wants to. + + * readelf.c (handle_core_items): Give abridged output + for identical groups repeated more than twice. + +2008-07-04 Roland McGrath <roland@redhat.com> + + * readelf.c (handle_core_items): Handle ELF_T_ADDR. + 2008-04-10 Roland McGrath <roland@redhat.com> * strip.c (handle_elf): Don't keep sections that kept symbol tables diff --git a/src/addr2line.c b/src/addr2line.c index 4b1d13e7..0d11e188 100644 --- a/src/addr2line.c +++ b/src/addr2line.c @@ -1,5 +1,5 @@ /* Locate source files and line information for given addresses - Copyright (C) 2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2005. @@ -96,7 +96,7 @@ static const struct argp argp = /* Handle ADDR. */ -static void handle_address (GElf_Addr addr, Dwfl *dwfl); +static int handle_address (const char *addr, Dwfl *dwfl); /* True if only base names of files should be shown. */ @@ -154,12 +154,7 @@ main (int argc, char *argv[]) if (getline (&buf, &len, stdin) < 0) break; - char *endp; - uintmax_t addr = strtoumax (buf, &endp, 0); - if (endp != buf) - handle_address (addr, dwfl); - else - result = 1; + result = handle_address (buf, dwfl); } free (buf); @@ -167,14 +162,7 @@ main (int argc, char *argv[]) else { do - { - char *endp; - uintmax_t addr = strtoumax (argv[remaining], &endp, 0); - if (endp != argv[remaining]) - handle_address (addr, dwfl); - else - result = 1; - } + result = handle_address (argv[remaining], dwfl); while (++remaining < argc); } @@ -328,9 +316,131 @@ print_addrsym (Dwfl_Module *mod, GElf_Addr addr) printf ("%s+%#" PRIx64 "\n", name, addr - s.st_value); } -static void -handle_address (GElf_Addr addr, Dwfl *dwfl) +static int +see_one_module (Dwfl_Module *mod, + void **userdata __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + Dwarf_Addr start __attribute__ ((unused)), + void *arg) +{ + Dwfl_Module **result = arg; + if (*result != NULL) + return DWARF_CB_ABORT; + *result = mod; + return DWARF_CB_OK; +} + +static int +find_symbol (Dwfl_Module *mod, + void **userdata __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + Dwarf_Addr start __attribute__ ((unused)), + void *arg) +{ + const char *looking_for = ((void **) arg)[0]; + GElf_Sym *symbol = ((void **) arg)[1]; + + int n = dwfl_module_getsymtab (mod); + for (int i = 1; i < n; ++i) + { + const char *symbol_name = dwfl_module_getsym (mod, i, symbol, NULL); + if (symbol_name == NULL) + continue; + switch (GELF_ST_TYPE (symbol->st_info)) + { + case STT_SECTION: + case STT_FILE: + case STT_TLS: + break; + default: + if (!strcmp (symbol_name, looking_for)) + { + ((void **) arg)[0] = NULL; + return DWARF_CB_ABORT; + } + } + } + + return DWARF_CB_OK; +} + +static int +handle_address (const char *string, Dwfl *dwfl) { + char *endp; + uintmax_t addr = strtoumax (string, &endp, 0); + if (endp == string) + { + bool parsed = false; + int n; + char *name = NULL; + if (sscanf (string, "(%m[^)])%" PRIiMAX "%n", &name, &addr, &n) == 2 + && string[n] == '\0') + { + /* It was (section)+offset. This makes sense if there is + only one module to look in for a section. */ + Dwfl_Module *mod = NULL; + if (dwfl_getmodules (dwfl, &see_one_module, &mod, 0) != 0 + || mod == NULL) + error (EXIT_FAILURE, 0, gettext ("Section syntax requires" + " exactly one module")); + + int nscn = dwfl_module_relocations (mod); + for (int i = 0; i < nscn; ++i) + { + GElf_Word shndx; + const char *scn = dwfl_module_relocation_info (mod, i, &shndx); + if (unlikely (scn == NULL)) + break; + if (!strcmp (scn, name)) + { + /* Found the section. */ + GElf_Shdr shdr_mem; + GElf_Addr shdr_bias; + GElf_Shdr *shdr = gelf_getshdr + (elf_getscn (dwfl_module_getelf (mod, &shdr_bias), shndx), + &shdr_mem); + if (unlikely (shdr == NULL)) + break; + + if (addr >= shdr->sh_size) + error (0, 0, + gettext ("offset %#" PRIxMAX " lies outside" + " section '%s'"), + addr, scn); + + addr += shdr->sh_addr + shdr_bias; + parsed = true; + break; + } + } + } + else if (sscanf (string, "%m[^-+]%" PRIiMAX "%n", &name, &addr, &n) == 2 + && string[n] == '\0') + { + /* It was symbol+offset. */ + GElf_Sym sym; + void *arg[2] = { name, &sym }; + (void) dwfl_getmodules (dwfl, &find_symbol, arg, 0); + if (arg[0] != NULL) + error (0, 0, gettext ("cannot find symbol '%s'"), name); + else + { + if (sym.st_size != 0 && addr >= sym.st_size) + error (0, 0, + gettext ("offset %#" PRIxMAX " lies outside" + " contents of '%s'"), + addr, name); + addr += sym.st_value; + parsed = true; + } + } + + free (name); + if (!parsed) + return 1; + } + Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr); if (show_functions) @@ -372,6 +482,8 @@ handle_address (GElf_Addr addr, Dwfl *dwfl) } else puts ("??:0"); + + return 0; } diff --git a/src/readelf.c b/src/readelf.c index 96b5d436..7b599ec8 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -5389,13 +5389,13 @@ print_core_item (unsigned int colno, char sep, unsigned int wrap, static const void * convert (Elf *core, Elf_Type type, uint_fast16_t count, - void *value, const void *data) + void *value, const void *data, size_t size) { Elf_Data valuedata = { .d_type = type, .d_buf = value, - .d_size = gelf_fsize (core, type, count, EV_CURRENT), + .d_size = size ?: gelf_fsize (core, type, count, EV_CURRENT), .d_version = EV_CURRENT, }; Elf_Data indata = @@ -5420,7 +5420,7 @@ typedef uint8_t GElf_Byte; static unsigned int handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc, - unsigned int colno) + unsigned int colno, size_t *repeated_size) { uint_fast16_t count = item->count ?: 1; @@ -5436,13 +5436,33 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc, union { TYPES; } value; #undef DO_TYPE - desc = convert (core, item->type, count, &value, desc + item->offset); + void *data = &value; + size_t size = gelf_fsize (core, item->type, count, EV_CURRENT); + size_t convsize = size; + if (repeated_size != NULL) + { + if (*repeated_size > size && (item->format == 'b' || item->format == 'B')) + { + data = alloca (*repeated_size); + count *= *repeated_size / size; + convsize = count * size; + *repeated_size -= convsize; + } + else + *repeated_size -= size; + } + + desc = convert (core, item->type, count, data, desc + item->offset, convsize); + + Elf_Type type = item->type; + if (type == ELF_T_ADDR) + type = gelf_getclass (core) == ELFCLASS32 ? ELF_T_WORD : ELF_T_XWORD; switch (item->format) { case 'd': assert (count == 1); - switch (item->type) + switch (type) { #define DO_TYPE(NAME, Name, hex, dec, max) \ case ELF_T_##NAME: \ @@ -5458,7 +5478,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc, case 'x': assert (count == 1); - switch (item->type) + switch (type) { #define DO_TYPE(NAME, Name, hex, dec, max) \ case ELF_T_##NAME: \ @@ -5473,30 +5493,59 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc, break; case 'b': - assert (count == 1); - Dwarf_Word bits = 0; - Dwarf_Word bit = 0; - switch (item->type) - { -#define DO_TYPE(NAME, Name, hex, dec, max) \ - case ELF_T_##NAME: \ - bits = value.Name[0]; \ - bit = (Dwarf_Word) 1 << ((sizeof value.Name[0] * 8) - 1); \ - break - TYPES; -#undef DO_TYPE - default: - abort (); - } - char printed[sizeof (Dwarf_Word) * 8 + 1]; - int i = 0; - while (bit != 0) - { - printed[i++] = (bits & bit) ? '1' : '0'; - bit >>= 1; - } - colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name, - sizeof printed - 1, "%.*s", i, printed); + case 'B': + assert (size % sizeof (unsigned int) == 0); + unsigned int nbits = count * size * 8; + unsigned int pop = 0; + for (const unsigned int *i = data; (void *) i < data + count * size; ++i) + pop += __builtin_popcount (*i); + bool negate = pop > nbits / 2; + const unsigned int bias = item->format == 'b'; + + { + char printed[(negate ? nbits - pop : pop) * 16]; + char *p = printed; + *p = '\0'; + + if (BYTE_ORDER != LITTLE_ENDIAN && size > sizeof (unsigned int)) + { + assert (size == sizeof (unsigned int) * 2); + for (unsigned int *i = data; + (void *) i < data + count * size; i += 2) + { + unsigned int w = i[1]; + i[1] = i[0]; + i[0] = w; + } + } + + unsigned int lastbit = 0; + for (const unsigned int *i = data; + (void *) i < data + count * size; ++i) + { + unsigned int bit = ((void *) i - data) * 8; + unsigned int w = negate ? ~*i : *i; + while (w != 0) + { + int n = ffs (w); + w >>= n; + bit += n; + + if (lastbit + 1 != bit) + p += sprintf (p, "-%u,%u", lastbit - bias, bit - bias); + else if (lastbit == 0) + p += sprintf (p, "%u", bit - bias); + + lastbit = bit; + } + } + if (lastbit > 0 && lastbit + 1 != nbits) + p += sprintf (p, "-%u", nbits - bias); + + colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name, + 4 + nbits * 4, + negate ? "~<%s>" : "<%s>", printed); + } break; case 'T': @@ -5505,7 +5554,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc, Dwarf_Word sec; Dwarf_Word usec; size_t maxfmt = 7; - switch (item->type) + switch (type) { #define DO_TYPE(NAME, Name, hex, dec, max) \ case ELF_T_##NAME: \ @@ -5615,6 +5664,17 @@ handle_core_items (Elf *core, const void *desc, size_t descsz, /* Write out all the groups. */ unsigned int colno = 0; + const void *last = desc; + if (nitems == 1) + { + size_t size = descsz; + colno = handle_core_item (core, sorted_items[0], desc, colno, &size); + if (size == 0) + return colno; + desc += descsz - size; + descsz = size; + } + do { for (size_t i = 0; i < ngroups; ++i) @@ -5624,7 +5684,7 @@ handle_core_items (Elf *core, const void *desc, size_t descsz, && ((*item)->group == groups[i][0]->group || !strcmp ((*item)->group, groups[i][0]->group))); ++item) - colno = handle_core_item (core, *item, desc, colno); + colno = handle_core_item (core, *item, desc, colno, NULL); /* Force a line break at the end of the group. */ colno = ITEM_WRAP_COLUMN; @@ -5639,8 +5699,27 @@ handle_core_items (Elf *core, const void *desc, size_t descsz, const Ebl_Core_Item *item = &items[nitems - 1]; size_t eltsz = item->offset + gelf_fsize (core, item->type, item->count ?: 1, EV_CURRENT); - descsz -= eltsz; - desc += eltsz; + + int reps = -1; + do + { + ++reps; + desc += eltsz; + descsz -= eltsz; + } + while (descsz >= eltsz && !memcmp (desc, last, eltsz)); + + if (reps == 1) + { + /* For just one repeat, print it unabridged twice. */ + desc -= eltsz; + descsz += eltsz; + } + else if (reps > 1) + printf (gettext ("\n%*s... <repeats %u more times> ..."), + ITEM_INDENT, "", reps); + + last = desc; } while (descsz > 0); @@ -5702,7 +5781,7 @@ handle_core_register (Ebl *ebl, Elf *core, int maxregname, { #define BITS(bits, xtype, sfmt, ufmt, max) \ case bits: \ - desc = convert (core, ELF_T_##xtype, 1, &value, desc); \ + desc = convert (core, ELF_T_##xtype, 1, &value, desc, 0); \ if (type == DW_ATE_signed) \ colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, \ maxregname, name, \ @@ -5717,7 +5796,7 @@ handle_core_register (Ebl *ebl, Elf *core, int maxregname, case 128: assert (type == DW_ATE_unsigned); - desc = convert (core, ELF_T_XWORD, 2, &value, desc); + desc = convert (core, ELF_T_XWORD, 2, &value, desc, 0); int be = elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB; colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, maxregname, name, |