crash-stack: Get executable name from cmdline
[platform/core/system/crash-worker.git] / src / crash-stack / crash-stack.c
index 82be10d..01c4b7f 100644 (file)
@@ -15,6 +15,7 @@
  *
  * Authors: Adrian Szyndela <adrian.s@samsung.com>
  *          Łukasz Stelmach <l.stelmach@samsung.com>
+ *          Rafał Pietruch <r.pietruch@samsung.com>
  */
 #define _GNU_SOURCE 1
 
@@ -24,7 +25,7 @@
  *
  * Crash-stack is a single purpose program. Its duty is to show call stack
  * of a crashed program. Crash-stack must be called with proper arguments:
- * either core dump file name or PID of a crashed program.
+ * PID of a crashed program.
  */
 #include "crash-stack.h"
 #include <dirent.h>
@@ -56,9 +57,9 @@
 #define STR_ANONY "[anony]"
 #define STR_ANONY_LEN 8
 
-static siginfo_t __siginfo;
 static FILE *outputfile = NULL;                ///< global output stream
 static FILE *errfile = NULL;           ///< global error stream
+static FILE *bufferfile = NULL;                ///< buffer file for ordering
 
 /**
  * @brief definitions for getopt options: identifiers
@@ -66,6 +67,7 @@ static FILE *errfile = NULL;          ///< global error stream
 enum {
        OPT_PID,
        OPT_TID,
+       OPT_SIGNUM,
        OPT_OUTPUTFILE,
        OPT_ERRFILE
 };
@@ -76,6 +78,7 @@ enum {
 const struct option opts[] = {
        { "pid", required_argument, 0, OPT_PID },
        { "tid", required_argument, 0, OPT_TID },
+       { "sig", required_argument, 0, OPT_SIGNUM },
        { "output", required_argument, 0, OPT_OUTPUTFILE },
        { "erroutput", required_argument, 0, OPT_ERRFILE },
        { 0, 0, 0, 0 }
@@ -121,116 +124,10 @@ static int __module_callback(Dwfl_Module *module, void **userdata,
                const char *name, Dwarf_Addr address,
                void *arg)
 {
-       if (name != NULL && name[0] == '[') {
-               /* libdwfl couldn't get the module file - we will get it later from notes */
-               Mappings *mappings = arg;
-               if (mappings->elems < MAX_MAPPINGS_NUM) {
-                       size_t elems = mappings->elems;
-                       mappings->tab[elems].m_start = address;
-                       mappings->tab[elems].m_end = 0;
-                       mappings->tab[elems].m_offset = 0;
-                       mappings->tab[elems].m_name = NULL;
-                       mappings->tab[elems].m_fd = -1;
-                       mappings->tab[elems].m_elf = 0;
-                       mappings->elems++;
-               }
-       }
        return DWARF_CB_OK;
 }
 
-/**
- * @brief Reads a value of specified size from core dump file.
- *
- * @param core ELF handler for the core dump file
- * @param from the source address in the ELF file
- * @param size size of the value in bits
- * @param to the address of allocated memory, where the value will be copied
- */
-static void __get_value(Elf *core, const void *from, size_t size, void *to)
-{
-       Elf_Type type = ELF_T_BYTE;
-       switch (size) {
-       case 8: type = ELF_T_BYTE; break;
-       case 16: type = ELF_T_HALF; break;
-       case 32: type = ELF_T_WORD; break;
-       case 64: type = ELF_T_XWORD; break;
-       default:
-                fprintf(errfile, "__get_value for strange size: %llu\n", (unsigned long long)size);
-                break;
-       }
-       Elf_Data out = {
-               .d_buf = to,
-               .d_type = type,
-               .d_version = EV_CURRENT,
-               .d_size = size/8,
-               .d_off = 0,
-               .d_align = 0
-       };
-       Elf_Data in = {
-               .d_buf = (void*)(from),
-               .d_type = out.d_type,
-               .d_version = out.d_version,
-               .d_size = out.d_size,
-               .d_off = 0,
-               .d_align = 0
-       };
-       Elf_Data *data;
-       if (gelf_getclass(core) == ELFCLASS32)
-               data = elf32_xlatetom(&out, &in, elf_getident(core, NULL)[EI_DATA]);
-       else
-               data = elf64_xlatetom(&out, &in, elf_getident(core, NULL)[EI_DATA]);
-       if (data == NULL)
-               fprintf(errfile, "failed to get value from core file\n");
-}
-
-/**
- * @brief gets number of values, page size, address size, values and names from ELF notes
- *
- * @remarks This is very specific for organization of notes part in ELF files
- *
- * @param elf ELF handler - may be core file
- * @param desc address of ELF notes descriptor
- * @param[out] values_cnt a place for number of values
- * @param[out] page_size a place for page size
- * @param[out] addr_size a place for address size
- * @param[out] values a place for address of values
- * @param[out] filenames a place for address of filenames
- */
-static void __parse_note_file(Elf *elf, const char *desc, uint64_t *values_cnt, uint64_t *page_size,
-               size_t *addr_size, const char **values, const char **filenames)
-{
-       *addr_size = gelf_fsize(elf, ELF_T_ADDR, 1, EV_CURRENT);
-       __get_value(elf, desc, *addr_size*8, values_cnt);
-       __get_value(elf, desc + *addr_size, *addr_size*8, page_size);
-       /* First: triplets of <mapping-start> <mapping-end> <offset-in-pages>
-        *     count = values_cnt
-        * Then the names of files.
-        */
-       *values = desc + 2 * *addr_size;
-       *filenames = *values + 3 * *addr_size * *values_cnt;
-}
-
-/**
- * @brief Simple accessor for mapping items in ELF files
- *
- * @remarks This is very specific for organization of notes part in ELF files
- *
- * @param elf ELF handler - may be core file
- * @param addr_size size of addresses in this ELF
- * @param item address of mapping item to get data from
- * @param[out] mapping_start value of the start of the mapping
- * @param[out] mapping_end value of the end of the mapping
- * @param[out] offset_in_pages number of pages of offset in the file
- */
-static void __get_mapping_item(Elf *elf, size_t addr_size, const void *item,
-               uint64_t *mapping_start, uint64_t *mapping_end, uint64_t *offset_in_pages)
-{
-       __get_value(elf, item, addr_size*8, mapping_start);
-       __get_value(elf, item + addr_size, addr_size*8, mapping_end);
-       __get_value(elf, item + 2 * addr_size, addr_size*8, offset_in_pages);
-}
-
-void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start)
+static void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start)
 {
        Elf *elf;
        int fd;
@@ -382,11 +279,6 @@ static Dwfl *__open_dwfl_with_pid(pid_t pid, pid_t tid)
                return NULL;
        }
 
-       if (ptrace(PTRACE_GETSIGINFO, tid, NULL, &__siginfo) != 0) {
-               fprintf(errfile, "ptrace GETSIGINFO failed: %m, pid=%d, tid=%d\n", pid, tid);
-               return NULL;
-       }
-
        static const Dwfl_Callbacks proc_callbacks = {
                .find_elf = dwfl_linux_proc_find_elf,
                .find_debuginfo = dwfl_standard_find_debuginfo,
@@ -443,17 +335,14 @@ static int __get_registers_ptrace(pid_t pid)
 }
 
 /**
- * @brief Get information about the signal that stopped the process
- *
- * @param pid pid of the live process
- * @return 0 on success, -1 otherwise
+ * @brief Print signal number causing dump
  */
-static int __get_signal_ptrace(pid_t pid)
+static void __crash_stack_print_signal(int signo)
 {
        const char* const signal_table[] = {
                [SIGHUP]="SIGHUP", [SIGINT]="SIGINT", [SIGQUIT]="SIGQUIT",
                [SIGILL]="SIGILL", [SIGTRAP]="SIGTRAP", [SIGABRT]="SIGABRT",
-               [SIGIOT]="SIGIOT", [SIGBUS]="SIGBUS", [SIGFPE]="SIGFPE",
+               /* [SIGIOT]="SIGIOT", */ [SIGBUS]="SIGBUS", [SIGFPE]="SIGFPE",
                [SIGKILL]="SIGKILL", [SIGUSR1]="SIGUSR1", [SIGSEGV]="SIGSEGV",
                [SIGUSR2]="SIGUSR2", [SIGPIPE]="SIGPIPE", [SIGALRM]="SIGALRM",
                [SIGTERM]="SIGTERM", [SIGSTKFLT]="SIGSTKFLT", [SIGCHLD]="SIGCHLD",
@@ -461,27 +350,18 @@ static int __get_signal_ptrace(pid_t pid)
                [SIGTTIN]="SIGTTIN", [SIGTTOU]="SIGTTOU", [SIGURG]="SIGURG",
                [SIGXCPU]="SIGXCPU", [SIGXFSZ]="SIGXFSZ", [SIGVTALRM]="SIGVTALRM",
                [SIGPROF]="SIGPROF", [SIGWINCH]="SIGWINCH", [SIGIO]="SIGIO",
-               [SIGPWR]="SIGPWR", [SIGSYS]="SIGSYS", [SIGUNUSED]="SIGUNUSED",
+               [SIGPWR]="SIGPWR", [SIGSYS]="SIGSYS", /* [SIGUNUSED]="SIGUNUSED", */
        };
 
-       printf("Signal: %d\n"
-              "\t(%s)\n"
-              "\tsi_code: %d\n",
-              __siginfo.si_signo,
-              signal_table[__siginfo.si_signo],
-              __siginfo.si_code);
-       switch (__siginfo.si_code) {
-       case SI_TKILL:
-       case SI_USER:
-               printf("\tsignal sent by %s (sent by pid %d, uid %d)",
-                      __siginfo.si_code == SI_TKILL ? "tkill" : "kill",
-                      __siginfo.si_pid, __siginfo.si_uid);
-               break;
-       case SI_KERNEL:
-               printf("\tsignal sent by the kernel\n");
-               break;
+       if (SIGHUP > signo || signo > SIGSYS) {
+               fprintf(errfile, "Invalid signal number: %d\n", signo);
+               return;
        }
-       return 0;
+
+       printf("Signal: %d\n"
+              "      (%s)\n",
+              signo,
+              signal_table[signo]);
 }
 
 /**
@@ -499,6 +379,9 @@ static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl)
                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);
@@ -518,56 +401,6 @@ static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl)
 }
 
 /**
- * @brief Resolves procedure and module names using elfutils
- *
- * @remarks This function is used in case that symbol name is not available by libelf,
- *                     e.g. when old libelf version does not take into account some modules.
- *
- * @param proc_info gathered call stack element
- * @param core ELF handler for the core dump file, NULL if live process analyzed
- * @param notes notes handler, NULL if live process analyzed
- */
-static void __resolve_symbols_from_elf(ProcInfo *proc_info, Elf *core, Elf_Data *notes)
-{
-       GElf_Nhdr nhdr;
-       size_t pos = 0;
-       size_t new_pos = 0;
-       size_t name_pos;
-       size_t desc_pos;
-
-       while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
-               if (nhdr.n_type == NT_FILE) {
-                       uint64_t values_cnt = 0, page_size = 0;
-                       const char *values;
-                       const char *filenames;
-                       size_t addr_size = 0;
-
-                       __parse_note_file(core, notes->d_buf + desc_pos, &values_cnt,
-                                                         &page_size, &addr_size, &values, &filenames);
-
-                       int ii;
-                       for (ii = 0; ii < values_cnt; ii++) {
-                               uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
-                               const char *item = values + 3 * addr_size * ii;
-
-                               __get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end,
-                                                                &offset_in_pages);
-
-                               if (mapping_start <= proc_info->addr && proc_info->addr < mapping_end) {
-                                       free(proc_info->module_name);
-                                       proc_info->module_name = strdup(filenames);
-                                       __find_symbol_in_elf(proc_info, mapping_start);
-                                       return;
-                               }
-
-                               filenames += strlen(filenames)+1;
-                       }
-               }
-               pos = new_pos;
-       }
-}
-
-/**
  * @brief Checks if symbol starts with '_Z' prefix
  *
  * @param symbol string to compare
@@ -599,16 +432,12 @@ static void __demangle_symbols(ProcInfo *proc_info)
  *
  * @param proc_info gathered call stack element
  * @param dwfl dwfl handler
- * @param core ELF handler for the core dump file, NULL if live process analyzed
  * @param notes notes handler, NULL if live process analyzed
  */
-static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl, Elf *core, Elf_Data *notes)
+static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl)
 {
        __resolve_symbols_from_dwfl(proc_info, dwfl);
 
-       if (core != NULL && (!proc_info->module_name || !proc_info->name))
-               __resolve_symbols_from_elf(proc_info, core, notes);
-
        if (is_symbol_demanglable(proc_info->name))
                __demangle_symbols(proc_info);
 }
@@ -631,7 +460,7 @@ static void __print_proc_info(ProcInfo *proc_info)
                fprintf(outputfile, "(0x%08x)", (int32_t)proc_info->addr);
 
        if (proc_info->module_name != 0)
-               fprintf(outputfile, " [%s]", proc_info->module_name);
+               fprintf(outputfile, " [%s] + 0x%x", proc_info->module_name, proc_info->module_offset);
 
        fprintf(outputfile, "\n");
 }
@@ -640,13 +469,12 @@ static void __print_proc_info(ProcInfo *proc_info)
  * @brief Prints call stack to the global outputfile.
  *
  * @param callstack gathered call stack database
- * @param pid PID of the live process, 0 if core dump file analyzed
+ * @param pid PID of the live process
  */
 static void __print_callstack(Callstack *callstack, pid_t pid)
 {
        fprintf(outputfile, "\nCallstack Information");
-       if (pid > 1)
-               fprintf(outputfile, " (PID:%d)", pid);
+       fprintf(outputfile, " (PID:%d)", pid);
        fprintf(outputfile, "\nCall Stack Count: %zu\n", callstack->elems);
 
        size_t it;
@@ -682,14 +510,22 @@ void callstack_destructor(Callstack *callstack)
  */
 static void __crash_stack_print_exe(FILE* outputfile, pid_t pid)
 {
+       int fd, ret;
        char file_path[PATH_MAX];
-       char link_path[PATH_MAX];
+       char cmd_path[PATH_MAX];
 
-       snprintf(link_path, PATH_MAX, "/proc/%d/exe", pid);
-       if (readlink(link_path, file_path, PATH_MAX) == -1) {
+       snprintf(cmd_path, PATH_MAX, "/proc/%d/cmdline", pid);
+       if ((fd = open(cmd_path, O_RDONLY)) < 0)
+               return;
+
+       if ((ret = read(fd, file_path, sizeof(file_path))) <= 0) {
+               close(fd);
                return;
        }
+       file_path[ret] = '\0';
+
        fprintf(outputfile, "Executable File Path: %s\n", file_path);
+       close(fd);
 }
 
 /**
@@ -771,7 +607,7 @@ static void __crash_stack_print_maps(FILE* outputfile, pid_t pid)
                if (!strncmp(STR_ANONY, t_node->fpath, STR_ANONY_LEN)) {
                        t_node = t_node->next;
                } else {
-                       printf( "%16lx %16lx %s %s\n",
+                       fprintf(outputfile, "%16lx %16lx %s %s\n",
                                (unsigned long)t_node->startaddr,
                                (unsigned long)t_node->endaddr,
                                t_node->perm, t_node->fpath);
@@ -902,7 +738,7 @@ static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid)
        char file_path[PATH_MAX];
        int fd;
 
-       printf("\nMemory information\n");
+       fprintf(outputfile, "\nMemory information\n");
 
         if ((fd = open("/proc/meminfo", O_RDONLY)) < 0) {
                 fprintf(errfile, "[crash-stack] cannot open /proc/meminfo\n");
@@ -910,13 +746,13 @@ static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid)
                 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
                         sscanf(linebuf, "%s %s %*s", infoname, memsize);
                         if (strcmp("MemTotal:", infoname) == 0) {
-                                printf("%s %8s KB\n", infoname, memsize);
+                                fprintf(outputfile, "%s %8s KB\n", infoname, memsize);
                         } else if (strcmp("MemFree:", infoname) == 0) {
-                                printf("%s  %8s KB\n", infoname, memsize);
+                                fprintf(outputfile, "%s  %8s KB\n", infoname, memsize);
                         } else if (strcmp("Buffers:", infoname) == 0) {
-                                printf("%s  %8s KB\n", infoname, memsize);
+                                fprintf(outputfile, "%s  %8s KB\n", infoname, memsize);
                         } else if (strcmp("Cached:", infoname) == 0) {
-                                printf("%s   %8s KB\n", infoname, memsize);
+                                fprintf(outputfile, "%s   %8s KB\n", infoname, memsize);
                                 break;
                         }
                 }
@@ -930,40 +766,40 @@ static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid)
                 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
                         sscanf(linebuf, "%s %s %*s", infoname, memsize);
                         if (strcmp("VmPeak:", infoname) == 0) {
-                                printf("%s   %8s KB\n", infoname,
+                                fprintf(outputfile, "%s   %8s KB\n", infoname,
                                                 memsize);
                         } else if (strcmp("VmSize:", infoname) == 0) {
-                                printf("%s   %8s KB\n", infoname,
+                                fprintf(outputfile, "%s   %8s KB\n", infoname,
                                                 memsize);
                         } else if (strcmp("VmLck:", infoname) == 0) {
-                                printf("%s    %8s KB\n", infoname,
+                                fprintf(outputfile, "%s    %8s KB\n", infoname,
                                                 memsize);
                         } else if (strcmp("VmPin:", infoname) == 0) {
-                                printf("%s    %8s KB\n", infoname,
+                                fprintf(outputfile, "%s    %8s KB\n", infoname,
                                                 memsize);
                         } else if (strcmp("VmHWM:", infoname) == 0) {
-                                printf("%s    %8s KB\n",
+                                fprintf(outputfile, "%s    %8s KB\n",
                                                 infoname, memsize);
                         } else if (strcmp("VmRSS:", infoname) == 0) {
-                                printf("%s    %8s KB\n",
+                                fprintf(outputfile, "%s    %8s KB\n",
                                                 infoname, memsize);
                         } else if (strcmp("VmData:", infoname) == 0) {
-                                printf("%s   %8s KB\n",
+                                fprintf(outputfile, "%s   %8s KB\n",
                                                 infoname, memsize);
                         } else if (strcmp("VmStk:", infoname) == 0) {
-                                printf("%s    %8s KB\n",
+                                fprintf(outputfile, "%s    %8s KB\n",
                                                 infoname, memsize);
                         } else if (strcmp("VmExe:", infoname) == 0) {
-                                printf("%s    %8s KB\n",
+                                fprintf(outputfile, "%s    %8s KB\n",
                                                 infoname, memsize);
                         } else if (strcmp("VmLib:", infoname) == 0) {
-                                printf("%s    %8s KB\n",
+                                fprintf(outputfile, "%s    %8s KB\n",
                                                 infoname, memsize);
                         } else if (strcmp("VmPTE:", infoname) == 0) {
-                                printf("%s    %8s KB\n",
+                                fprintf(outputfile, "%s    %8s KB\n",
                                                 infoname, memsize);
                         } else if (strcmp("VmSwap:", infoname) == 0) {
-                                printf("%s   %8s KB\n",
+                                fprintf(outputfile, "%s   %8s KB\n",
                                                 infoname, memsize);
                                 break;
                         }
@@ -973,22 +809,119 @@ static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid)
 }
 
 /**
+ * @brief Print information saved in buffer (bufferfile)
+ *
+ * @param bufferfile File handle for reading saved info.
+ * @param outputfile File handle for printing report.
+ */
+static void __print_buffer_info(FILE* bufferfile, FILE *outputfile)
+{
+       int cnt;
+       char buf[1024];
+
+       if (fseek(bufferfile, 0, SEEK_SET) < 0) {
+               fprintf(errfile, "Failed to fseek\n");
+               return;
+       }
+       while ((cnt = fread(buf, sizeof(char), sizeof(buf), bufferfile)) != 0) {
+               if (cnt != fwrite(buf, sizeof(char), cnt, outputfile))
+                       break;
+       }
+}
+
+/**
+ * @brief Check wchan of thread
+ *
+ * @param pid PID of the inspected process
+ * @param tid TID of the thread to check
+ */
+static int check_thread_wchan(int pid, int tid)
+{
+       int fd, cnt;
+       char path[PATH_MAX], buf[100];
+
+       snprintf(path, PATH_MAX, "/proc/%d/task/%d/wchan", pid, tid);
+       fd = open(path, O_RDONLY);
+       if (fd == -1) {
+               fprintf(errfile, "[crash-stack] cannot open %s\n", path);
+               return -errno;
+       }
+       cnt = read(fd, buf, sizeof(buf));
+       if (cnt == -1 || cnt == sizeof(buf)) {
+               fprintf(errfile, "[crash-stack] read %s error\n", path);
+               close(fd);
+               return -errno;
+       }
+       buf[cnt] = 0;
+       close(fd);
+
+       if (strncmp("do_coredump", buf, sizeof(buf)) == 0)
+               return tid;
+       else
+               return 0;
+}
+
+/**
+ * @brief Find crashed tid if tid was not offered
+ *
+ * @param pid PID of the inspected process
+ */
+static int find_crash_tid(int pid)
+{
+       int threadnum = 1;
+       int crash_tid = -1;
+       DIR *dir;
+       struct dirent entry;
+       struct dirent *dentry = NULL;
+       char task_path[PATH_MAX];
+       struct stat sb;
+
+       snprintf(task_path, PATH_MAX, "/proc/%d/task", pid);
+       if (stat(task_path, &sb) == -1) {
+               return -1;
+       }
+
+       threadnum = sb.st_nlink - 2;
+
+       if (threadnum > 1) {
+               dir = opendir(task_path);
+               if (!dir) {
+                       fprintf(errfile, "[crash-stack] cannot open %s\n", task_path);
+                       return -1;
+               } else {
+                       while (readdir_r(dir, &entry, &dentry) == 0 && dentry) {
+                               if (strcmp(dentry->d_name, ".") == 0 ||
+                                   strcmp(dentry->d_name, "..") == 0)
+                                       continue;
+                               crash_tid = check_thread_wchan(pid,
+                                               atoi(dentry->d_name));
+                               if (crash_tid > 0)
+                                       break;
+                       }
+                       closedir(dir);
+                       return crash_tid;
+               }
+       }
+       return -1;
+}
+
+/**
  * @brief Main function.
  *
- * Main module accepts two forms of launching:
+ * Main module accepts should be launched with:
  *
- *     crash-stack core-dump-file
- *     crash-stack --pid pid
+ *     crash-stack --pid pid [--tid tid] [--sig sig]
  *
- * The first form allows user to print call stack of a generated core dump file.
- * The second form allows connecting to a live process and displaying its call stack.
+ * It allows connecting to a live process and displaying its call stack.
  * It might be also used for connecting to a process from system's core dump handler.
  */
 int main(int argc, char **argv)
 {
        int c;
+       int signo = 0;
        pid_t pid = 0;
        pid_t tid = 0;
+       char bufferfile_path[20] = "/tmp/crash.XXXXXX";
 
        prctl(PR_SET_DUMPABLE, 0);
 
@@ -1000,6 +933,9 @@ int main(int argc, char **argv)
                case OPT_TID:
                        tid = atoi(optarg);
                        break;
+               case OPT_SIGNUM:
+                       signo = atoi(optarg);
+                       break;
                case OPT_OUTPUTFILE:
                        outputfile = fopen(optarg, "w");
                        break;
@@ -1012,7 +948,17 @@ int main(int argc, char **argv)
        if (NULL == errfile) errfile = stderr;
        if (NULL == outputfile) outputfile = stdout;
 
-       if (tid == 0) tid = pid;
+       if (tid == 0) {
+               if ((tid = find_crash_tid(pid)) < 0)
+                       tid = pid;
+       }
+
+       if (mkstemp(bufferfile_path) < 0) {
+               fprintf(errfile, "Failed to create buffer file.\n");
+               return errno;
+       }
+       bufferfile = fopen(bufferfile_path, "w+");
+       unlink(bufferfile_path);
 
        argc -= optind;
 
@@ -1021,6 +967,27 @@ int main(int argc, char **argv)
        /* 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);
+
+       /* Threads */
+       __crash_stack_print_threads(bufferfile, pid, tid);
+
+       /* Maps information */
+       __crash_stack_print_maps(bufferfile, pid);
+
        if (pid > 1)
                dwfl = __open_dwfl_with_pid(pid, tid);
        else {
@@ -1033,18 +1000,8 @@ int main(int argc, char **argv)
        if (NULL == dwfl)
                return 1111;
 
-       Mappings mappings;
-       mappings.elems = 0;
+       dwfl_getmodules(dwfl, __module_callback, NULL, 0);
 
-       dwfl_getmodules(dwfl, __module_callback, &mappings, 0);
-       Elf_Data *notes = 0;
-
-       /* Executable File Path */
-       __crash_stack_print_exe(outputfile, pid);
-
-       /* Now, get registers */
-       if (-1 == __get_signal_ptrace(pid))
-               return 4444;
        if (-1 == __get_registers_ptrace(tid))
                return 3333;
 
@@ -1052,22 +1009,16 @@ int main(int argc, char **argv)
        Callstack callstack;
        callstack_constructor(&callstack);
 
-       _create_crash_stack(dwfl, NULL, tid, &mappings, &callstack);
+       _create_crash_stack(dwfl, tid, &callstack);
        size_t it;
        for (it = 0; it != callstack.elems; ++it)
-               __resolve_symbols(&callstack.proc[it], dwfl, NULL, notes);
+               __resolve_symbols(&callstack.proc[it], dwfl);
 
        /* Print registers */
        _crash_stack_print_regs(outputfile);
 
-       /* Memory information */
-       __crash_stack_print_meminfo(outputfile, pid);
-
-       /* Threads */
-       __crash_stack_print_threads(outputfile, pid, tid);
-
-       /* Maps Information */
-       __crash_stack_print_maps(outputfile, pid);
+       /* Print pre-ptrace info */
+       __print_buffer_info(bufferfile, outputfile);
 
        /* Print the results */
        __print_callstack(&callstack, tid);