diff options
author | Adrian Szyndela <adrian.s@samsung.com> | 2016-12-14 08:16:22 +0100 |
---|---|---|
committer | Karol Lewandowski <k.lewandowsk@samsung.com> | 2016-12-14 16:55:24 +0100 |
commit | 1c23e085a8377ee92f2200af9b98a0841edf3e87 (patch) | |
tree | 1282d1db2f1ad5a2a2bc2633c046b1fc30aa77e6 /src/crash-stack | |
parent | 753d359c44f4f61aa894fdc3a842c750a09f08bd (diff) | |
download | crash-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.c | 197 |
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)) |