From c954427bb005de2308e92d8f70284b1301fe35c3 Mon Sep 17 00:00:00 2001 From: Rafal Pietruch Date: Thu, 15 Dec 2016 16:28:17 +0100 Subject: crash-stack: use libunwind for i686 and x86_64 Change-Id: I0022cc3ac772ba26ed67f7d64d45c3ab4e22db88 --- src/crash-stack/CMakeLists.txt | 28 +++-- src/crash-stack/crash-stack-libelf-helpers.c | 46 ------- src/crash-stack/crash-stack-libelf.c | 180 --------------------------- src/crash-stack/crash-stack-libunw.c | 9 +- src/crash-stack/crash-stack-x86.c | 24 ++-- 5 files changed, 30 insertions(+), 257 deletions(-) delete mode 100644 src/crash-stack/crash-stack-libelf.c (limited to 'src/crash-stack') diff --git a/src/crash-stack/CMakeLists.txt b/src/crash-stack/CMakeLists.txt index ccf845e..499c9dc 100644 --- a/src/crash-stack/CMakeLists.txt +++ b/src/crash-stack/CMakeLists.txt @@ -4,22 +4,24 @@ option(WITH_CORE_DUMP "builds with support for core dump files (with GPL2 licens set(CRASH_STACK_BIN "crash-stack") # Common source code files -set(CRASH_STACK_SRCS crash-stack.c crash-stack-libelf-helpers.c) +set(CRASH_STACK_SRCS crash-stack.c) + # Add architecture dependent source files -if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") - set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libunw.c) - set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-arm.c) +if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") + set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-aarch64.c) + set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libelf-helpers.c) + else() - if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") - set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-aarch64.c) - elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") - set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libelf.c) - set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-x86.c) - elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686") - set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libelf.c) + set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libunw.c) + + if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") + set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-arm.c) + + elseif ((${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") + OR (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")) set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-x86.c) + else() - set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libelf.c) set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-stub.c) endif() endif() @@ -28,7 +30,7 @@ endif() add_executable(${CRASH_STACK_BIN} ${CRASH_STACK_SRCS}) # Set architecture dependent options for the binary - it must be already added -if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") +if (NOT (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")) include(FindPkgConfig) pkg_check_modules(LIBUNWIND_PTRACE REQUIRED libunwind-ptrace) set_property(TARGET ${CRASH_STACK_BIN} APPEND_STRING PROPERTY COMPILE_FLAGS ${LIBUNWIND_PTRACE_CFLAGS_OTHER}) diff --git a/src/crash-stack/crash-stack-libelf-helpers.c b/src/crash-stack/crash-stack-libelf-helpers.c index ab95350..8239a05 100644 --- a/src/crash-stack/crash-stack-libelf-helpers.c +++ b/src/crash-stack/crash-stack-libelf-helpers.c @@ -92,49 +92,3 @@ bool _crash_stack_libelf_read_value(Dwfl *dwfl, Elf *core, pid_t pid, return false; } - -Dwarf_Addr _crash_stack_libelf_get_prologue_pc(Dwfl *dwfl, Dwarf_Addr current_pc, Mappings *mappings) -{ - Dwarf_Addr result = 0; - Dwfl_Module *module = dwfl_addrmodule(dwfl, current_pc); - if (module) { - GElf_Sym sym; - dwfl_module_addrsym(module, current_pc, &sym, NULL); - result = sym.st_value; - } - if (0 == result) { - int i; - for (i=0; i < mappings->elems; i++) { - if (mappings->tab[i].m_start <= current_pc && current_pc < mappings->tab[i].m_end) { - /* go through symbols to find the nearest */ - Elf_Scn *scn = NULL; - Elf *elf = mappings->tab[i].m_elf; - 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 = current_pc; - if (shdr->sh_type == SHT_DYNSYM) - address_offset -= mappings->tab[i].m_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) { - return sym->st_value; - } - } - } - } - } - } - } - } - return result; -} diff --git a/src/crash-stack/crash-stack-libelf.c b/src/crash-stack/crash-stack-libelf.c deleted file mode 100644 index c341c96..0000000 --- a/src/crash-stack/crash-stack-libelf.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * - * Copyright (c) 2016 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Author: Adrian Szyndela - */ -/** - * @file crash-stack-libelf.c - * @brief unwinding call stacks, functions specific for archs that use only libelf - */ -#include "crash-stack.h" -#include -#include -#include - -/** - * @brief Convenience type for registers of different sizes - */ -typedef union { - uint16_t reg16; ///< 16-bit register - uint32_t reg32; ///< 32-bit register - uint64_t reg64; ///< 64-bit register -} Register; - -static Register g_pc; ///< storage for program counter value -static Register g_sp; ///< storage for stack pointer value - -#if _ELFUTILS_PREREQ(0,158) -/** - * @brief Callback for modern elfutils; called on each found frame. - * - * @param state state of the calls tack traversal - * @param arg user data - pointer to callstack database - */ -static int __frame_callback(Dwfl_Frame *state, void *arg) -{ - Callstack *callstack = (Callstack*)arg; - Dwarf_Addr address; - dwfl_frame_pc(state, &address, NULL); - callstack->proc[callstack->elems++].addr = address; - return callstack->elems < MAX_CALLSTACK_LEN ? DWARF_CB_OK : DWARF_CB_ABORT; -} - -/** - * @brief Callback for modern elfutils; called on each found thread. - * - * @param thread thread handle - * @param thread_arg user data - pointer to callstack database - */ -static int __thread_callback(Dwfl_Thread *thread, void *thread_arg) -{ - dwfl_thread_getframes(thread, __frame_callback, thread_arg); - return DWARF_CB_ABORT; -} -#endif - -/** - * @brief common names for program counter/instruction pointer - */ -static const char *pc_names[] = { - "pc", "rip", "eip", "ip" -}; - -/** - * @brief common names for stack pointer - */ -static const char *sp_names[] = { - "sp", "rsp", "esp" -}; - -/** - * @brief Helper functions that checks if a name is present in array of names - * - * @param name name to look for - * @param names array of names - * @param elems number of elements in names - * @returns true if name is found in names, false otherwise - */ -static bool __is_in(const char *name, const char **names, int elems) -{ - int nit; - for (nit = 0; nit < elems; ++nit) { - if (strcmp(name, names[nit]) == 0) - return true; - } - return false; -} - -/** - * @brief Helper macro for looking for name in array of names - */ -#define IS_IN(name,names) __is_in((name), (names), sizeof(names)/sizeof(names[0])) - -void *_get_place_for_register_value(const char *regname, int regnum) -{ - if (IS_IN(regname, pc_names)) return &g_pc; - else if (IS_IN(regname, sp_names)) return &g_sp; - - return 0; -} - -/** - * @brief Tries to heuristically gather call stack information. - * - * @remarks This function walks through the stack of the given process, and checks - * if found addresses are addresses belonging to functions. If so, it treats - * such address as an element of the call stack. - * While it gathers some useful information, it gathers also "false positives". - * @remarks It should be used as a last resort - when no other method is available. - * - * @param dwfl dwfl handle - * @param core core file handle, NULL if live process is analyzed - * @param pid PID of the analyzed process, 0 if core dump file is analyzed - * @param mappings module mappings database - * @param callstack call stack database - */ -static void _explore_stack_in_search_of_functions(Dwfl *dwfl, Elf *core, pid_t pid, - Mappings *mappings, Callstack *callstack) -{ - Dwarf_Addr stack_pointer = sizeof(uintptr_t) == 4 ? g_sp.reg32 : g_sp.reg64; - Dwarf_Addr stack_max_lookup = stack_pointer + 8*1024*1024; - bool data_remaining = true; - do { - uintptr_t value; - data_remaining = _crash_stack_libelf_read_value(dwfl, core, pid, stack_pointer, - &value, sizeof(value), mappings); - if (data_remaining) { - Dwarf_Addr bias; - /* check presence of address in text sections */ - Dwfl_Module *module = dwfl_addrmodule(dwfl, value); - if (module != NULL) { - Dwarf_Addr elfval = value; - GElf_Sym sym; - GElf_Word shndxp = -1; - dwfl_module_addrsym(module, value, &sym, &shndxp); - Elf_Scn *scn = dwfl_module_address_section(module, &elfval, &bias); - if (scn != 0 || shndxp != -1) { - callstack->proc[callstack->elems++].addr = value; - if (callstack->elems >= MAX_CALLSTACK_LEN) - return; - } - else { - /* check also inside [pie] and [exe] */ - int i; - for (i = 0; i < mappings->elems; i++) { - if (mappings->tab[i].m_start <= elfval && elfval < mappings->tab[i].m_end) { - callstack->proc[callstack->elems++].addr = value; - break; - } - } - } - } - } - stack_pointer += sizeof(uintptr_t); - } while (data_remaining && stack_pointer < stack_max_lookup); -} - -void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) -{ - callstack->elems = 0; -#if _ELFUTILS_PREREQ(0,158) - dwfl_getthreads(dwfl, __thread_callback, callstack); -#else - callstack->proc[callstack->elems++].addr = sizeof(uintptr_t) == 4 ? g_pc.reg32 : g_pc.reg64; - _explore_stack_in_search_of_functions(dwfl, core, pid, mappings, callstack); -#endif -} - diff --git a/src/crash-stack/crash-stack-libunw.c b/src/crash-stack/crash-stack-libunw.c index 23e3df3..f013e63 100644 --- a/src/crash-stack/crash-stack-libunw.c +++ b/src/crash-stack/crash-stack-libunw.c @@ -33,6 +33,7 @@ void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, C unw_addr_space_t as = 0; void *ui = 0; do { + //init before return callstack->elems = 0; as = unw_create_addr_space(&_UPT_accessors, 0); @@ -48,11 +49,8 @@ void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, C break; char proc_name[MAXPROCNAMELEN]; - int n; - // MaxDeep as proposed in libunwind tests/test-ptrace.c file - // guard against bad unwind info in old libraries - static const int MaxDeep = 64; - for (n = 0; n < MaxDeep; ++n) { + for (; callstack->elems < sizeof(callstack->proc)/sizeof(callstack->proc[0]); + ++callstack->elems) { unw_word_t ip; if (unw_get_reg(&cursor, UNW_REG_IP, &ip) < 0) @@ -66,7 +64,6 @@ void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, C callstack->proc[callstack->elems].name = strdup(proc_name); callstack->proc[callstack->elems].offset = off; - ++callstack->elems; if (unw_step(&cursor) <= 0) break; } diff --git a/src/crash-stack/crash-stack-x86.c b/src/crash-stack/crash-stack-x86.c index b63f279..a72a198 100644 --- a/src/crash-stack/crash-stack-x86.c +++ b/src/crash-stack/crash-stack-x86.c @@ -33,20 +33,20 @@ void *_crash_stack_get_memory_for_ptrace_registers(size_t *size) return &g_registers; } -void _crash_stack_set_ptrace_registers(void *regbuf) +void *_get_place_for_register_value(const char *regname, int regnum) { - void *rsp = _get_place_for_register_value("rsp", 0); - void *rip = _get_place_for_register_value("rip", 0); - - struct user_regs_struct *regs = regbuf; + /* Function is not used for x86 anymore, make it dummy + * It is still called by generic __get_registers_core function + * The return value is checked for NULL in __get_registers_core. + */ + return NULL; +} -#if defined(__x86_64__) - memcpy(rsp, ®s->rsp, sizeof(regs->rsp)); - memcpy(rip, ®s->rip, sizeof(regs->rip)); -#else - memcpy(rsp, ®s->esp, sizeof(regs->esp)); - memcpy(rip, ®s->eip, sizeof(regs->eip)); -#endif +void _crash_stack_set_ptrace_registers(void *regbuf) +{ + /* Make it dummy as it not used for x86 anymore + * However it is still called by generic __get_registers_ptrace functions + */ } void _crash_stack_print_regs(FILE* outputfile) -- cgit v1.2.3