Integrate code from tbstack 44/186144/16
authorŁukasz Stelmach <l.stelmach@samsung.com>
Tue, 7 Aug 2018 13:54:30 +0000 (15:54 +0200)
committerKarol Lewandowski <k.lewandowsk@samsung.com>
Wed, 22 Aug 2018 05:51:37 +0000 (07:51 +0200)
Change-Id: I4f9b523b277fb464e60deaccba316ed94c750df9
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
16 files changed:
packaging/crash-worker.spec
src/crash-manager/CMakeLists.txt
src/crash-manager/crash-manager.c
src/crash-stack/CMakeLists.txt
src/crash-stack/crash-stack-aarch64.c
src/crash-stack/crash-stack-arm.c
src/crash-stack/crash-stack-libunw.c
src/crash-stack/crash-stack-stub.c
src/crash-stack/crash-stack-x86.c
src/crash-stack/crash-stack.c
src/crash-stack/crash-stack.h
src/crash-stack/mem_map.c
src/crash-stack/mem_map.h
src/crash-stack/proc.c
src/crash-stack/proc.h
src/crash-stack/unwind.c

index cf126d7..5d41038 100644 (file)
@@ -24,7 +24,7 @@ BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(rpm)
 BuildRequires:  cmake
 
-BuildRequires:  pkgconfig(libunwind-ptrace)
+BuildRequires:  pkgconfig(libunwind-generic)
 %if "%{TIZEN_FEATURE_PTRACE_CALLSTACK}" == "on"
 BuildRequires:  libelf-devel libelf
 BuildRequires:  libebl-devel libebl
index 5fe5b19..d70dde2 100644 (file)
@@ -45,7 +45,7 @@ ENDIF()
 
 CONFIGURE_FILE(crash-manager.h.in crash-manager.h @ONLY)
 ADD_EXECUTABLE(${PROJECT_NAME} ${CRASH_MANAGER_SRCS})
-TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${crash-manager_pkgs_LDFLAGS} -pie)
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${crash-manager_pkgs_LDFLAGS} -pie -lrt)
 
 INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin
                PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
index 3e2af24..bdc2469 100644 (file)
@@ -25,6 +25,8 @@
 #include <unistd.h>
 #include <libgen.h>
 #include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/procfs.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/prctl.h>
@@ -106,6 +108,7 @@ static struct crash_info {
        char sysassert_cs_path[PATH_MAX];
        bool have_sysassert_report;
 #endif
+       int prstatus_fd;
 } crash_info;
 
 static void get_config(void)
@@ -259,6 +262,49 @@ error:
        return ret;
 }
 
+static int set_prstatus()
+{
+       int ret;
+       char prstatus_name[NAME_MAX+1];
+
+       ret = snprintf(prstatus_name, NAME_MAX, "/%s.prstatus", crash_info.pid_info);
+       if (ret < 0) {
+               goto close_fd;
+       }
+
+       crash_info.prstatus_fd = shm_open(prstatus_name, O_RDWR | O_CREAT, 0600);
+       if (crash_info.prstatus_fd < 0) {
+               goto close_fd;
+       }
+
+       ret = shm_unlink(prstatus_name);
+       if (ret < 0) {
+               goto close_fd;
+       }
+
+       ret = fcntl(crash_info.prstatus_fd, F_GETFD);
+       if (ret < 0) {
+               goto close_fd;
+       }
+
+       ret = fcntl(crash_info.prstatus_fd, F_SETFD, ret & ~FD_CLOEXEC);
+       if (ret < 0) {
+               goto close_fd;
+       }
+
+       ret = ftruncate(crash_info.prstatus_fd, sizeof(struct elf_prstatus));
+       if (ret < 0) {
+               goto close_fd;
+       }
+
+       return 0;
+
+close_fd:
+       if (crash_info.prstatus_fd >= 0)
+               close(crash_info.prstatus_fd);
+       return -1;
+}
+
 static int set_crash_info(int argc, char *argv[])
 {
        int ret;
@@ -359,6 +405,8 @@ static int set_crash_info(int argc, char *argv[])
                goto rm_temp;
        }
 #endif
+       if (set_prstatus() < 0)
+               goto rm_temp;
 
        return 0;
 
@@ -531,9 +579,14 @@ static void execute_crash_modules(int argc, char *argv[])
 
 #ifdef TIZEN_ENABLE_MINICOREDUMP
        char *coredump_name = NULL;
+       char *prstatus_fd_str = NULL;
+
        if (asprintf(&coredump_name, "%s.coredump", crash_info.name) == -1)
                coredump_name = strdup("core");
 
+       if (asprintf(&prstatus_fd_str, "%d", crash_info.prstatus_fd) == -1)
+               prstatus_fd_str = strdup("-1");
+
        /* Execute minicoredumper */
        char *args[] = {
                        MINICOREDUMPER_PATH,       // minicoredumper filename path
@@ -549,40 +602,50 @@ static void execute_crash_modules(int argc, char *argv[])
                        crash_info.pfx,            // temp dir
                        "-o",
                        coredump_name,             // coredump filename
+                       "-P",
+                       prstatus_fd_str,
                        NULL
                        };
 
-       _D("    %s", args[0]);
+       _D("    %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
+               args[0], args[1], args[2], args[3],
+               args[4], args[5], args[6], args[7],
+               args[8], args[9], args[10], args[11],
+               args[12], args[13], args[14]);
 
        run_command_timeout(args[0], args, NULL, MINICOREDUMPER_TIMEOUT);
 
        free(coredump_name);
+       free(prstatus_fd_str);
 #endif
 
 #ifdef TIZEN_FEATURE_PTRACE_CALLSTACK
 
 # ifdef SYS_ASSERT
-       /* Use ptrace version as fallback if sys-assert failed to
-        * generate report */
+       /* Use process_vm_readv() version as fallback if sys-assert
+        * failed to generate report */
        if (crash_info.have_sysassert_report)
                return;
 # endif
        /* Execute crash-stack */
        if (argc > 8)
                ret = snprintf(command, sizeof(command),
-                               "%s --pid %s --tid %s --sig %s > %s",
+                               "%s --pid %s --tid %s --sig %s --prstatus_fd %d > %s",
                                CRASH_STACK_PATH,
                                crash_info.pid_info,
                                crash_info.tid_info,
                                crash_info.sig_info,
+                               crash_info.prstatus_fd,
                                crash_info.info_path);
        else
                ret = snprintf(command, sizeof(command),
-                               "%s --pid %s --sig %s > %s",
+                               "%s --pid %s --sig %s --prstatus_fd %d > %s",
                                CRASH_STACK_PATH,
                                crash_info.pid_info,
                                crash_info.sig_info,
+                               crash_info.prstatus_fd,
                                crash_info.info_path);
+       _D("    %s", command);
        if (ret < 0) {
                _E("Failed to snprintf for crash-stack command");
                return;
@@ -955,5 +1018,6 @@ int main(int argc, char *argv[])
                launch_crash_popup();
 #endif
 
+       close(crash_info.prstatus_fd);
        return 0;
 }
index 3e41269..29e1fb4 100644 (file)
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8.11)
 set(CRASH_STACK_BIN "crash-stack")
 
 # Common source code files
-set(CRASH_STACK_SRCS crash-stack.c crash-stack-libunw.c)
+set(CRASH_STACK_SRCS crash-stack.c crash-stack-libunw.c unwind.c proc.c mem_map.c)
 
 # Add architecture dependent source files
 if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
@@ -20,18 +20,19 @@ else()
   set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-stub.c)
 endif()
 
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fPIE")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fPIE -D_GNU_SOURCE=1")
 set(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie")
 
 # Binary
 add_executable(${CRASH_STACK_BIN} ${CRASH_STACK_SRCS})
 
 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})
+pkg_check_modules(LIBUNWIND REQUIRED libunwind-generic)
+set_property(TARGET ${CRASH_STACK_BIN} APPEND_STRING PROPERTY COMPILE_FLAGS ${LIBUNWIND_CFLAGS_OTHER})
 
 # Linking
-target_link_libraries(${CRASH_STACK_BIN} ${LIBUNWIND_PTRACE_LIBRARIES} ${EBL_LIBRARY} dw elf dl stdc++)
+target_link_libraries(${CRASH_STACK_BIN} ${LIBUNWIND_LIBRARIES} ${EBL_LIBRARY} elf dl stdc++)
+
 # Installing
 install(TARGETS ${CRASH_STACK_BIN} DESTINATION libexec)
 
index 7ce1be5..5b11332 100644 (file)
@@ -24,7 +24,7 @@
 #include <sys/user.h>
 #include <string.h>
 
-static struct user_regs_struct g_registers;    ///< static storage for ptrace buffer for registers
+static struct user_regs_struct g_registers;    ///< static storage for registers
 
 /**
  * @brief Important registers for unwinding stack on aarch64
@@ -44,14 +44,14 @@ struct Regs {
 typedef struct Regs Regs;      ///< convenience type definition
 static Regs g_regs;                    ///< static storage for target register values
 
-void *_crash_stack_get_memory_for_ptrace_registers(size_t *size)
+void *_crash_stack_get_memory_for_registers(size_t *size)
 {
        if (NULL != size)
                *size = sizeof(g_registers);
        return &g_registers;
 }
 
-void _crash_stack_set_ptrace_registers(void *regbuf)
+void _crash_stack_set_registers(void *regbuf)
 {
   struct user_regs_struct *regs = regbuf;
 
index ca338d8..1876b80 100644 (file)
@@ -25,7 +25,6 @@
 #include "crash-stack.h"
 
 #include <string.h>
-#include <sys/ptrace.h>
 #include <sys/user.h>
 
 // definitions copied from previously used McTernan unwinder
@@ -51,13 +50,13 @@ struct Regs {
 typedef struct Regs Regs;                                      ///< convenience type definition
 static Regs g_regs;                                                    ///< static storage for target register values
 
-static struct user_regs g_ptrace_registers;    ///< static storage for ptrace buffer for registers
+static struct user_regs g_registers;   ///< static storage for registers
 
-void *_crash_stack_get_memory_for_ptrace_registers(size_t *size)
+void *_crash_stack_get_memory_for_registers(size_t *size)
 {
        if (NULL != size)
-               *size = sizeof(g_ptrace_registers);
-       return &g_ptrace_registers;
+               *size = sizeof(g_registers);
+       return &g_registers;
 }
 
 void *_get_place_for_register_value(const char *regname, int regnum)
@@ -75,7 +74,7 @@ void *_get_place_for_register_value(const char *regname, int regnum)
        return NULL;
 }
 
-void _crash_stack_set_ptrace_registers(void *regbuf)
+void _crash_stack_set_registers(void *regbuf)
 {
        struct user_regs *registers = regbuf;
        int i;
@@ -88,24 +87,24 @@ void _crash_stack_set_ptrace_registers(void *regbuf)
 
 unsigned long _get_register_value(int n)
 {
-       return g_ptrace_registers.uregs[n];
+       return g_registers.uregs[n];
 }
 
 void _crash_stack_print_regs(FILE* outputfile)
 {
        fprintf(outputfile, "\nRegister Information\n");
        fprintf(outputfile, "r0   = 0x%08lx, r1   = 0x%08lx\nr2   = 0x%08lx, r3   = 0x%08lx\n",
-              g_ptrace_registers.uregs[0], g_ptrace_registers.uregs[1],
-              g_ptrace_registers.uregs[2], g_ptrace_registers.uregs[3]);
+              g_registers.uregs[0], g_registers.uregs[1],
+              g_registers.uregs[2], g_registers.uregs[3]);
        fprintf(outputfile, "r4   = 0x%08lx, r5   = 0x%08lx\nr6   = 0x%08lx, r7   = 0x%08lx\n",
-              g_ptrace_registers.uregs[4], g_ptrace_registers.uregs[5],
-              g_ptrace_registers.uregs[6], g_ptrace_registers.uregs[7]);
+              g_registers.uregs[4], g_registers.uregs[5],
+              g_registers.uregs[6], g_registers.uregs[7]);
        fprintf(outputfile, "r8   = 0x%08lx, r9   = 0x%08lx\nr10  = 0x%08lx, fp   = 0x%08lx\n",
-              g_ptrace_registers.uregs[8], g_ptrace_registers.uregs[9],
-              g_ptrace_registers.uregs[10], g_ptrace_registers.uregs[REG_FP]);
+              g_registers.uregs[8], g_registers.uregs[9],
+              g_registers.uregs[10], g_registers.uregs[REG_FP]);
        fprintf(outputfile, "ip   = 0x%08lx, sp   = 0x%08lx\nlr   = 0x%08lx, pc   = 0x%08lx\n",
-              g_ptrace_registers.uregs[REG_IP], g_ptrace_registers.uregs[REG_SP],
-              g_ptrace_registers.uregs[REG_LR], g_ptrace_registers.uregs[REG_PC]);
+              g_registers.uregs[REG_IP], g_registers.uregs[REG_SP],
+              g_registers.uregs[REG_LR], g_registers.uregs[REG_PC]);
        /* XXX the label should probably write "spsr" */
-       fprintf(outputfile, "cpsr = 0x%08lx\n", g_ptrace_registers.uregs[REG_SPSR]);
+       fprintf(outputfile, "cpsr = 0x%08lx\n", g_registers.uregs[REG_SPSR]);
 }
index 7161010..1875a05 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016-2018 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.
  * @file crash-stack-libunw.c
  * @brief unwinding call stacks, functions specific for archs that use only libunwind
  */
+#include <libunwind.h>
+#include <limits.h>
+#include <string.h>
+
 #include "crash-stack.h"
-#include <libunwind-ptrace.h>
 
-#define MAXPROCNAMELEN 512
+#define MAXPROCNAMELEN 1024
 
-void _create_crash_stack(Dwfl *dwfl, pid_t pid, Callstack *callstack)
+void _create_crash_stack(Dwfl *dwfl, pid_t pid, Callstack *callstack, elf_gregset_t *regs)
 {
        // reimplemented based on libunwind tests/test-ptrace.c file
        unw_addr_space_t as = 0;
@@ -34,11 +37,11 @@ void _create_crash_stack(Dwfl *dwfl, pid_t pid, Callstack *callstack)
                //init before return
                callstack->elems = 0;
 
-               as = unw_create_addr_space(&_UPT_accessors, 0);
+               as = unw_create_addr_space(_TB_accessors(), 0);
                if (!as)
                        break;
 
-               ui = _UPT_create(pid);
+               ui = _TB_create(pid);
                if (!ui)
                        break;
 
@@ -47,6 +50,7 @@ void _create_crash_stack(Dwfl *dwfl, pid_t pid, Callstack *callstack)
                        break;
 
                char proc_name[MAXPROCNAMELEN];
+               char mod_name[PATH_MAX];
                for (; callstack->elems < sizeof(callstack->proc)/sizeof(callstack->proc[0]); ) {
 
                        unw_word_t ip;
@@ -55,10 +59,23 @@ void _create_crash_stack(Dwfl *dwfl, pid_t pid, Callstack *callstack)
                        callstack->proc[callstack->elems].addr = ip;
 
                        proc_name[0] = '\0';
+                       mod_name[0] = '\0';
                        unw_word_t off;
-                       if (unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &off) == 0)
+                       unw_word_t off_m;
+                       if (unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &off) == 0) {
                                callstack->proc[callstack->elems].offset = off;
-
+                               callstack->proc[callstack->elems].name = strdup(proc_name);
+                       } else {
+                               callstack->proc[callstack->elems].offset = 0;
+                               callstack->proc[callstack->elems].name = NULL;
+                       }
+                       if (get_mod_name(ip, mod_name, PATH_MAX, &off_m) == 0) {
+                               callstack->proc[callstack->elems].module_offset = off_m;
+                               callstack->proc[callstack->elems].module_name = strdup(mod_name);
+                       } else {
+                               callstack->proc[callstack->elems].module_offset = 0;
+                               callstack->proc[callstack->elems].module_name = NULL;
+                       }
                        ++callstack->elems;
 
                        if (unw_step(&cursor) <= 0)
@@ -67,7 +84,7 @@ void _create_crash_stack(Dwfl *dwfl, pid_t pid, Callstack *callstack)
        } while (0);
 
        if (ui)
-               _UPT_destroy(ui);
+               _TB_destroy(ui);
        if (as)
                unw_destroy_addr_space(as);
 }
index eef97ea..ca1429c 100644 (file)
@@ -1,11 +1,11 @@
 #include "crash-stack.h"
 
-void *_crash_stack_get_memory_for_ptrace_registers(size_t *size)
+void *_crash_stack_get_memory_for_registers(size_t *size)
 {
                return NULL;
 }
 
-void _crash_stack_set_ptrace_registers(void *regbuf)
+void _crash_stack_set_registers(void *regbuf)
 {
 }
 
index e42de30..454848e 100644 (file)
@@ -24,9 +24,9 @@
 #include <sys/user.h>
 #include <string.h>
 
-struct user_regs_struct g_registers;   ///< static storage for ptrace buffer for registers
+struct user_regs_struct g_registers;   ///< static storage for registers
 
-void *_crash_stack_get_memory_for_ptrace_registers(size_t *size)
+void *_crash_stack_get_memory_for_registers(size_t *size)
 {
        if (NULL != size)
                *size = sizeof(g_registers);
@@ -42,10 +42,10 @@ void *_get_place_for_register_value(const char *regname, int regnum)
        return NULL;
 }
 
-void _crash_stack_set_ptrace_registers(void *regbuf)
+void _crash_stack_set_registers(void *regbuf)
 {
        /* Make it dummy as it not used for x86 anymore
-        * However it is still called by generic __get_registers_ptrace functions
+        * However it is still called by generic __get_registers functions
         */
 }
 
index 3ddffd7..c78a847 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016-2018 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.
@@ -27,7 +27,6 @@
  * of a crashed program. Crash-stack must be called with proper arguments:
  * PID of a crashed program.
  */
-#include "crash-stack.h"
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -39,7 +38,6 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
-#include <sys/ptrace.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
@@ -48,8 +46,8 @@
 #include <unistd.h>
 #include <assert.h>
 
-#include <elfutils/version.h>
-#include <elfutils/libdwfl.h>
+#include "crash-stack.h"
+
 
 #define BUF_SIZE (BUFSIZ)
 #define HEXA 16
@@ -73,7 +71,8 @@ enum {
        OPT_TID,
        OPT_SIGNUM,
        OPT_OUTPUTFILE,
-       OPT_ERRFILE
+       OPT_ERRFILE,
+       OPT_PRSTATUS_FD
 };
 
 /**
@@ -85,6 +84,7 @@ const struct option opts[] = {
        { "sig", required_argument, 0, OPT_SIGNUM },
        { "output", required_argument, 0, OPT_OUTPUTFILE },
        { "erroutput", required_argument, 0, OPT_ERRFILE },
+       { "prstatus_fd", required_argument, 0, OPT_PRSTATUS_FD },
        { 0, 0, 0, 0 }
 };
 
@@ -104,231 +104,33 @@ static struct addr_node *get_addr_list_from_maps(int fd);
 static void free_all_nodes(struct addr_node *start);
 static char *fgets_fd(char *str, int len, int fd);
 
-/*
- * __cxa_demangle() is taken from libstdc++, however there is no header that we
- * can take a declaration from. Importing through 'extern' allows using it.
- */
-/// @cond false
-extern char *__cxa_demangle(const char *mangled_name, char *output_buffer,
-               size_t *length, int *status);
-///@endcond
-
-/**
- * @brief A callback for dwfl_getmodules().
- *
- * This callback is called once for every module discovered by dwfl_getmodules().
- *
- * @param module the dwfl module
- * @param userdata unused, required by dwfl_getmodules()
- * @param name name of the module
- * @param address address of the module
- * @param arg 4th argument to dwfl_getmodules is passed here
- */
-static int __module_callback(Dwfl_Module *module, void **userdata,
-               const char *name, Dwarf_Addr address,
-               void *arg)
-{
-       return DWARF_CB_OK;
-}
-
-static void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start)
-{
-       Elf *elf;
-       int fd;
-       const char *elf_name = proc_info->module_name;
-       Dwarf_Addr address = proc_info->addr;
-
-       fd = open(elf_name, O_RDONLY);
-       if (-1 == fd)
-               return;
-
-       elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
-
-       if (NULL == elf) {
-               close(fd);
-               return;
-       }
-
-       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);
-}
-
-static int __attachable(pid_t pid, pid_t tid)
-{
-       /* read /proc/<pid>/stat */
-       char buf[40];
-       FILE *f;
-       char status;
-
-       snprintf(buf, sizeof(buf), "/proc/%d/task/%d/stat", pid, tid);
-
-       f = fopen(buf, "r");
-       if (NULL == f)
-               return -1;
-
-       /* check if status is D */
-       if (fscanf(f, "%*d %*s %c", &status) != 1) {
-               fclose(f);
-               return -1;
-       }
-
-       fclose(f);
-
-       return status != 'D';
-}
-
-static void __print_proc_file(pid_t pid, pid_t tid, const char *name)
-{
-       char buf[1024];
-       FILE *f;
-       int r;
-
-       snprintf(buf, sizeof(buf), "/proc/%d/task/%d/%s", pid, tid, name);
-
-       fprintf(outputfile, "%s:\n", buf);
-
-       f = fopen(buf, "r");
-       if (NULL == f) {
-               fprintf(errfile, "Failed to open %s: %m\n", buf);
-               return;
-       }
-
-       while ((r = fread(buf, 1, sizeof(buf), f)) > 0)
-               fwrite(buf, r, 1, outputfile);
-
-       fclose(f);
-
-       fprintf(outputfile, "\n");
-}
-
-static void __print_not_attachable_process_info(pid_t pid, pid_t tid)
-{
-       fprintf(outputfile, "ERROR: can't attach to process %d, thread %d - thread is in uninterruptible sleep state\n", pid, tid);
-       fprintf(outputfile, "Giving some /proc info instead:\n\n");
-       __print_proc_file(pid, tid, "wchan");
-       fprintf(outputfile, "\n");
-       __print_proc_file(pid, tid, "syscall");
-       __print_proc_file(pid, tid, "stack");
-}
-
-/**
- * @brief Opens libdwfl for using with live process
- *
- * @param pid pid of the process to attach to
- * @return Dwfl handle
- */
-static Dwfl *__open_dwfl_with_pid(pid_t pid, pid_t tid)
-{
-       int status;
-       pid_t stopped_pid;
-
-       status = __attachable(pid, tid);
-       if (-1 == status) {
-               fprintf(errfile, "failed to read /proc/%d/task/%d/stat: %m\n", pid, tid);
-               return NULL;
-       }
-
-       if (!status) {
-               __print_not_attachable_process_info(pid, tid);
-               return NULL;
-       }
-
-       if (ptrace(PTRACE_SEIZE, tid, NULL, PTRACE_O_TRACEEXIT) != 0) {
-               fprintf(errfile, "PTRACE_SEIZE failed on TID %d: %m\n", tid);
-               return NULL;
-       }
-
-       ptrace(PTRACE_INTERRUPT, tid, 0, 0);
-
-       stopped_pid = waitpid(tid, &status, __WALL);
-       if (stopped_pid == -1 || stopped_pid != tid || !WIFSTOPPED(status)) {
-               fprintf(errfile, "waitpid failed: %m, stopped_pid=%d, status=%d\n", stopped_pid, status);
-               return NULL;
-       }
-
-       static const Dwfl_Callbacks proc_callbacks = {
-               .find_elf = dwfl_linux_proc_find_elf,
-               .find_debuginfo = dwfl_standard_find_debuginfo,
-               .section_address = NULL,
-               .debuginfo_path = NULL
-       };
-
-       Dwfl *dwfl = dwfl_begin(&proc_callbacks);
-       if (dwfl == NULL) {
-               fprintf(errfile, "process %d : Can't start dwfl (%s)\n", tid, dwfl_errmsg(-1));
-               return NULL;
-       }
-
-       if (dwfl_linux_proc_report(dwfl, tid) < 0) {
-               fprintf(errfile, "process %d : dwfl report failed (%s)\n", tid, dwfl_errmsg(-1));
-               dwfl_end(dwfl);
-               return NULL;
-       }
-
-#if _ELFUTILS_PREREQ(0, 158)
-       if (dwfl_linux_proc_attach(dwfl, tid, true) < 0) {
-               fprintf(errfile, "process %d : dwfl attach failed (%s)\n", tid, dwfl_errmsg(-1));
-               dwfl_end(dwfl);
-               return NULL;
-       }
-#endif
-       return dwfl;
-}
-
 /**
  * @brief Gets registers information for live process
  *
  * @param pid pid of the live process
  * @return 0 on success, -1 otherwise
  */
-static int __get_registers_ptrace(pid_t pid)
+static int __get_registers_fd(pid_t pid, int fd)
 {
-       struct iovec data;
-       data.iov_base = _crash_stack_get_memory_for_ptrace_registers(&data.iov_len);
+       struct elf_prstatus *prstatus = NULL; ///< NT_PRSTATUS of the failed process
+       size_t size = 0;
+       char *registers = _crash_stack_get_memory_for_registers(&size);
 
-       if (NULL == data.iov_base) {
-               fprintf(errfile, "Cannot get memory for registers for ptrace (not implemented for this architecture\n");
+       if (NULL == registers) {
+               fprintf(errfile, "Cannot get memory for registers (not implemented for this architecture\n");
                return -1;
        }
 
-       if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &data) != 0) {
-               fprintf(errfile, "PTRACE_GETREGSET failed on PID %d: %m\n", pid);
+       prstatus = mmap(NULL, sizeof(struct elf_prstatus),
+                       PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+       if (prstatus == MAP_FAILED)
                return -1;
-       }
 
-       _crash_stack_set_ptrace_registers(data.iov_base);
+       if (prstatus->pr_pid != pid)
+               return -1;
+
+       memcpy(registers, prstatus->pr_reg, size);
 
        return 0;
 }
@@ -386,82 +188,6 @@ static void __crash_stack_print_signal(int signo)
 }
 
 /**
- * @brief Resolves procedure and module names using libdwfl
- *
- * @param proc_info gathered call stack element
- * @param dwfl dwfl handler
- */
-static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl)
-{
-       uintptr_t address = proc_info->addr;
-       Dwfl_Module *module = dwfl_addrmodule(dwfl, address);
-       if (module) {
-
-               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);
-
-               proc_info->module_offset = address - mapping_start;
-
-               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 = 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);
-       }
-}
-
-/**
- * @brief Checks if symbol starts with '_Z' prefix
- *
- * @param symbol string to compare
- */
-static int is_symbol_demanglable(const char *symbol)
-{
-       return symbol != 0 && (strlen(symbol) >= 2) &&
-               symbol[0] == '_' && symbol[1] == 'Z';
-}
-
-/**
- * @brief Replaces symbols with demangled
- *
- * @param proc_info gathered call stack element
- */
-static void __demangle_symbols(ProcInfo *proc_info)
-{
-       int status = -1;
-       char *dem_buffer = NULL;
-       char *demangled_symbol = __cxa_demangle(proc_info->name, dem_buffer, NULL, &status);
-       if (status == 0) {
-               free(proc_info->name);
-               proc_info->name = demangled_symbol;
-       }
-}
-
-/**
- * @brief Resolves procedure and module name
- *
- * @param proc_info gathered call stack element
- * @param dwfl dwfl handler
- * @param notes notes handler, NULL if live process analyzed
- */
-static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl)
-{
-       __resolve_symbols_from_dwfl(proc_info, dwfl);
-
-       if (is_symbol_demanglable(proc_info->name))
-               __demangle_symbols(proc_info);
-}
-
-/**
  * @brief Prints call stack element to the global outputfile.
  *
  * @param proc_info gathered call stack element
@@ -934,11 +660,13 @@ static int find_crash_tid(int pid)
  */
 int main(int argc, char **argv)
 {
+       int prstatus_fd = -1;
        int c;
        int signo = 0;
        pid_t pid = 0;
        pid_t tid = 0;
        char bufferfile_path[20] = "/tmp/crash.XXXXXX";
+       char *p = NULL;
 
        while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) {
                switch (c) {
@@ -957,6 +685,11 @@ int main(int argc, char **argv)
                case OPT_ERRFILE:
                        errfile = fopen(optarg, "w");
                        break;
+               case OPT_PRSTATUS_FD:
+                       prstatus_fd = strtol(optarg, &p, 10);
+                       if (*p != 0)
+                               prstatus_fd = -1;
+                       break;
                }
        }
 
@@ -985,21 +718,12 @@ int main(int argc, char **argv)
 
        elf_version(EV_CURRENT);
 
-       /* First, prepare dwfl and modules */
-       Dwfl *dwfl = NULL;
-
        /* Executable File Path */
        __crash_stack_print_exe(outputfile, pid);
 
        /* Signal information */
        __crash_stack_print_signal(signo);
 
-       /*
-        * Pre-ptrace info
-        *  Memory, thread, map info should be print in advance
-        *  because some of them will be lost after ptrace analysis
-        */
-
        /* Memory information */
        __crash_stack_print_meminfo(bufferfile, pid);
 
@@ -1009,36 +733,27 @@ int main(int argc, char **argv)
        /* Maps information */
        __crash_stack_print_maps(bufferfile, pid);
 
-       if (pid > 1)
-               dwfl = __open_dwfl_with_pid(pid, tid);
-       else {
+       if (pid <= 1) {
                fprintf(errfile,
                                "Usage: %s [--output file] [--erroutput file] [--pid <pid> [--tid <tid>]]\n",
                                argv[0]);
                return 1;
        }
 
-       if (NULL == dwfl)
-               return 1111;
-
-       dwfl_getmodules(dwfl, __module_callback, NULL, 0);
-
-       if (-1 == __get_registers_ptrace(tid))
+       if (-1 == __get_registers_fd(tid, prstatus_fd))
                return 3333;
 
        /* Unwind call stack */
        Callstack callstack;
        callstack_constructor(&callstack);
 
-       _create_crash_stack(dwfl, tid, &callstack);
-       size_t it;
-       for (it = 0; it != callstack.elems; ++it)
-               __resolve_symbols(&callstack.proc[it], dwfl);
+       _create_crash_stack(NULL, tid, &callstack,
+                           _crash_stack_get_memory_for_registers(NULL));
 
        /* Print registers */
        _crash_stack_print_regs(outputfile);
 
-       /* Print pre-ptrace info */
+       /* Print info */
        __print_buffer_info(bufferfile, outputfile);
 
        /* Print the results */
@@ -1046,8 +761,6 @@ int main(int argc, char **argv)
 
        /* Clean up */
        callstack_destructor(&callstack);
-       dwfl_report_end(dwfl, NULL, NULL);
-       dwfl_end(dwfl);
 
        return 0;
 }
index 0675251..6ce58c8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016-2017 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.
@@ -26,6 +26,8 @@
 
 #include <stdint.h>
 #include <elfutils/libdwfl.h>
+#include <libunwind.h>
+#include <sys/procfs.h>
 
 /**
  * @brief callstack.procedure info
@@ -66,32 +68,78 @@ void *_get_place_for_register_value(const char *regname, int regnum);
  * @param dwfl dwfl handle
  * @param pid pid of the analyzed process
  * @param callstack pointer to call stack database; results are put here
+ * @param regs pointer to registers of the analyzed process
  */
-void _create_crash_stack(Dwfl *dwfl, pid_t pid, Callstack *callstack);
+void _create_crash_stack(Dwfl *dwfl, pid_t pid, Callstack *callstack, elf_gregset_t *regs);
 
 /**
- * @brief Gets allocated space for getting target registers with ptrace().
+ * @brief Gets allocated space for getting target registers.
  *
  * @remarks This function uses static storage. Thus, it shouldn't be used in multiple threads.
  *
  * @param[out] size size of the registers structure
  * @return address of statically allocated storage of proper size for the registers
  */
-void *_crash_stack_get_memory_for_ptrace_registers(size_t *size);
+void *_crash_stack_get_memory_for_registers(size_t *size);
 
 /**
- * @brief Sets current values of registers from the ptrace buffer
+ * @brief Sets current values of registers from the buffer.
  *
- * @param regbuf buffer used for getting registers with ptrace()
+ * @param regbuf buffer used for getting registers
  *
- * @see _crash_stack_get_memory_for_ptrace_registers()
+ * @see _crash_stack_get_memory_for_registers()
  */
-void _crash_stack_set_ptrace_registers(void *regbuf);
+void _crash_stack_set_registers(void *regbuf);
 
 /**
- * @brief Print values of registers from the ptrace buffer
+ * @brief Return a value of a register from the buffer
+ *
+ * @param n libunwind register index, e.g. UNW_X86_EAX
+ *
+ * @return the value of the register
+ */
+unsigned long _get_register_value(int n);
+
+/**
+ * @brief Print values of registers from the buffer
  *
  * @param outputfile output stream
  */
 void _crash_stack_print_regs(FILE* outputfile);
+
+/**
+ * @brief Return the set of ptrace(2)-free accessors for libunwind
+ *
+ * @return pointer to unw_accessors_t structure
+ */
+unw_accessors_t *_TB_accessors();
+
+/**
+ * @brief Create a context for analysis
+ *
+ * @param pid pid of the analyzed process
+ *
+ * @return a pointer to pass as the third argument for unw_inint_remote()
+ */
+void *_TB_create(pid_t pid);
+
+/**
+ * @brief Free any resources allocated by _TB_create()
+ *
+ * @param ptr pointer returned by _TB_create()
+ */
+void _TB_destroy(void *ptr);
+
+/**
+ * @brief Find the name of the module and the offset for the address
+ *
+ * @param addr the address of the code to find the module for
+ * @param bufp the output buffer for the module name
+ * @param buf_len the size of the buffer
+ * @param offp output the offset of the code inside the module
+ *
+ * @return zero on success
+ */
+int get_mod_name(unw_word_t addr, char *bufp,
+                size_t buf_len, unw_word_t *offp);
 #endif /* CRASH_STACK_H */
index e330a1d..4703a74 100644 (file)
@@ -1,7 +1,6 @@
-/*
- * tbstack -- fast stack trace utility
- *
+/* -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * Copyright (c) 2014, Tbricks AB
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define VSYSCALL_START (-10UL << 20)
 #endif
 
-extern int opt_verbose;
-extern int opt_ignore_deleted;
+// extern int opt_verbose;
+// extern int opt_ignore_deleted;
+static int opt_verbose = 1;
+static int opt_ignore_deleted = 0;
+
+static void mem_region_print(const struct mem_region *region);
 
 static int in(const void *point, const void *start, size_t size)
 {
@@ -120,13 +123,14 @@ void mem_region_init(struct mem_region *region)
     region->next = NULL;
 }
 
-static void mem_region_add_label(struct mem_region *region,
+static int mem_region_add_label(struct mem_region *region,
         void *label, size_t reserve)
 {
     size_t i;
 
-    if (region->labels == NULL)
-        region->labels = malloc(sizeof(void *)*reserve);
+    if (region->labels == NULL &&
+        (region->labels = malloc(sizeof(void *)*reserve)) == NULL)
+        return -1;
 
     for (i = 0; i < region->num_labels; ++i) {
         if (region->labels[i] > label) {
@@ -138,6 +142,8 @@ static void mem_region_add_label(struct mem_region *region,
 
     region->labels[i] = label;
     ++region->num_labels;
+    mem_region_print(region);
+    return 0;
 }
 
 static int mem_region_add_data_chunk(struct mem_region *region,
@@ -152,14 +158,13 @@ static int mem_region_add_data_chunk(struct mem_region *region,
 
     for (i = 0; i < region->num_data_chunks; ++i) {
         if (in(chunk->start, (*cur)->start, (*cur)->length) ||
-            in(chunk_ceil, (*cur)->start, (*cur)->length))
-        {
             fprintf(stderr, "error: overlapping chunks: existing: %p-%p "
                             "new: %p-%p\n",
                             (*cur)->start,
                             (*cur)->start + (*cur)->length,
                             chunk->start,
                             chunk_ceil);
+            in(chunk_ceil, (*cur)->start, (*cur)->length)) {
             return -1;
         }
         if ((*cur)->start > chunk->start)
@@ -180,6 +185,8 @@ static struct mem_data_chunk *mem_region_alloc_chunk(struct mem_region *region,
     int rc;
 
     chunk = malloc(sizeof(struct mem_data_chunk));
+    if (chunk == NULL)
+        return NULL;
     mem_data_chunk_init(chunk);
 
     chunk->start = start;
@@ -187,6 +194,8 @@ static struct mem_data_chunk *mem_region_alloc_chunk(struct mem_region *region,
     rc = posix_memalign((void **)&chunk->data, align, chunk->length);
     if (rc < 0) {
         perror("posix_memalign");
+        int err = errno;
+        free(chunk);
         return NULL;
     }
 
@@ -218,9 +227,10 @@ const char *str_mem_region_type(int type)
 
 static void mem_region_print(const struct mem_region *region)
 {
+    int i;
     fprintf(stderr,
             "region addr: %zx-%zx len: %zx off: %zx num_chunks: %zd "
-            "path='%s' fd=%d type=%s\n",
+            "path='%s' fd=%d type=%s num_labels=%zd labels=[",
             (size_t)region->start,
             (size_t)region->start+region->length,
             region->length,
@@ -228,20 +238,30 @@ static void mem_region_print(const struct mem_region *region)
             region->num_data_chunks,
             region->path,
             region->fd,
-            str_mem_region_type(region->type));
+            str_mem_region_type(region->type),
+            region->num_labels);
+    for (i = 0; i < region->num_labels; i++) {
+        fprintf(stderr, "%p%s",
+                region->labels[i],
+                (region->num_labels > i + 1) ? ", " : "");
+    }
+    fprintf(stderr,"]\n");
 }
 
-static void mem_region_create_data_chunk_index(struct mem_region *region)
+static int mem_region_create_data_chunk_index(struct mem_region *region)
 {
     int i;
     struct mem_data_chunk *cur;
 
     if (!region->num_data_chunks)
-        return;
+        return -1;
 
-    region->data_index = malloc(sizeof(
-                struct mem_data_chunk*) * region->num_data_chunks);
+    region->data_index = malloc(sizeof(struct mem_data_chunk*) *
+                                region->num_data_chunks);
 
+    if (region->data_index == NULL) {
+        return -1;
+    }
     cur = region->data_head;
     for (i = 0; cur != NULL; cur = cur->next) {
         region->data_index[i++] = cur;
@@ -250,9 +270,10 @@ static void mem_region_create_data_chunk_index(struct mem_region *region)
             fprintf(stderr, "region %p: num_data_chunks=%zd but cur != NULL\n",
                     region, region->num_data_chunks);
             mem_region_print(region);
-            break;
+            return -1;
         }
     }
+    return 0;
 }
 
 static char *addr_increment_clamped(char *start, char *end, size_t increment)
@@ -276,7 +297,8 @@ static int mem_region_build_label_cover(struct mem_region *region,
 
         region_end = (char *)region->start + region->length;
         cur_start = region->labels[i];
-        cur_end = addr_increment_clamped(cur_start, region_end, generic_chunk_size);
+        cur_end = addr_increment_clamped(cur_start, region_end,
+                                         generic_chunk_size);
 
         for (++i; i < region->num_labels; ++i) {
             if ((size_t)region->labels[i] <= (size_t)cur_end) {
@@ -292,7 +314,8 @@ static int mem_region_build_label_cover(struct mem_region *region,
         ++n;
     }
 
-    mem_region_create_data_chunk_index(region);
+    if (mem_region_create_data_chunk_index(region) < 0)
+        return 0;
 
     return n;
 }
@@ -312,7 +335,8 @@ static int mem_region_map_file(struct mem_region *region)
 
     region->fd = open(region->path, O_RDONLY);
     if (region->fd < 0) {
-        perror(region->path);
+        int err = errno;
+        mem_region_print(region);
         return -1;
     }
 
@@ -345,12 +369,23 @@ static int mem_region_map_file(struct mem_region *region)
     }
 
     region->data_head = malloc(sizeof(struct mem_data_chunk));
+    if (region->data_head == NULL) {
+        int err = errno;
+        munmap(data, length);
+        return -1;
+    }
     mem_data_chunk_init(region->data_head);
     region->data_head->start = region->start;
     region->data_head->data = data;
     region->data_head->length = length;
 
     region->data_index = malloc(sizeof(struct mem_data_chunk**));
+    if (region->data_index == NULL){
+        int err = errno;
+        free(region->data_head);
+        munmap(data, length);
+        return -1;
+    }
     *region->data_index = region->data_head;
     ++region->num_data_chunks;
 
@@ -370,6 +405,10 @@ static int mem_region_init_vdso(struct mem_region *region)
         return -1;
 
     region->data_index = malloc(sizeof(struct mem_data_chunk**));
+    if (region->data_index == NULL) {
+        int err = errno;
+        return -1;
+    }
     *region->data_index = region->data_head;
     ++region->num_data_chunks;
 
@@ -381,12 +420,19 @@ static int mem_region_init_vdso(struct mem_region *region)
 static int mem_region_init_vsyscall(struct mem_region *region)
 {
     region->data_head = malloc(sizeof(struct mem_data_chunk));
+    if (region->data_head == NULL) {
+        int err = errno;
+        return -1;
+    }
     mem_data_chunk_init(region->data_head);
     region->data_head->start = region->start;
     region->data_head->data = (char *)VSYSCALL_START;
     region->data_head->length = region->length;
-
     region->data_index = malloc(sizeof(struct mem_data_chunk**));
+    if (region->data_index == NULL) {
+        int err = errno;
+        return -1;
+    }
     *region->data_index = region->data_head;
     ++region->num_data_chunks;
 
@@ -455,6 +501,7 @@ static int mem_region_read_word(struct mem_region *region,
     case MEM_REGION_TYPE_DELETED:
         if (!opt_ignore_deleted)
             return -2;
+        break;
 
     case MEM_REGION_TYPE_MMAP:
         if (region->fd < 0 && mem_region_map_file(region) < 0)
@@ -470,7 +517,6 @@ static int mem_region_read_word(struct mem_region *region,
         if (region->data_head == NULL && mem_region_init_vsyscall(region) < 0)
             return -1;
         break;
-
     default:
         break;
     }
@@ -504,7 +550,7 @@ static int mem_region_read_word(struct mem_region *region,
             value);
 }
 
-static void mem_region_destroy(struct mem_region *region)
+void mem_region_destroy(struct mem_region *region)
 {
     if (region->data_head != NULL)
         mem_data_chunk_list_destroy(region->data_head, region->type);
@@ -670,8 +716,7 @@ int mem_map_add_label(struct mem_map *map, void *label, size_t reserve)
     if (region == NULL)
         return -1;
 
-    mem_region_add_label(region, label, reserve);
-    return 0;
+    return mem_region_add_label(region, label, reserve);
 }
 
 int mem_map_build_label_cover(struct mem_map *map, size_t generic_chunk_size,
@@ -693,14 +738,16 @@ int mem_map_build_label_cover(struct mem_map *map, size_t generic_chunk_size,
 int mem_map_read_word(struct mem_map *map, void *addr, uintptr_t *value)
 {
     struct mem_region *region;
-
+    int err;
     region = mem_map_find_region(map, addr);
     if (region == NULL)
         return -1;
 
-    return mem_region_read_word(region,
+    err = mem_region_read_word(region,
             addr,
             value);
+
+    return err;
 }
 
 void mem_map_destroy(struct mem_map *map)
index 309671e..074e87e 100644 (file)
@@ -1,6 +1,4 @@
-/*
- * tbstack -- fast stack trace utility
- *
+/* -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * Copyright (c) 2014, Tbricks AB
  * All rights reserved.
  *
@@ -107,6 +105,8 @@ const char *str_mem_region_type(int type);
 
 void mem_region_init(struct mem_region *region);
 
+void mem_region_destroy(struct mem_region *region);
+
 /*
  * mem map
  */
index 929929f..457f530 100644 (file)
@@ -1,7 +1,6 @@
-/*
- * tbstack -- fast stack trace utility
- *
+/* -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * Copyright (c) 2014, Tbricks AB
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,7 +41,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/ptrace.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
 #include <sys/time.h>
@@ -56,6 +54,8 @@
 #define SYS_process_vm_readv 365
 #elif defined(__x86_64)
 #define SYS_process_vm_readv 310
+#elif defined(__arm__) || defined(__aarch64__)
+#define SYS_process_vm_readv 376
 #else
 #error SYS_process_vm_readv is undefined
 #endif
@@ -67,7 +67,7 @@ int attached_pid = 0;
 
 /* timeout on waiting for process to stop (us) */
 extern int stop_timeout;
-static int sleep_time = 0;
+/* static int sleep_time = 0; */
 
 /* for summary */
 int sleep_count = 0;
@@ -76,9 +76,12 @@ size_t total_length = 0;
 extern struct timeval freeze_time;
 extern struct timeval unfreeze_time;
 
-extern int opt_proc_mem;
-extern int opt_use_waitpid_timeout;
-extern int opt_verbose;
+/* extern int opt_proc_mem; */
+/* extern int opt_use_waitpid_timeout; */
+/* extern int opt_verbose; */
+
+static int opt_proc_mem = 0;
+static int opt_verbose = 0;
 
 int proc_state(int pid)
 {
@@ -87,7 +90,7 @@ int proc_state(int pid)
     char c;
     int res = -1;
 
-    sprintf(buf, "/proc/%d/status", pid);
+    snprintf(buf, sizeof(buf), "/proc/%d/status", pid);
     if ((f = fopen(buf, "r")) == NULL) {
         fprintf(stderr, "cannot open %s: %s\n", buf, strerror(errno));
         return -1;
@@ -104,20 +107,11 @@ int proc_state(int pid)
     return res;
 }
 
-static int proc_stopped(int pid)
-{
-    int c = proc_state(pid);
-    if (c == -1)
-        return -1;
-
-    return (c == 't' || c == 'T');
-}
-
 struct mem_map *create_maps(int pid)
 {
-    FILE *f;
+    FILE *f = NULL;
     char *buf = NULL, *str = NULL;
-    size_t total_read, capacity;
+    size_t total_read, capacity, count;
 
     size_t addr_start, addr_end, offset, len;
     char r, w, x, p;
@@ -129,21 +123,27 @@ struct mem_map *create_maps(int pid)
 
     capacity = 0x100000;
     buf = calloc(1, capacity);
-
-    sprintf(buf, "/proc/%d/maps", pid);
+    if (buf == NULL) {
+        return NULL;
+    }
+    snprintf(buf, capacity, "/proc/%d/maps", pid);
     if ((f = fopen(buf, "r")) == NULL) {
         fprintf(stderr, "cannot open %s: %s\n", buf, strerror(errno));
-        return NULL;
+        goto create_maps_end;
     }
 
     map = malloc(sizeof(struct mem_map));
+    if (map == NULL){
+        goto create_maps_end;
+    }
     mem_map_init(map);
 
     memset(buf, 0, capacity);
     total_read = 0;
     while (!feof(f)) {
-        fread(&buf[total_read], capacity - total_read - 1, 1, f);
-        if (errno) {
+        count = fread(&buf[total_read], capacity - total_read - 1, 1, f);
+        if (count <1 && ferror(f)) {
+            clearerr(f);
             perror("maps");
             mem_map_destroy(map);
             map = NULL;
@@ -154,6 +154,11 @@ struct mem_map *create_maps(int pid)
         if ((total_read + 1) == capacity) {
             capacity *= 2;
             buf = realloc(buf, capacity);
+            if (buf == NULL) {
+                mem_map_destroy(map);
+                map = NULL;
+                goto create_maps_end;
+            }
             memset(&buf[total_read], 0, capacity - total_read);
         } else {
             buf[total_read] = '\0';
@@ -184,6 +189,11 @@ struct mem_map *create_maps(int pid)
         }
 
         region = malloc(sizeof(struct mem_region));
+        if (region == NULL) {
+            mem_map_destroy(map);
+            map = NULL;
+            break;
+        }
         mem_region_init(region);
 
         region->start = (void *)addr_start;
@@ -206,6 +216,7 @@ struct mem_map *create_maps(int pid)
         }
 
         if (mem_map_add_region(map, region) != 0) {
+            mem_region_destroy(region);
             mem_map_destroy(map);
             map = NULL;
             break;
@@ -219,15 +230,17 @@ struct mem_map *create_maps(int pid)
         mem_map_create_region_index(map);
 
 create_maps_end:
-    fclose(f);
-    free(buf);
+    if (f != NULL)
+        fclose(f);
+    if (buf != NULL)
+        free(buf);
     return map;
 }
 
 int print_proc_maps(int pid)
 {
     char cmd[32];
-    sprintf(cmd, "cat /proc/%d/maps 1>&2", pid);
+    snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps 1>&2", pid);
     return system(cmd);
 }
 
@@ -340,111 +353,6 @@ int filter_threads(int tids[], int index[], char states[], int nr_tids,
     return nr_tids;
 }
 
-int attach_process(int pid)
-{
-    int status = 0;
-
-    gettimeofday(&freeze_time, NULL);
-
-    attached_pid = pid;
-    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
-        perror("attach");
-        detach_process(pid);
-        return -1;
-    }
-    if (!proc_stopped(pid)) {
-        struct itimerval tm;
-
-        if (opt_use_waitpid_timeout) {
-            /* setup alarm to avoid long waiting on waitpid */
-            tm.it_interval.tv_sec = 0;
-            tm.it_interval.tv_usec = 0;
-            tm.it_value.tv_sec = 1;
-            tm.it_value.tv_usec = stop_timeout % 1000000;
-            setitimer(ITIMER_REAL, &tm, NULL);
-        }
-
-        if (waitpid(pid, &status, WUNTRACED) < 0) {
-            if (errno == EINTR) {
-                fprintf(stderr, "timeout on waitpid\n");
-                detach_process(pid);
-                return -1;
-            }
-            fprintf(stderr, "waitpid %d: %s\n", pid, strerror(errno));
-            detach_process(pid);
-            return -1;
-        }
-
-        if (opt_use_waitpid_timeout) {
-            tm.it_value.tv_sec = 0;
-            tm.it_value.tv_usec = 0;
-            setitimer(ITIMER_REAL, &tm, NULL);
-        }
-
-        if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP)
-            fprintf(stderr, "warning: waitpid(%d) WIFSTOPPED=%d WSTOPSIG=%d\n",
-                    pid, WIFSTOPPED(status), WSTOPSIG(status));
-    }
-    if (kill(pid, SIGSTOP) < 0) {
-        perror("send SIGSTOP");
-        return -1;
-    }
-    return 0;
-}
-
-int attach_thread(int tid)
-{
-    if (ptrace(PTRACE_ATTACH, tid, NULL, NULL) < 0) {
-        perror("PTRACE_ATTACH");
-        return -1;
-    }
-    if (wait_thread(tid) < 0)
-        return -1;
-    return 0;
-}
-
-int detach_process(int pid)
-{
-    int rc = 0;
-    if (ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {
-        perror("detach");
-        rc = -1;
-    }
-    if (kill(pid, SIGCONT) < 0) {
-        perror("send SIGCONT");
-        rc = -1;
-    }
-
-    attached_pid = 0;
-    gettimeofday(&unfreeze_time, NULL);
-    return rc;
-}
-
-int detach_thread(int tid)
-{
-    long rc = ptrace(PTRACE_DETACH, tid, NULL, NULL);
-    if (rc < 0) {
-        perror("PTRACE_DETACH");
-        return -1;
-    }
-    return 0;
-}
-
-int wait_thread(int tid)
-{
-    int rc;
-    while (!(rc = proc_stopped(tid))) {
-        if (stop_timeout && sleep_time > stop_timeout) {
-            fprintf(stderr, "timeout waiting for thread %d to stop", tid);
-            return -1;
-        }
-        usleep(SLEEP_WAIT);
-        sleep_time += SLEEP_WAIT;
-        sleep_count++;
-    }
-    return (rc == -1 ? -1 : 0);
-}
-
 /*
  * copy memory contents using process_vm_readv(). reduces number
  * of system calls comparing to /proc/pid/mem
@@ -542,7 +450,7 @@ static int copy_memory_proc_mem(int pid, struct mem_data_chunk **frames,
     int fd;
     int rc = -1;
 
-    sprintf(fname, "/proc/%d/mem", pid);
+    snprintf(fname, sizeof(fname), "/proc/%d/mem", pid);
     if ((fd = open(fname, O_RDONLY)) == -1) {
         fprintf(stderr, "cannot open %s\n", fname);
         perror(fname);
@@ -558,7 +466,7 @@ static int copy_memory_proc_mem(int pid, struct mem_data_chunk **frames,
             ssize_t rd = pread(fd, to, count, from);
 
             if (rd == -1) {
-                fprintf(stderr, "pread() at %s:0x%jx (#%d) failed: %s [%d]\n",
+                fprintf(stderr, "pread() at %s:0x%lx (#%d) failed: %s [%d]\n",
                         fname, from, i, strerror(errno), errno);
                 goto proc_mem_end;
             }
@@ -622,22 +530,3 @@ get_vdso_fail:
     fclose(f);
     return NULL;
 }
-
-void quit_handler(int signum)
-{
-    /*
-     * We can't call PTRACE_DETACH here because we are in a signal handler.
-     * Additionally ptrace will automatically detach when this process exits at
-     * the end of this function. We do however always need to send the SIGCONT
-     * if we have ptrace attached because when the ptrace automatically
-     * detaches it will leave the process in a stopped state even if we had not
-     * yet sent SIGSTOP to it.
-     */
-    if (attached_pid)
-        kill(attached_pid, SIGCONT);
-    if (signum == SIGSEGV) {
-        static volatile int *n = NULL;
-        *n = 1969;
-    }
-    _exit(1);
-}
index 454d62a..00c8c1c 100644 (file)
@@ -1,7 +1,6 @@
-/*
- * tbstack -- fast stack trace utility
- *
+/* -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * Copyright (c) 2014, Tbricks AB
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -110,10 +109,5 @@ int copy_memory(int pid, struct mem_data_chunk **frames, int n_frames);
  */
 void *get_vdso(void);
 
-/*
- * detach from process and send SIGCONT when interrupt/termination occurs
- */
-void quit_handler(int signum);
-
 #endif
 
index 7f2e54d..a2b140d 100644 (file)
@@ -1,7 +1,6 @@
-/*
- * tbstack -- fast stack trace utility
- *
+/* -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * Copyright (c) 2014, Tbricks AB
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * DAMAGE.
  */
 
-#include "mem_map.h"
-#include "snapshot.h"
-#include "unwind.h"
-
 #include <dwarf.h>
 #include <gelf.h>
 #include <libelf.h>
 #include <libgen.h>
 #include <libunwind.h>
-#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
 #include <sys/user.h>
+#include <unistd.h>
+
+#include "mem_map.h"
+#include "proc.h"
+#include "crash-stack.h"
+
+size_t stack_size = 0xa00000;
 
 /*
  * some libelf implementations do not provide ELF_C_READ_MMAP
 #define TBSTACK_ELF_C_READ ELF_C_READ
 #endif
 
+#define to_unw_word(p) ((unw_word_t) (uintptr_t) (p))
+
 /*
  * search unwind table for a procedure (used by find_proc_info)
  */
+#if defined(__arm__)
+#define search_unwind_table UNW_OBJ(search_unwind_table)
+#else
 #define search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
+#endif
 extern int search_unwind_table(unw_addr_space_t as, unw_word_t ip,
         unw_dyn_info_t *di, unw_proc_info_t *pip,
         int need_unwind_info, void *arg);
 
+static struct mem_map *map = NULL;
+static unsigned long eip = 0;
+static unsigned long esp = 0;
+static FILE *debug;
+
+static Elf *elf_start(int fd, char *image, uint64_t size)
+{
+    Elf *elf;
+
+    if (fd > 0) {
+        if ((elf = elf_begin(fd, TBSTACK_ELF_C_READ, NULL)) == NULL)
+            fprintf(stderr, "error:elf_begin: %s\n", elf_errmsg(elf_errno()));
+    } else {
+        if ((elf = elf_memory(image, size)) == NULL)
+            fprintf(stderr, "error:elf_memory: %s\n", elf_errmsg(elf_errno()));
+    }
 
-#ifdef HAVE_DWARF
-#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
+    return elf;
+}
 
-extern int dwarf_find_debug_frame(int found,
-                                unw_dyn_info_t *di_debug,
-                                unw_word_t ip,
-                                unw_word_t segbase,
-                                const char *obj_name, unw_word_t start,
-                                unw_word_t end);
-#endif
+#if defined(__arm__)
+/*
+ * find section .ARM.exidx in ELF binary
+ */
+static int find_exidx(int fd, char *image, uint64_t size,
+                     uint64_t *table_data, uint64_t *table_len)
+{
+    Elf *elf;
+    GElf_Ehdr ehdr;
+    Elf_Scn *scn = NULL;
+    GElf_Shdr shdr;
+    uint64_t offset = 0;
+
+    if ((elf = elf_start(fd, image, size)) == NULL)
+        return -1;
+
+    if (gelf_getehdr(elf, &ehdr) == NULL) {
+        fprintf(stderr, "error:elf_getehdr: %s\n", elf_errmsg(elf_errno()));
+        goto find_exidx_end;
+    }
+
+    while ((scn = elf_nextscn(elf, scn)) != NULL) {
+        if (gelf_getshdr(scn, &shdr) == NULL) {
+            fprintf(stderr, "error:elf_getshdr: %s\n", elf_errmsg(elf_errno()));
+            break;
+        }
 
+        if (shdr.sh_type == SHT_ARM_EXIDX) {
+            Elf_Data *data = NULL;
 
+            if ((data = elf_getdata(scn, data)) == NULL) {
+                fprintf(stderr, "error:elf_getdata: %s\n", elf_errmsg(elf_errno()));
+                break;
+            }
+
+            offset = *table_data = shdr.sh_offset;
+           *table_len = shdr.sh_size;
+        }
+    }
+
+find_exidx_end:
+    elf_end(elf);
+    return (offset ? 0 : -1);
+}
+#else /* __arm__ */
 /*
  * get dwarf encoded value
  */
@@ -163,7 +223,7 @@ static int parse_eh_frame_hdr(char *data, size_t pos,
     pos += 4;
 
     if (version != 1) {
-        fprintf(stderr, "unknown .ehf_frame_hdr version %d\n", version);
+        fprintf(stderr, "error:unknown .ehf_frame_hdr version %d\n", version);
         return -1;
     }
 
@@ -182,21 +242,6 @@ static int parse_eh_frame_hdr(char *data, size_t pos,
     return 0;
 }
 
-static Elf *elf_start(int fd, char *image, uint64_t size)
-{
-    Elf *elf;
-
-    if (fd > 0) {
-        if ((elf = elf_begin(fd, TBSTACK_ELF_C_READ, NULL)) == NULL)
-            fprintf(stderr, "elf_begin: %s\n", elf_errmsg(elf_errno()));
-    } else {
-        if ((elf = elf_memory(image, size)) == NULL)
-            fprintf(stderr, "elf_memory: %s\n", elf_errmsg(elf_errno()));
-    }
-
-    return elf;
-}
-
 /*
  * find section .eh_frame_hdr in ELF binary
  */
@@ -221,7 +266,7 @@ static int find_eh_frame_hdr(int fd, char *image, uint64_t size,
         char *str;
 
         if (gelf_getshdr(scn, &shdr) == NULL) {
-            fprintf(stderr, "elf_getshdr: %s\n", elf_errmsg(elf_errno()));
+            fprintf(stderr, "elf_nextscn: %s\n", elf_errmsg(elf_errno()));
             break;
         }
 
@@ -240,13 +285,27 @@ static int find_eh_frame_hdr(int fd, char *image, uint64_t size,
         }
     }
 
-    if (!offset)
-        goto elf_section_offset_end;
-
 elf_section_offset_end:
     elf_end(elf);
     return (offset ? 0 : -1);
 }
+#endif /* __arm__ */
+
+static int find_unwind_table(int fd, char *image, uint64_t size,
+                            uint64_t *table_data, int *table_format,
+                            uint64_t *segbase, uint64_t *table_len)
+{
+#if defined(__arm__)
+       (void) segbase;
+       *table_format = UNW_INFO_FORMAT_ARM_EXIDX;
+       return find_exidx(fd, image, size, table_data, table_len);
+#else
+       (void) table_data;
+       *table_format = UNW_INFO_FORMAT_REMOTE_TABLE;
+       return find_eh_frame_hdr(fd, image, size, table_data, segbase, table_len);
+#endif
+}
+
 
 /*
  * dynamic array of symbols
@@ -261,18 +320,22 @@ struct symbols
 /*
  * add a symbol to array
  */
-static void push_symbol(struct symbols *array, const GElf_Sym *s)
+static int push_symbol(struct symbols *array, const GElf_Sym *s)
 {
     ++array->s_size;
     if (array->s_size > array->s_cap) {
         GElf_Sym *new_data;
         array->s_cap <<= 1;
         new_data = malloc(sizeof(GElf_Sym) * array->s_cap);
+        if (new_data == NULL) {
+            return -1;
+        }
         memcpy(new_data, array->s_data, sizeof(GElf_Sym) * (array->s_size-1));
         free(array->s_data);
         array->s_data = new_data;
     }
     memcpy(array->s_data + (array->s_size-1), s, sizeof(GElf_Sym));
+    return 0;
 }
 
 /*
@@ -323,6 +386,9 @@ static char *proc_name(int fd, char *image, size_t size, uint64_t load,
     all.s_size = 0;
     all.s_data = malloc(all.s_cap * sizeof(GElf_Sym));
 
+    if (all.s_data == NULL)
+           goto proc_name_end;
+
     if (elf_getphdrnum (elf, &pnum))
         goto proc_name_end;
 
@@ -406,7 +472,8 @@ static char *proc_name(int fd, char *image, size_t size, uint64_t load,
                 /*
                  * save symbol in array
                  */
-                push_symbol(&all, &s);
+                if (push_symbol(&all, &s) < 0)
+                    goto proc_name_end;
             }
         }
     }
@@ -465,136 +532,61 @@ static int get_elf_image_info(struct mem_region *region,
     return 0;
 }
 
-#ifdef HAVE_DWARF
-static int elf_is_exec(int fd, char *image, uint64_t size)
-{
-    Elf *elf;
-    GElf_Ehdr ehdr;
-    int ret = 0;
-
-    if ((elf = elf_start(fd, image, size)) == NULL)
-        return 0;
-
-    if (gelf_getehdr(elf, &ehdr) == NULL) {
-        fprintf(stderr, "elf_getehdr: %s\n", elf_errmsg(elf_errno()));
-        goto elf_is_exec_end;
-    }
-
-    ret = ehdr.e_type == ET_EXEC;
-
-elf_is_exec_end:
-    elf_end(elf);
-
-    return ret;
-}
-
-static int elf_get_link_base(int fd, char *image, uint64_t size,
-        uint64_t *link_base)
-{
-    Elf *elf;
-    GElf_Ehdr ehdr;
-    GElf_Phdr phdr;
-    int idx=0;
-    uint64_t offset = UINT64_MAX;
-
-    if ((elf = elf_start(fd, image, size)) == NULL)
-        return -1;
-
-    if (gelf_getehdr(elf, &ehdr) == NULL) {
-        fprintf(stderr, "elf_getehdr: %s\n", elf_errmsg(elf_errno()));
-        goto elf_section_offset_end;
-    }
-
-    /* Get the vaddr of the segment with 0 offset.  This is the link base of
-     * the shared object. */
-    while (gelf_getphdr(elf, idx, &phdr) && phdr.p_type != PT_NULL) {
-       if (phdr.p_type != PT_LOAD)
-           goto next;
-
-       if (phdr.p_offset)
-           goto next;
-
-       offset = phdr.p_vaddr;
-       break;
-
-next:
-       idx++;
-    }
-
-    *link_base = offset;
-    elf_end(elf);
-    return 0;
-
-elf_section_offset_end:
-    elf_end(elf);
-    return -1;
-}
-
-#endif
-
 /*
  * find unwind info for function
  */
 static int find_proc_info(unw_addr_space_t as, unw_word_t ip,
         unw_proc_info_t *pip, int need_unwind_info, void *arg)
 {
-    struct snapshot *snap = arg;
     struct mem_region *region;
     char *elf_image = NULL;
     uint64_t elf_length = 0;
     unw_dyn_info_t di;
     uint64_t table_data = 0;
     uint64_t segbase, fde_count;
+    int table_format = -1;
     int rc = -UNW_EINVAL;
 
+    (void) arg;
+
     if (ip == 0)
         return -UNW_ENOINFO;
 
-    if ((region = mem_map_get_file_region(snap->map, (void *)ip)) == NULL)
+    if ((region = mem_map_get_file_region(map, (void *)ip)) == NULL)
         return rc;
 
     if (region->fd < 0 && region->type != MEM_REGION_TYPE_VDSO
-            && region->type != MEM_REGION_TYPE_VSYSCALL)
+        && region->type != MEM_REGION_TYPE_VSYSCALL)
         return rc;
 
     if (region->fd < 0 &&
-            get_elf_image_info(region, &elf_image, &elf_length, ip) < 0)
+        get_elf_image_info(region, &elf_image, &elf_length, ip) < 0)
         return rc;
 
     memset(&di, 0, sizeof(di));
 
-    if (!find_eh_frame_hdr(region->fd, elf_image, elf_length,
-                &table_data, &segbase, &fde_count)) {
-
-        di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
+    if (find_unwind_table(region->fd, elf_image, elf_length,
+                          &table_data, &table_format, &segbase,
+                          &fde_count) !=0) {
+        rc = -UNW_ENOINFO;
+    } else {
+        di.format = table_format;
         di.start_ip = (unw_word_t)region->start;
         di.end_ip = (unw_word_t)region->start + region->length;
-        di.u.rti.segbase = (unw_word_t)(region->start - region->offset) + segbase;
-        di.u.rti.table_data = (unw_word_t)(region->start - region->offset) + table_data;
-        di.u.rti.table_len =
-            fde_count * sizeof(uint32_t) * 2 / sizeof(unw_word_t);
 
+        if (table_format == UNW_INFO_FORMAT_REMOTE_TABLE) {
+            di.u.rti.name_ptr = 0;
+            di.u.rti.segbase = (unw_word_t)(region->start - region->offset) + segbase;
+            di.u.rti.table_data = (unw_word_t)(region->start - region->offset) + table_data;
+            di.u.rti.table_len = fde_count * sizeof(uint32_t) * 2 / sizeof(unw_word_t);
+        } else if (table_format == UNW_INFO_FORMAT_ARM_EXIDX) {
+            di.u.rti.name_ptr = to_unw_word(region->path);
+            di.u.rti.table_data = (unw_word_t)region->start + table_data;
+            di.u.rti.table_len = fde_count;
+        }
         rc = search_unwind_table(as, ip, &di, pip, need_unwind_info, arg);
     }
 
-    if (rc == 0)
-        return rc;
-
-#ifdef HAVE_DWARF
-    unw_word_t base = 0;
-    if (!elf_is_exec(region->fd, elf_image, elf_length)) {
-       uint64_t link_base;
-       if (elf_get_link_base(region->fd, elf_image, elf_length, &link_base))
-           return -UNW_EINVAL;
-        base = (uintptr_t)region->start - link_base;
-    }
-
-    if (dwarf_find_debug_frame(0, &di, ip, base, region->path,
-                (unw_word_t) region->start,
-                (unw_word_t) region->start + region->length))
-            return search_unwind_table(as, ip, &di, pip, need_unwind_info, arg);
-#endif
-
     return rc;
 }
 
@@ -607,6 +599,7 @@ static void put_unwind_info(unw_addr_space_t as,
     (void) as;
     (void) pip;
     (void) arg;
+    fprintf(debug, "%s is not supported\n", __func__);
 }
 
 /*
@@ -618,6 +611,7 @@ static int get_dyn_info_list_addr(unw_addr_space_t as,
     (void) as;
     (void) dilap;
     (void) arg;
+    fprintf(debug, "%s is not supported\n", __func__);
     return -UNW_ENOINFO;
 }
 
@@ -627,16 +621,15 @@ static int get_dyn_info_list_addr(unw_addr_space_t as,
 static int access_mem(unw_addr_space_t as, unw_word_t addr,
         unw_word_t *valp, int write, void *arg)
 {
-    struct snapshot *snap = arg;
-
     (void) as;
+    (void) arg;
 
     if (write) {
         fprintf(stderr, "access_mem: requested write, rejecting\n");
         return -UNW_EINVAL;
     }
 
-    return mem_map_read_word(snap->map, (void *)(uintptr_t)addr, valp);
+    return mem_map_read_word(map, (void *)(uintptr_t)addr, valp);
 }
 
 /*
@@ -645,133 +638,86 @@ static int access_mem(unw_addr_space_t as, unw_word_t addr,
 static int access_reg(unw_addr_space_t as, unw_regnum_t reg,
         unw_word_t *val, int write, void *arg)
 {
-    struct snapshot *snap = arg;
 
-    (void) as;
+       (void) as;
+       (void) val;
+       (void) write;
+       (void) arg;
 
-    if (write) {
-        fprintf(stderr, "requested to write into register\n");
-        return -UNW_EINVAL;
-    }
+       fprintf(debug, "debug: requested register %d\n", reg);
+       fflush(debug);
 
-    switch (reg) {
-#if defined(UNW_TARGET_AARCH64)
-    case UNW_AARCH64_X0 ... UNW_AARCH64_X30:
-        /*
-         * Currently this enum directly maps to the index so this is a no-op.
-         * Assert just in case.
-         */
-        reg -= UNW_AARCH64_X0;
-        assert(reg>= 0 && reg <= 30);
-        *val = snap->regs[snap->cur_thr].regs[reg];
-        break;
-    case UNW_AARCH64_SP:
-        *val = snap->regs[snap->cur_thr].sp;
-        break;
-    case UNW_AARCH64_PC:
-        *val = snap->regs[snap->cur_thr].pc;
-        break;
-    case UNW_AARCH64_PSTATE:
-        *val = snap->regs[snap->cur_thr].pstate;
-        break;
-#elif defined(UNW_TARGET_ARM)
-    case UNW_ARM_R0 ... UNW_ARM_R15:
-        /*
-         * Currently this enum directly maps to the index so this is a no-op.
-         * Assert just in case.
-         */
-        reg -= UNW_ARM_R0;
-        assert(reg >= 0 && reg <= 15);
-        *val = snap->regs[snap->cur_thr].uregs[reg];
-        break;
-#elif defined(UNW_TARGET_X86)
-    case UNW_X86_EAX:
-        *val = snap->regs[snap->cur_thr].eax;
-        break;
-    case UNW_X86_EDX:
-        *val = snap->regs[snap->cur_thr].edx;
-        break;
-    case UNW_X86_ECX:
-        *val = snap->regs[snap->cur_thr].ecx;
-        break;
-    case UNW_X86_EBX:
-        *val = snap->regs[snap->cur_thr].ebx;
-        break;
-    case UNW_X86_ESI:
-        *val = snap->regs[snap->cur_thr].esi;
-        break;
-    case UNW_X86_EDI:
-        *val = snap->regs[snap->cur_thr].edi;
-        break;
-    case UNW_X86_EBP:
-        *val = snap->regs[snap->cur_thr].ebp;
-        break;
-    case UNW_X86_ESP:
-        *val = snap->regs[snap->cur_thr].esp;
-        break;
-    case UNW_X86_EIP:
-        *val = snap->regs[snap->cur_thr].eip;
-        break;
-#elif defined(UNW_TARGET_X86_64)
-    case UNW_X86_64_RAX:
-        *val = snap->regs[snap->cur_thr].rax;
-        break;
-    case UNW_X86_64_RDX:
-        *val = snap->regs[snap->cur_thr].rdx;
-        break;
-    case UNW_X86_64_RCX:
-        *val = snap->regs[snap->cur_thr].rcx;
-        break;
-    case UNW_X86_64_RBX:
-        *val = snap->regs[snap->cur_thr].rbx;
-        break;
-    case UNW_X86_64_RSI:
-        *val = snap->regs[snap->cur_thr].rsi;
-        break;
-    case UNW_X86_64_RDI:
-        *val = snap->regs[snap->cur_thr].rdi;
-        break;
-    case UNW_X86_64_RBP:
-        *val = snap->regs[snap->cur_thr].rbp;
-        break;
-    case UNW_X86_64_RSP:
-        *val = snap->regs[snap->cur_thr].rsp;
-        break;
-    case UNW_X86_64_R8:
-        *val = snap->regs[snap->cur_thr].r8;
-        break;
-    case UNW_X86_64_R9:
-        *val = snap->regs[snap->cur_thr].r9;
-        break;
-    case UNW_X86_64_R10:
-        *val = snap->regs[snap->cur_thr].r10;
-        break;
-    case UNW_X86_64_R11:
-        *val = snap->regs[snap->cur_thr].r11;
-        break;
-    case UNW_X86_64_R12:
-        *val = snap->regs[snap->cur_thr].r12;
-        break;
-    case UNW_X86_64_R13:
-        *val = snap->regs[snap->cur_thr].r13;
-        break;
-    case UNW_X86_64_R14:
-        *val = snap->regs[snap->cur_thr].r14;
-        break;
-    case UNW_X86_64_R15:
-        *val = snap->regs[snap->cur_thr].r15;
-        break;
-    case UNW_X86_64_RIP:
-        *val = snap->regs[snap->cur_thr].rip;
-        break;
-#else
-#error Need porting to this arch
-#endif
-    default:
-        return -UNW_EBADREG;
-    }
+       if (write) {
+               fprintf(debug, "requested to write into register\n");
+               return -UNW_EINVAL;
+       }
 
-    return 0;
+       *val = _get_register_value(reg);
+       return 0;
+}
+
+/*
+ * __cxa_demangle() is taken from libstdc++, however there is no header that we
+ * can take a declaration from. Importing through 'extern' allows using it.
+ */
+/// @cond false
+extern char *__cxa_demangle(const char *mangled_name, char *output_buffer,
+               size_t *length, int *status);
+///@endcond
+
+/**
+ * @brief Checks if symbol starts with '_Z' prefix
+ *
+ * @param symbol string to compare
+ */
+static int is_symbol_demanglable(const char *symbol)
+{
+       return symbol != 0 && (strlen(symbol) >= 2) &&
+               symbol[0] == '_' && symbol[1] == 'Z';
+}
+
+/**
+ * @brief Replaces symbols with demangled
+ *
+ * @param proc_info gathered call stack element
+ */
+static void demangle_symbol(char **symbol)
+{
+       int status = -1;
+       char *demangled_symbol = NULL;
+       if (!is_symbol_demanglable(*symbol))
+               return;
+       demangled_symbol = __cxa_demangle(*symbol, NULL, NULL, &status);
+       if (status == 0) {
+               free(*symbol);
+               *symbol = demangled_symbol;
+       }
+       return;
+}
+
+/**
+ * @brief Find the name of the module and the offset for the address
+ *
+ * @param addr the address of the code to find the module for
+ * @param bufp the output buffer for the module name
+ * @param buf_len the size of the buffer
+ * @param offp output the offset of the code inside the module
+ *
+ * @return zero on success
+ */
+int get_mod_name(unw_word_t addr, char *bufp,
+                size_t buf_len, unw_word_t *offp)
+{
+       struct mem_region *region;
+
+       region = mem_map_get_file_region(map, (void *)addr);
+       if (region == NULL || region->path == NULL || region->path[0] == '\0')
+               return -1;
+
+       strncpy(bufp, region->path, buf_len);
+       bufp[buf_len - 1] = '\0';
+       *offp = addr - (uintptr_t)region->start;
+       return 0;
 }
 
 /*
@@ -786,7 +732,8 @@ static int access_fpreg(unw_addr_space_t as, unw_regnum_t regnum,
     (void) write;
     (void) arg;
 
-    fprintf(stderr, "access_fpreg is not supported\n");
+    fprintf(debug, "access_fpreg is not supported\n");
+    fflush(debug);
     return -UNW_ENOINFO;
 }
 
@@ -799,7 +746,8 @@ static int resume(unw_addr_space_t as, unw_cursor_t *cp, void *arg)
     (void) cp;
     (void) arg;
 
-    fprintf(stderr, "resume is not supported\n");
+    fprintf(debug, "resume is not supported\n");
+    fflush(debug);
     return -UNW_ENOINFO;
 }
 
@@ -809,16 +757,16 @@ static int resume(unw_addr_space_t as, unw_cursor_t *cp, void *arg)
 static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp,
         size_t buf_len, unw_word_t *offp, void *arg)
 {
-    struct snapshot *snap = arg;
     struct mem_region *region;
     char *name = NULL;
 
     (void) as;
+    (void) arg;
 
     if (addr == 0)
         return -UNW_ENOINFO;
 
-    if ((region = mem_map_get_file_region(snap->map, (void *)addr)) == NULL)
+    if ((region = mem_map_get_file_region(map, (void *)addr)) == NULL)
         return -UNW_ENOINFO;
 
     if (region->fd < 0 && region->type == MEM_REGION_TYPE_DELETED) {
@@ -838,6 +786,7 @@ static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp,
 
         name = proc_name(region->fd, elf_image, elf_length,
                 (uint64_t)(uintptr_t)region->start, region->offset, addr, offp);
+        demangle_symbol(&name);
     }
 
     if (name == NULL) {
@@ -845,11 +794,10 @@ static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp,
          * if name cannot be resolved, print binary file name or region type
          */
         if (region->type == MEM_REGION_TYPE_MMAP) {
-            const char *base = basename(region->path);
-            snprintf(bufp, buf_len, "?? (%s)", base);
+           return -UNW_ENOINFO;
         } else {
             snprintf(bufp, buf_len, "?? [%s]",
-                    str_mem_region_type(region->type));
+                 str_mem_region_type(region->type));
         }
         *offp = 0;
         return 0;
@@ -864,7 +812,7 @@ static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp,
 /*
  * libunwind remote callbacks
  */
-unw_accessors_t snapshot_addr_space_accessors = {
+static unw_accessors_t snapshot_addr_space_accessors = {
     .find_proc_info = find_proc_info,
     .put_unwind_info = put_unwind_info,
     .get_dyn_info_list_addr = get_dyn_info_list_addr,
@@ -874,3 +822,98 @@ unw_accessors_t snapshot_addr_space_accessors = {
     .resume = resume,
     .get_proc_name = get_proc_name,
 };
+
+unw_accessors_t *_TB_accessors() {
+       return &snapshot_addr_space_accessors;
+}
+
+void *_TB_create (pid_t pid) {
+#define STAT_LINE_MAXSIZE 4096
+       int n_frames;
+       struct mem_data_chunk **stacks_cover = NULL;
+       int rc;
+       void *ret = NULL;
+       char *buf = NULL;
+       char *p = NULL;
+       FILE *f = NULL;
+       int i;
+
+       long page;
+       long label;
+
+       if ((page = sysconf(_SC_PAGESIZE)) < 0) {
+               perror("get pagesize");
+               return NULL;
+       }
+       --page;
+
+       map = create_maps(pid);
+
+       buf = malloc(STAT_LINE_MAXSIZE);
+       if (!buf)
+               return NULL;
+
+       debug = stderr;
+
+       snprintf(buf, STAT_LINE_MAXSIZE, "/proc/%d/stat", pid);
+       f = fopen(buf, "r");
+       if (!f)
+               goto out_err;
+
+       if (fgets(buf, STAT_LINE_MAXSIZE, f) == NULL)
+               goto out_err;
+
+       for (i = 0, p = buf; i < 28; i++) {
+               p = strchr(p, ' ');
+               if (!p)
+                       goto out_err;
+               p++;
+       }
+
+       if (sscanf(p, "%lu %lu ", &esp, &eip) != 2)
+               goto out_err;
+
+       ret = (void*)&snapshot_addr_space_accessors;
+
+       label = esp & ~page;
+       mem_map_add_label(map, (void *)label, 1);
+
+       /*
+        * arrange data chunks to copy memory contents. in most cases the chunks
+        * will start from %rsp pointing somewhere in thread's stack
+        * to the end of the stack region
+        */
+       stacks_cover = malloc(sizeof(struct mem_data_chunk*) * 1);
+       if (stacks_cover == NULL) {
+               fprintf(stderr, "error: stacks cover == NULL\n");
+               goto out_err;
+       }
+
+       n_frames = mem_map_build_label_cover(map, stack_size,
+                                            stacks_cover, page + 1);
+
+       /*
+        * copy memory contents
+        */
+       rc = copy_memory(pid, stacks_cover, n_frames);
+
+       if (rc < 0)
+               ret = NULL;
+
+out_err:
+        if (stacks_cover)
+               free(stacks_cover);
+       if (f)
+               fclose(f);
+       if (buf)
+               free(buf);
+       return ret;
+}
+
+void _TB_destroy (void *ptr) {
+       (void) ptr;
+        if (debug)
+               fprintf(debug, "_TB_destroy\n");
+       if (debug && debug != stdout && debug != stderr)
+               fclose(debug);
+}