summaryrefslogtreecommitdiff
path: root/src/crash-stack
diff options
context:
space:
mode:
authorAdrian Szyndela <adrian.s@samsung.com>2016-12-14 08:16:22 +0100
committerKarol Lewandowski <k.lewandowsk@samsung.com>2016-12-14 16:55:24 +0100
commit1c23e085a8377ee92f2200af9b98a0841edf3e87 (patch)
tree1282d1db2f1ad5a2a2bc2633c046b1fc30aa77e6 /src/crash-stack
parent753d359c44f4f61aa894fdc3a842c750a09f08bd (diff)
downloadcrash-worker-1c23e085a8377ee92f2200af9b98a0841edf3e87.tar.gz
crash-worker-1c23e085a8377ee92f2200af9b98a0841edf3e87.tar.bz2
crash-worker-1c23e085a8377ee92f2200af9b98a0841edf3e87.zip
crash-stack: put more effort into getting names
It seems libdwfl-0.153 sometimes can't get symbol names automatically. This commit adds fallback procedure, that takes module name and mapping provided by libdwfl, and - using libelf - looks for the symbol name, instead of relying only on libdwfl. Change-Id: I7e65f810b46dc43bea217b715852a5ae5c3d70c9
Diffstat (limited to 'src/crash-stack')
-rw-r--r--src/crash-stack/crash-stack.c197
1 files changed, 93 insertions, 104 deletions
diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c
index 07cdb46..d839a4f 100644
--- a/src/crash-stack/crash-stack.c
+++ b/src/crash-stack/crash-stack.c
@@ -209,102 +209,58 @@ static void __get_mapping_item(Elf *elf, size_t addr_size, const void *item,
__get_value(elf, item + 2 * addr_size, addr_size*8, offset_in_pages);
}
-/**
- * @brief Tries to get symbol name from ELF files
- *
- * @remarks This function is used in case that symbol name is not available by libelf,
- * e.g. when old libelf version does not take into account some modules.
- *
- * @param core ELF handler for the core dump file
- * @param notes notes descriptor from core file
- * @param address address to get symbol name for
- * @param[out] module_name name of the module of the found symbol. Not touched when
- * symbol is not found
- * @return name of the symbol or NULL if not found
- */
-static char *__try_symbol_from_elfs(Elf *core, Elf_Data *notes, uintptr_t address,
- const char **module_name)
+void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start)
{
- GElf_Nhdr nhdr;
- char *symbol = NULL;
- size_t pos = 0;
- size_t new_pos = 0;
- size_t name_pos;
- size_t desc_pos;
-
- while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
- if (nhdr.n_type == NT_FILE) {
- uint64_t values_cnt = 0, page_size = 0;
- const char *values;
- const char *filenames;
- size_t addr_size = 0;
+ Elf *elf;
+ int fd;
+ const char *elf_name = proc_info->module_name;
+ Dwarf_Addr address = proc_info->addr;
- __parse_note_file(core, notes->d_buf + desc_pos, &values_cnt,
- &page_size, &addr_size, &values, &filenames);
-
- int ii;
- for (ii = 0; ii < values_cnt; ii++) {
- uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
- const char *item = values + 3 * addr_size * ii;
-
- __get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end,
- &offset_in_pages);
-
- if (mapping_start <= address && address < mapping_end) {
- Elf *elf;
- int fd;
- fd = open(filenames, O_RDONLY);
- if (-1 == fd)
- return NULL;
+ fd = open(elf_name, O_RDONLY);
+ if (-1 == fd)
+ return;
- elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
+ elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
- if (NULL == elf) {
- close(fd);
- return NULL;
- }
+ if (NULL == elf) {
+ close(fd);
+ return;
+ }
- Elf_Scn *scn = NULL;
- *module_name = filenames;
-
- while ((scn = elf_nextscn(elf, scn)) != NULL) {
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
- if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) {
- Elf_Data *sdata = elf_getdata(scn, NULL);
- unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ?
- sizeof(Elf32_Sym) :
- sizeof(Elf64_Sym));
- unsigned int cnt;
- uintptr_t address_offset = address;
- if (shdr->sh_type == SHT_DYNSYM)
- address_offset -= mapping_start;
- for (cnt = 0; cnt < nsyms; ++cnt) {
- GElf_Sym sym_mem;
- Elf32_Word xndx;
- GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx);
- if (sym != NULL && sym->st_shndx != SHN_UNDEF) {
- if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) {
- symbol = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name));
- break;
- }
- }
- }
- }
+ Elf_Scn *scn = NULL;
+ int found = 0;
+
+ while ((scn = elf_nextscn(elf, scn)) != NULL && !found) {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
+ if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) {
+ Elf_Data *sdata = elf_getdata(scn, NULL);
+ unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ?
+ sizeof(Elf32_Sym) :
+ sizeof(Elf64_Sym));
+ unsigned int cnt;
+ uintptr_t address_offset = address;
+ if (shdr->sh_type == SHT_DYNSYM)
+ address_offset -= mapping_start;
+ for (cnt = 0; cnt < nsyms; ++cnt) {
+ GElf_Sym sym_mem;
+ Elf32_Word xndx;
+ GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx);
+ if (sym != NULL && sym->st_shndx != SHN_UNDEF) {
+ if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) {
+ free(proc_info->name);
+ proc_info->name = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name));
+ proc_info->offset = address_offset - sym->st_value;
+ found = 1;
+ break;
}
-
- elf_end(elf);
- close(fd);
- return symbol;
}
-
- filenames += strlen(filenames)+1;
}
}
- pos = new_pos;
}
- return NULL;
+ elf_end(elf);
+ close(fd);
}
/**
@@ -323,7 +279,6 @@ static Dwfl *__open_dwfl_with_pid(pid_t pid)
return NULL;
}
-
ptrace(PTRACE_INTERRUPT, pid, 0, 0);
stopped_pid = waitpid(pid, &status, 0);
@@ -648,20 +603,23 @@ static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl)
Dwfl_Module *module = dwfl_addrmodule(dwfl, address);
if (module) {
- const char *module_name = proc_info->module_name;
- if (!module_name) {
- const char *fname = 0;
- const char *module_name = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
+ Dwarf_Addr mapping_start = 0;
+ const char *fname = 0;
+ const char *module_name = dwfl_module_info(module, NULL, &mapping_start, NULL, NULL, NULL, &fname, NULL);
+ if (!proc_info->module_name) {
if (fname)
proc_info->module_name = strdup(fname);
else if (module_name)
proc_info->module_name = strdup(module_name);
}
- const char *symbol = proc_info->name;
- if (!symbol) {
- symbol = dwfl_module_addrname(module, proc_info->addr);
- if (symbol)
- proc_info->name = strdup(symbol);
+
+ const char *symbol = dwfl_module_addrname(module, address);
+ if (symbol) {
+ free(proc_info->name);
+ proc_info->name = strdup(symbol);
+ }
+ else if (proc_info->module_name != NULL) {
+ __find_symbol_in_elf(proc_info, mapping_start);
}
}
}
@@ -669,19 +627,51 @@ static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl)
/**
* @brief Resolves procedure and module names using elfutils
*
+ * @remarks This function is used in case that symbol name is not available by libelf,
+ * e.g. when old libelf version does not take into account some modules.
+ *
* @param proc_info gathered call stack element
* @param core ELF handler for the core dump file, NULL if live process analyzed
* @param notes notes handler, NULL if live process analyzed
*/
static void __resolve_symbols_from_elf(ProcInfo *proc_info, Elf *core, Elf_Data *notes)
{
- const char *fname = 0;
- char *symbol_from_elf = __try_symbol_from_elfs(core, notes, proc_info->addr, &fname);
- if (!proc_info->module_name && fname)
- proc_info->module_name = strdup(fname);
+ GElf_Nhdr nhdr;
+ size_t pos = 0;
+ size_t new_pos = 0;
+ size_t name_pos;
+ size_t desc_pos;
+
+ while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
+ if (nhdr.n_type == NT_FILE) {
+ uint64_t values_cnt = 0, page_size = 0;
+ const char *values;
+ const char *filenames;
+ size_t addr_size = 0;
+
+ __parse_note_file(core, notes->d_buf + desc_pos, &values_cnt,
+ &page_size, &addr_size, &values, &filenames);
+
+ int ii;
+ for (ii = 0; ii < values_cnt; ii++) {
+ uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
+ const char *item = values + 3 * addr_size * ii;
- if (!proc_info->name && symbol_from_elf)
- proc_info->name = symbol_from_elf;
+ __get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end,
+ &offset_in_pages);
+
+ if (mapping_start <= proc_info->addr && proc_info->addr < mapping_end) {
+ free(proc_info->module_name);
+ proc_info->module_name = strdup(filenames);
+ __find_symbol_in_elf(proc_info, mapping_start);
+ return;
+ }
+
+ filenames += strlen(filenames)+1;
+ }
+ }
+ pos = new_pos;
+ }
}
/**
@@ -721,10 +711,9 @@ static void __demangle_symbols(ProcInfo *proc_info)
*/
static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl, Elf *core, Elf_Data *notes)
{
- if (!proc_info->module_name || !proc_info->name)
- __resolve_symbols_from_dwfl(proc_info, dwfl);
+ __resolve_symbols_from_dwfl(proc_info, dwfl);
- if (!proc_info->module_name || !proc_info->name)
+ if (core != NULL && (!proc_info->module_name || !proc_info->name))
__resolve_symbols_from_elf(proc_info, core, notes);
if (is_symbol_demanglable(proc_info->name))