summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2008-08-07 08:39:41 +0000
committerRoland McGrath <roland@redhat.com>2008-08-07 08:39:41 +0000
commit1d8bb25cac06b5af57f8733e5ea7a068a79edfe0 (patch)
treef794a75ef8e1f324185d2850e6e4da59323fe9ca /src
parent9d2f3ee2554185a9df70f434eddc4405a4aff0fa (diff)
downloadandroid_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/ChangeLog27
-rw-r--r--src/addr2line.c148
-rw-r--r--src/readelf.c151
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,