From dffc33ddb5133bc477ea6c0521cfe1dc894f8e81 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Mon, 6 Jul 2009 16:06:41 -0700 Subject: Handle unknown register numbers gracefully in readelf -n core reading. --- src/ChangeLog | 6 +++++ src/readelf.c | 72 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index a1078ab6..e2749424 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2009-07-06 Roland McGrath + + * readelf.c (register_info): New function. Handle unknown register #s. + (print_cfa_program): Use it. + (handle_core_register, handle_core_registers): Likewise. + 2009-06-28 Roland McGrath * readelf.c (print_address_names): New static variable. diff --git a/src/readelf.c b/src/readelf.c index 2ab2ab58..b990bfe1 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -4315,6 +4315,27 @@ print_debug_ranges_section (Dwfl_Module *dwflmod, } } +#define REGNAMESZ 16 +static const char * +register_info (Ebl *ebl, unsigned int regno, const Ebl_Register_Location *loc, + char name[REGNAMESZ], int *bits, int *type) +{ + const char *set; + const char *pfx; + int ignore; + ssize_t n = ebl_register_info (ebl, regno, name, REGNAMESZ, &pfx, &set, + bits ?: &ignore, type ?: &ignore); + if (n <= 0) + { + snprintf (name, sizeof name, "reg%u", loc->regno); + if (bits != NULL) + *bits = loc->bits; + if (type != NULL) + *type = DW_ATE_unsigned; + set = "??? unrecognized registers"; + } + return set; +} static void print_cfa_program (const unsigned char *readp, const unsigned char *const endp, @@ -4322,14 +4343,11 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp, int data_align, unsigned int ptr_size, Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg) { - char regnamebuf[16]; + char regnamebuf[REGNAMESZ]; const char *regname (unsigned int regno) { - const char *str; - int i; - return (ebl_register_info (ebl, regno, regnamebuf, sizeof (regnamebuf), - &str, &str, &i, &i) < 0 - ? "???" : regnamebuf); + register_info (ebl, regno, NULL, regnamebuf, NULL, NULL); + return regnamebuf; } puts ("\n Program:"); @@ -6867,17 +6885,10 @@ handle_core_register (Ebl *ebl, Elf *core, int maxregname, for (int reg = regloc->regno; reg < regloc->regno + regloc->count; ++reg) { - const char *pfx; - const char *set; - char name[16]; + char name[REGNAMESZ]; int bits; int type; - ssize_t n = ebl_register_info (ebl, reg, name, sizeof name, - &pfx, &set, &bits, &type); - if (n <= 0) - error (EXIT_FAILURE, 0, - gettext ("unable to handle register number %d"), - regloc->regno); + register_info (ebl, reg, regloc, name, &bits, &type); #define TYPES \ BITS (8, BYTE, "%4" PRId8, "0x%.2" PRIx8, 4); \ @@ -6965,10 +6976,10 @@ struct register_info { const Ebl_Register_Location *regloc; const char *set; - char name[16]; - Dwarf_Half regno; - uint8_t bits; - uint8_t type; + char name[REGNAMESZ]; + int regno; + int bits; + int type; }; static int @@ -7022,8 +7033,12 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc, ssize_t maxnreg = ebl_register_info (ebl, 0, NULL, 0, NULL, NULL, NULL, NULL); if (maxnreg <= 0) - error (EXIT_FAILURE, 0, - gettext ("cannot get register info: %s"), elf_errmsg (-1)); + { + for (size_t i = 0; i < nregloc; ++i) + if (maxnreg < reglocs[i].regno + reglocs[i].count) + maxnreg = reglocs[i].regno + reglocs[i].count; + assert (maxnreg > 0); + } struct register_info regs[maxnreg]; memset (regs, 0, sizeof regs); @@ -7039,20 +7054,9 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc, if (reg > maxreg) maxreg = reg; struct register_info *info = ®s[reg]; - - const char *pfx; - int bits; - int type; - ssize_t n = ebl_register_info (ebl, reg, info->name, sizeof info->name, - &pfx, &info->set, &bits, &type); - if (n <= 0) - error (EXIT_FAILURE, 0, - gettext ("cannot register info: %s"), elf_errmsg (-1)); - info->regloc = ®locs[i]; - info->regno = reg; - info->bits = bits; - info->type = type; + info->set = register_info (ebl, reg, ®locs[i], + info->name, &info->bits, &info->type); } qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers); -- cgit v1.2.3 From 46d5827cc232c689853b50181b17751aa7574128 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Mon, 6 Jul 2009 17:57:33 -0700 Subject: Fix last change. --- src/readelf.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/readelf.c b/src/readelf.c index b990bfe1..c8bb2f08 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -4332,7 +4332,15 @@ register_info (Ebl *ebl, unsigned int regno, const Ebl_Register_Location *loc, *bits = loc->bits; if (type != NULL) *type = DW_ATE_unsigned; - set = "??? unrecognized registers"; + set = "??? unrecognized"; + } + else + { + if (bits != NULL && *bits <= 0) + *bits = loc->bits; + if (type != NULL && *type == DW_ATE_void) + *type = DW_ATE_unsigned; + } return set; } -- cgit v1.2.3 From 70c442caa8296a698b395b8969b9a04d5491d47b Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Wed, 8 Jul 2009 00:53:24 -0700 Subject: Add support for STB_GNU_UNIQUE to libebl. --- NEWS | 2 ++ libebl/ChangeLog | 8 ++++++++ libebl/eblsymbolbindingname.c | 8 +++++++- libebl/eblsymboltypename.c | 6 +++++- libelf/ChangeLog | 4 ++++ libelf/elf.h | 1 + 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 2933d35a..1b73645f 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ libelf: Add elf_getshdrnum alias for elf_getshnum and elf_getshdrstrndx alias for elf_getshstrndx and deprecate original names. Sun screwed up their implementation and asked for a solution. +libebl: Add support for STB_GNU_UNIQUE. + readelf: Add -N option, speeds up DWARF printing without address->name lookups. Version 0.141: diff --git a/libebl/ChangeLog b/libebl/ChangeLog index 83319c70..12e94f42 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -1,3 +1,11 @@ +2009-07-08 Ulrich Drepper + + * eblsymbolbindingname.c (ebl_symbol_binding_name): Handle + STB_GNU_UNIQUE. + + * eblsymboltypename.c (ebl_symbol_type_name): Only handle STT_GNU_IFUNC + if the binary is marked as being for Linux. + 2009-04-01 Roland McGrath * eblsymboltypename.c (ebl_symbol_type_name): Add STT_GNU_IFUNC. diff --git a/libebl/eblsymbolbindingname.c b/libebl/eblsymbolbindingname.c index c4412c9e..334a9c3e 100644 --- a/libebl/eblsymbolbindingname.c +++ b/libebl/eblsymbolbindingname.c @@ -1,5 +1,5 @@ /* Return symbol binding name. - Copyright (C) 2001, 2002 Red Hat, Inc. + Copyright (C) 2001, 2002, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2001. @@ -78,8 +78,14 @@ ebl_symbol_binding_name (ebl, binding, buf, len) res = stb_names[binding]; else { + char *ident; + if (binding >= STB_LOPROC && binding <= STB_HIPROC) snprintf (buf, len, "LOPROC+%d", binding - STB_LOPROC); + else if (binding == STB_GNU_UNIQUE + && (ident = elf_getident (ebl->elf, NULL)) != NULL + && ident[EI_OSABI] == ELFOSABI_LINUX) + return "GNU_UNIQUE"; else if (binding >= STB_LOOS && binding <= STB_HIOS) snprintf (buf, len, "LOOS+%d", binding - STB_LOOS); else diff --git a/libebl/eblsymboltypename.c b/libebl/eblsymboltypename.c index 6aae13ee..f2ac6222 100644 --- a/libebl/eblsymboltypename.c +++ b/libebl/eblsymboltypename.c @@ -84,9 +84,13 @@ ebl_symbol_type_name (ebl, symbol, buf, len) res = stt_names[symbol]; else { + char *ident; + if (symbol >= STT_LOPROC && symbol <= STT_HIPROC) snprintf (buf, len, "LOPROC+%d", symbol - STT_LOPROC); - else if (symbol == STT_GNU_IFUNC) + else if (symbol == STT_GNU_IFUNC + && (ident = elf_getident (ebl->elf, NULL)) != NULL + && ident[EI_OSABI] == ELFOSABI_LINUX) return "GNU_IFUNC"; else if (symbol >= STT_LOOS && symbol <= STT_HIOS) snprintf (buf, len, "LOOS+%d", symbol - STT_LOOS); diff --git a/libelf/ChangeLog b/libelf/ChangeLog index a0163db1..5d8ac8ae 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,7 @@ +2009-07-08 Ulrich Drepper + + * elf.h: Update from glibc. + 2009-06-13 Ulrich Drepper * Makefile.am (libelf_a_SOURCES): Replace elf_getshnum.c and diff --git a/libelf/elf.h b/libelf/elf.h index 8fdf74b0..7efdedef 100644 --- a/libelf/elf.h +++ b/libelf/elf.h @@ -444,6 +444,7 @@ typedef struct #define STB_WEAK 2 /* Weak symbol */ #define STB_NUM 3 /* Number of defined types. */ #define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Unique symbol. */ #define STB_HIOS 12 /* End of OS-specific */ #define STB_LOPROC 13 /* Start of processor-specific */ #define STB_HIPROC 15 /* End of processor-specific */ -- cgit v1.2.3 From f735db16b52665f2324eff101f0e5cad861bfea2 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Wed, 8 Jul 2009 19:18:53 +0200 Subject: Handle DW_Form constants for DW_AT_data_member_location in readelf. --- src/ChangeLog | 5 +++++ src/readelf.c | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ChangeLog b/src/ChangeLog index e2749424..51b3dd80 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2009-07-08 Mark Wielaard + + * readelf.c (attr_callback): Handle DW_Form constants for + DW_AT_data_member_location. + 2009-07-06 Roland McGrath * readelf.c (register_info): New function. Handle unknown register #s. diff --git a/src/readelf.c b/src/readelf.c index c8bb2f08..bc67c31b 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -5135,9 +5135,20 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) const char *valuestr = NULL; switch (attr) { + /* This case can take either a constant or a loclistptr. */ + case DW_AT_data_member_location: + if (form != DW_FORM_data4 && form != DW_FORM_data8) + { + printf (" %*s%-20s %" PRIxMAX "\n", + (int) (level * 2), "", dwarf_attr_string (attr), + (uintmax_t) num); + return DWARF_CB_OK; + } + /* else fallthrough */ + + /* These cases always take a loclistptr and no constant. */ case DW_AT_location: case DW_AT_data_location: - case DW_AT_data_member_location: case DW_AT_vtable_elem_location: case DW_AT_string_length: case DW_AT_use_location: -- cgit v1.2.3 From cfdd86ed929c137eaca5dd49cd266bb739c6cdbd Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 8 Jul 2009 13:15:07 -0700 Subject: Handle DW_AT_data_member_location of class constant magically in dwarf_getlocation{,_addr}. --- libdw/ChangeLog | 6 +++++ libdw/dwarf_getlocation.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 6ae3154a..600f6dc3 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,9 @@ +2009-07-08 Roland McGrath + + * dwarf_getlocation.c (check_constant_offset): New function. + (dwarf_getlocation, dwarf_getlocation_addr): Call it to + handle DW_AT_data_member_location of data[48] as constant offset. + 2009-06-18 Roland McGrath * libdwP.h (__libdw_read_address_inc): Constify. diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c index 504db376..62106ce3 100644 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@ -55,6 +55,7 @@ #include #include #include +#include #include @@ -111,6 +112,57 @@ loc_compare (const void *p1, const void *p2) return 0; } +/* DW_AT_data_member_location can be a constant as well as a loclistptr. + Only data[48] indicate a loclistptr. */ +static int +check_constant_offset (Dwarf_Attribute *attr, + Dwarf_Op **llbuf, size_t *listlen) +{ + if (attr->code != DW_AT_data_member_location + || attr->form == DW_FORM_data4 + || attr->form == DW_FORM_data8) + return 1; + + /* Check whether we already cached this location. */ + struct loc_s fake = { .addr = attr->valp }; + struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare); + + if (found == NULL) + { + Dwarf_Word offset; + if (INTUSE(dwarf_formudata) (attr, &offset) != 0) + return -1; + + Dwarf_Op *result = libdw_alloc (attr->cu->dbg, + Dwarf_Op, sizeof (Dwarf_Op), 1); + + result->atom = DW_OP_plus_uconst; + result->number = offset; + result->number2 = 0; + result->offset = 0; + + /* Insert a record in the search tree so we can find it again later. */ + struct loc_s *newp = libdw_alloc (attr->cu->dbg, + struct loc_s, sizeof (struct loc_s), + 1); + newp->addr = attr->valp; + newp->loc = result; + newp->nloc = 1; + + found = tsearch (newp, &attr->cu->locs, loc_compare); + } + + assert ((*found)->nloc == 1); + + if (llbuf != NULL) + { + *llbuf = (*found)->loc; + *listlen = 1; + } + + return 0; +} + static int getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, Dwarf_Op **llbuf, size_t *listlen, int sec_index) @@ -333,6 +385,10 @@ dwarf_getlocation (attr, llbuf, listlen) Dwarf_Op **llbuf; size_t *listlen; { + int result = check_constant_offset (attr, llbuf, listlen); + if (result != 1) + return result; + if (! attr_ok (attr)) return -1; @@ -378,6 +434,10 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs) return -1; } + int result = check_constant_offset (attr, &llbufs[0], &listlens[0]); + if (result != 1) + return result ?: 1; + unsigned char *endp; unsigned char *readp = __libdw_formptr (attr, IDX_debug_loc, DWARF_E_NO_LOCLIST, &endp, NULL); -- cgit v1.2.3