crash-stack: Get executable name from cmdline
[platform/core/system/crash-worker.git] / src / crash-stack / crash-stack.c
index 71c3114..01c4b7f 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- * Author: Adrian Szyndela <adrian.s@samsung.com>
+ * Authors: Adrian Szyndela <adrian.s@samsung.com>
+ *          Łukasz Stelmach <l.stelmach@samsung.com>
+ *          Rafał Pietruch <r.pietruch@samsung.com>
  */
+#define _GNU_SOURCE 1
+
 /**
  * @file crash-stack.c
  * @brief This file contains Main module of call stack unwinding program
  *
  * 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.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <libelf.h>
-#include <elfutils/libdwfl.h>
-/*
- * In case the program is compiled with core dumps, the license may switch to GPL2.
+ * PID of a crashed program.
  */
-#ifdef WITH_CORE_DUMP
-#include <elfutils/libebl.h>
-#endif
+#include "crash-stack.h"
+#include <dirent.h>
 #include <errno.h>
-#include <sys/stat.h>
 #include <fcntl.h>
-#include <unistd.h>
-#include <sys/prctl.h>
+#include <getopt.h>
+#include <libelf.h>
 #include <linux/prctl.h>
-#include "crash-stack.h"
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <elfutils/version.h>
-#include <getopt.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
 #include <sys/ptrace.h>
-#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
+#include <sys/uio.h>
 #include <sys/wait.h>
+#include <unistd.h>
+
+#include <elfutils/version.h>
+#include <elfutils/libdwfl.h>
+
+#define BUF_SIZE (BUFSIZ)
+#define HEXA 16
+#define PERM_LEN 5
+#define ADDR_LEN 16
+#define STR_ANONY "[anony]"
+#define STR_ANONY_LEN 8
 
 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
  */
 enum {
        OPT_PID,
+       OPT_TID,
+       OPT_SIGNUM,
        OPT_OUTPUTFILE,
        OPT_ERRFILE
 };
@@ -65,11 +77,29 @@ 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 }
 };
 
+/**
+ * @brief container for information from /proc/PID/maps
+ */
+struct addr_node {
+       uintptr_t startaddr;
+       uintptr_t endaddr;
+       char perm[PERM_LEN];
+       char *fpath;
+       struct addr_node *next;
+};
+
+/* helper functions for reading /proc/PID/maps */
+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.
@@ -94,211 +124,122 @@ 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)
+static void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start)
 {
-       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(stderr, "__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");
-}
+       Elf *elf;
+       int fd;
+       const char *elf_name = proc_info->module_name;
+       Dwarf_Addr address = proc_info->addr;
 
-/**
- * @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;
+       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);
 }
 
-/**
- * @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)
+static int __attachable(pid_t pid, pid_t tid)
 {
-       __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);
+       /* 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';
 }
 
-/**
- * @brief Tries to get symbol name from ELF files
- *
- * @remarks This function is used in case that symbol name is not available by libelf,
- *                     e.g. when old libelf version does not take into account some modules.
- *
- * @param core ELF handler for the core dump file
- * @param notes notes descriptor from core file
- * @param address address to get symbol name for
- * @param[out] module_name name of the module of the found symbol. Not touched when
- *             symbol is not found
- * @return name of the symbol or NULL if not found
- */
-static char *__try_symbol_from_elfs(Elf *core, Elf_Data *notes, uintptr_t address,
-               const char **module_name)
+static void __print_proc_file(pid_t pid, pid_t tid, const char *name)
 {
-       GElf_Nhdr nhdr;
-       char *symbol = NULL;
-       size_t pos = 0;
-       size_t new_pos = 0;
-       size_t name_pos;
-       size_t desc_pos;
-
-       while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
-               if (nhdr.n_type == NT_FILE) {
-                       uint64_t values_cnt = 0, page_size = 0;
-                       const char *values;
-                       const char *filenames;
-                       size_t addr_size = 0;
-
-                       __parse_note_file(core, notes->d_buf + desc_pos, &values_cnt,
-                                                         &page_size, &addr_size, &values, &filenames);
-
-                       int ii;
-                       for (ii = 0; ii < values_cnt; ii++) {
-                               uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
-                               const char *item = values + 3 * addr_size * ii;
-
-                               __get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end,
-                                                                &offset_in_pages);
-
-                               if (mapping_start <= address && address < mapping_end) {
-                                       Elf *elf;
-                                       int fd;
-                                       fd = open(filenames, O_RDONLY);
-                                       if (-1 == fd)
-                                               return NULL;
-
-                                       elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
-
-                                       if (NULL == elf) {
-                                               close(fd);
-                                               return NULL;
-                                       }
+       char buf[1024];
+       FILE *f;
+       int r;
 
-                                       Elf_Scn *scn = NULL;
-                                       *module_name = filenames;
-
-                                       while ((scn = elf_nextscn(elf, scn)) != NULL) {
-                                               GElf_Shdr shdr_mem;
-                                               GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
-                                               if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) {
-                                                       Elf_Data *sdata = elf_getdata(scn, NULL);
-                                                       unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ?
-                                                                       sizeof(Elf32_Sym) :
-                                                                       sizeof(Elf64_Sym));
-                                                       unsigned int cnt;
-                                                       uintptr_t address_offset = address;
-                                                       if (shdr->sh_type == SHT_DYNSYM)
-                                                               address_offset -= mapping_start;
-                                                       for (cnt = 0; cnt < nsyms; ++cnt) {
-                                                               GElf_Sym sym_mem;
-                                                               Elf32_Word xndx;
-                                                               GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx);
-                                                               if (sym != NULL && sym->st_shndx != SHN_UNDEF) {
-                                                                       if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) {
-                                                                               symbol = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name));
-                                                                               break;
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       }
+       snprintf(buf, sizeof(buf), "/proc/%d/task/%d/%s", pid, tid, name);
 
-                                       elf_end(elf);
-                                       close(fd);
-                                       return symbol;
-                               }
+       fprintf(outputfile, "%s:\n", buf);
 
-                               filenames += strlen(filenames)+1;
-                       }
-               }
-               pos = new_pos;
+       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);
        }
 
-       return NULL;
+       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");
 }
 
 /**
@@ -307,20 +248,33 @@ static char *__try_symbol_from_elfs(Elf *core, Elf_Data *notes, uintptr_t addres
  * @param pid pid of the process to attach to
  * @return Dwfl handle
  */
-static Dwfl *__open_dwfl_with_pid(pid_t pid)
+static Dwfl *__open_dwfl_with_pid(pid_t pid, pid_t tid)
 {
        int status;
        pid_t stopped_pid;
 
-       if (ptrace(PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACEEXIT) != 0) {
-               fprintf(errfile, "PTRACE_SEIZE failed on PID %d: %m\n", 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, pid, 0, 0);
+       ptrace(PTRACE_INTERRUPT, tid, 0, 0);
 
-       stopped_pid = waitpid(pid, &status, 0);
-       if (stopped_pid == -1 || stopped_pid != pid || !WIFSTOPPED(status)) {
+       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;
        }
@@ -334,66 +288,19 @@ static Dwfl *__open_dwfl_with_pid(pid_t pid)
 
        Dwfl *dwfl = dwfl_begin(&proc_callbacks);
        if (dwfl == NULL) {
-               fprintf(errfile, "process %d : Can't start dwfl (%s)\n", pid, dwfl_errmsg(-1));
+               fprintf(errfile, "process %d : Can't start dwfl (%s)\n", tid, dwfl_errmsg(-1));
                return NULL;
        }
 
-       if (dwfl_linux_proc_report(dwfl, pid) < 0) {
-               fprintf(errfile, "process %d : dwfl report failed (%s)\n", pid, dwfl_errmsg(-1));
+       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, pid, true) < 0) {
-               fprintf(errfile, "process %d : dwfl attach failed (%s)\n", pid, dwfl_errmsg(-1));
-               dwfl_end(dwfl);
-               return NULL;
-       }
-#endif
-       return dwfl;
-}
-
-/**
- * @brief Opens libdwfl for using with core dump file
- *
- * @remarks This function will open core file regardless of WITH_CORE_DUMP setting.
- *          It may help with detecting issues with using dwfl even without support
- *          for dumps.
- *
- * @param core elf handler for the core dump file
- * @param core_file_name name of the core file; needed only for diagnostics
- * @return Dwfl handle
- */
-static Dwfl *__open_dwfl_with_core(Elf *core, const char *core_file_name)
-{
-       static const Dwfl_Callbacks core_callbacks = {
-               .find_elf = dwfl_build_id_find_elf,
-               .find_debuginfo = dwfl_standard_find_debuginfo,
-               .section_address = NULL,
-               .debuginfo_path = NULL
-       };
-
-       Dwfl *dwfl = dwfl_begin(&core_callbacks);
-       if (dwfl == NULL) {
-               fprintf(errfile, "%s : Can't start dwfl (%s)\n", core_file_name, dwfl_errmsg(-1));
-               return NULL;
-       }
-
-#if _ELFUTILS_PREREQ(0,158)
-       if (dwfl_core_file_report(dwfl, core, NULL) < 0)
-#else
-               if (dwfl_core_file_report(dwfl, core) < 0)
-#endif
-               {
-                       fprintf(errfile, "%s : dwfl report failed (%s)\n", core_file_name, dwfl_errmsg(-1));
-                       dwfl_end(dwfl);
-                       return NULL;
-               }
-
-#if _ELFUTILS_PREREQ(0,158)
-       if (dwfl_core_file_attach(dwfl, core) < 0) {
-               fprintf(errfile, "%s : dwfl attach failed (%s)\n", core_file_name, dwfl_errmsg(-1));
+       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;
        }
@@ -427,238 +334,594 @@ static int __get_registers_ptrace(pid_t pid)
        return 0;
 }
 
-#ifdef WITH_CORE_DUMP
 /**
- * @brief Helper function for updating mappings.
- *
- * @remarks Old versions of libelf not always extract full information about modules.
- *          For such cases we maintain mappings for every module. Those mappings
- *          may be updated while reading notes from core file.
+ * @brief Print signal number causing dump
+ */
+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",
+               [SIGKILL]="SIGKILL", [SIGUSR1]="SIGUSR1", [SIGSEGV]="SIGSEGV",
+               [SIGUSR2]="SIGUSR2", [SIGPIPE]="SIGPIPE", [SIGALRM]="SIGALRM",
+               [SIGTERM]="SIGTERM", [SIGSTKFLT]="SIGSTKFLT", [SIGCHLD]="SIGCHLD",
+               [SIGCONT]="SIGCONT", [SIGSTOP]="SIGSTOP", [SIGTSTP]="SIGTSTP",
+               [SIGTTIN]="SIGTTIN", [SIGTTOU]="SIGTTOU", [SIGURG]="SIGURG",
+               [SIGXCPU]="SIGXCPU", [SIGXFSZ]="SIGXFSZ", [SIGVTALRM]="SIGVTALRM",
+               [SIGPROF]="SIGPROF", [SIGWINCH]="SIGWINCH", [SIGIO]="SIGIO",
+               [SIGPWR]="SIGPWR", [SIGSYS]="SIGSYS", /* [SIGUNUSED]="SIGUNUSED", */
+       };
+
+       if (SIGHUP > signo || signo > SIGSYS) {
+               fprintf(errfile, "Invalid signal number: %d\n", signo);
+               return;
+       }
+
+       printf("Signal: %d\n"
+              "      (%s)\n",
+              signo,
+              signal_table[signo]);
+}
+
+/**
+ * @brief Resolves procedure and module names using libdwfl
  *
- * @param mappings mappings database
- * @param mapping_start address of the mapped start of the module; module is identified
- *                      by mapping_start
- * @param mapping_end address of the end of the module; needed to compute module boundaries
- * @param offset offset within core file - unused
- * @param name file name of the module
+ * @param proc_info gathered call stack element
+ * @param dwfl dwfl handler
  */
-static void __updateMapping(Mappings *mappings, uint64_t mapping_start, uint64_t mapping_end,
-               uint64_t offset, const char *name)
+static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl)
 {
-       int i;
-       for (i = 0; i < mappings->elems; i++) {
-               if (mappings->tab[i].m_start == mapping_start) {
-                       mappings->tab[i].m_end = mapping_end;
-                       mappings->tab[i].m_name = name;
-                       mappings->tab[i].m_offset = offset;
-                       mappings->tab[i].m_fd = open(name, O_RDONLY);
-                       mappings->tab[i].m_elf = elf_begin(mappings->tab[i].m_fd, ELF_C_READ_MMAP, NULL);
-                       return;
+       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);
                }
        }
 }
-#endif
 
 /**
- * @brief Gets registers from core dump
+ * @brief Checks if symbol starts with '_Z' prefix
  *
- * @param core ELF handler for the core dump file
- * @param core_file_name name of the core file; needed only for diagnostics
- * @param mappings mappings database
- * @return notes handler, NULL on error
+ * @param symbol string to compare
  */
-static Elf_Data *__get_registers_core(Elf *core, const char *core_file_name, Mappings *mappings)
+static int is_symbol_demanglable(const char *symbol)
 {
-       Elf_Data *notes = NULL;
-       /* The part below uses libebl. In case WITH_CORE_DUMP is enabled, the license
-        * may switch to GPL2.
-        */
-#ifdef WITH_CORE_DUMP
-       GElf_Phdr mem;
-       GElf_Phdr *phdr = gelf_getphdr(core, 0, &mem);
+       return symbol != 0 && (strlen(symbol) >= 2) &&
+               symbol[0] == '_' && symbol[1] == 'Z';
+}
 
-       if (phdr == NULL || phdr->p_type != PT_NOTE) {
-               fprintf(errfile, "%s : Missing note section at the first position in core file\n",
-                               core_file_name);
-               return NULL;
+/**
+ * @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;
        }
+}
 
-       notes = elf_getdata_rawchunk(core, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR);
-       if (notes == NULL) {
-               fprintf(errfile, "%s : error getting notes (%s)\n", core_file_name, dwfl_errmsg(-1));
-               return NULL;
+/**
+ * @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
+ */
+static void __print_proc_info(ProcInfo *proc_info)
+{
+       if (proc_info->name) {
+               fprintf(outputfile, "%s ", proc_info->name);
+               if (proc_info->offset >= 0)
+                       fprintf(outputfile, "+ 0x%x ", proc_info->offset);
        }
+       if (sizeof(proc_info->addr) > 4)
+               fprintf(outputfile, "(0x%016llx)", (long long)proc_info->addr);
+       else
+               fprintf(outputfile, "(0x%08x)", (int32_t)proc_info->addr);
 
-       Ebl *ebl = ebl_openbackend(core);
-       if (ebl == NULL) {
-               fprintf(errfile, "%s : Can't initialize ebl\n", core_file_name);
-               return NULL;
+       if (proc_info->module_name != 0)
+               fprintf(outputfile, " [%s] + 0x%x", proc_info->module_name, proc_info->module_offset);
+
+       fprintf(outputfile, "\n");
+}
+
+/**
+ * @brief Prints call stack to the global outputfile.
+ *
+ * @param callstack gathered call stack database
+ * @param pid PID of the live process
+ */
+static void __print_callstack(Callstack *callstack, pid_t pid)
+{
+       fprintf(outputfile, "\nCallstack Information");
+       fprintf(outputfile, " (PID:%d)", pid);
+       fprintf(outputfile, "\nCall Stack Count: %zu\n", callstack->elems);
+
+       size_t it;
+       for (it = 0; it != callstack->elems; ++it) {
+               fprintf(outputfile, "%2zu: ", it);
+               __print_proc_info(&callstack->proc[it]);
        }
+       fprintf(outputfile, "End of Call Stack\n");
+}
 
-       GElf_Nhdr nhdr;
-       size_t name_pos;
-       size_t desc_pos;
-       size_t pos = 0;
-       size_t new_pos = 0;
-       int got_regs = 0;
-       /* registers should be in the first note! */
-       while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
-               if (nhdr.n_type == NT_PRSTATUS && !got_regs) {
-                       GElf_Word regs_offset;
-                       size_t nregloc;
-                       const Ebl_Register_Location *reglocs;
-                       size_t nitems;
-                       const Ebl_Core_Item *items;
-
-                       got_regs = 1;
-
-                       if (0 == ebl_core_note(ebl, &nhdr, "CORE", &regs_offset, &nregloc,
-                                               &reglocs, &nitems, &items)) {
-                               fprintf(errfile,
-                                               "%s : error parsing notes (built with different build of libebl?)\n",
-                                               core_file_name);
-                               return NULL;
+void callstack_constructor(Callstack *callstack)
+{
+       size_t it;
+       callstack->elems = 0;
+       for (it = 0; it < (int)sizeof(callstack->proc)/sizeof(callstack->proc[0]); ++it) {
+               callstack->proc[it].offset = -1;
+               callstack->proc[it].name = 0;
+               callstack->proc[it].module_name = 0;
+       }
+}
+
+void callstack_destructor(Callstack *callstack)
+{
+       size_t it;
+       for (it = 0; it < callstack->elems; ++it) {
+               free(callstack->proc[it].name);
+               free(callstack->proc[it].module_name);
+       }
+}
+
+/**
+ * @brief Print full path of executable file
+ */
+static void __crash_stack_print_exe(FILE* outputfile, pid_t pid)
+{
+       int fd, ret;
+       char file_path[PATH_MAX];
+       char cmd_path[PATH_MAX];
+
+       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);
+}
+
+/**
+ * @brief Print thread information
+ *
+ * @param outputfile File handle for printing report
+ * @param pid PID of the inspected process
+ * @param tid TID of the inspected thread
+ */
+static void __crash_stack_print_threads(FILE* outputfile, pid_t pid, pid_t tid)
+{
+       int threadnum=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;
+       }
+
+       threadnum = sb.st_nlink - 2;
+
+       if (threadnum > 1) {
+               fprintf(outputfile, "\nThreads Information\n");
+               fprintf(outputfile,
+                       "Threads: %d\nPID = %d TID = %d\n",
+                       threadnum, pid, tid);
+               /* print thread */
+               dir = opendir(task_path);
+               if (!dir) {
+                       fprintf(errfile, "[crash-stack] cannot open %s\n", task_path);
+               } else {
+                       while (readdir_r(dir, &entry, &dentry) == 0 && dentry) {
+                               if (strcmp(dentry->d_name, ".") == 0 ||
+                                   strcmp(dentry->d_name, "..") == 0)
+                                       continue;
+                               fprintf(outputfile, "%s ", dentry->d_name);
                        }
+                       closedir(dir);
+                       fprintf(outputfile, "\n");
+               }
+       }
 
-                       const char *regs_location = (const char *)(notes->d_buf) + pos + desc_pos
-                               + regs_offset;
-                       unsigned i;
-
-                       for (i = 0; i < nregloc; i++) {
-                               const char *register_location = regs_location + reglocs[i].offset;
-                               int regnum;
-                               for (regnum = reglocs[i].regno;
-                                               regnum < reglocs[i].regno + reglocs[i].count;
-                                               regnum++) {
-                                       char regname[5];
-                                       int bits, type;
-                                       const char *prefix = 0;
-                                       const char *setname = 0;
-
-                                       ssize_t ret = ebl_register_info(ebl, regnum, regname,
-                                                       sizeof(regname), &prefix, &setname,
-                                                       &bits, &type);
-                                       if (ret < 0) {
-                                               fprintf(errfile, "%s : can't get register info\n", core_file_name);
-                                               return NULL;
-                                       }
-                                       void *place_for_reg_value = _get_place_for_register_value(regname, regnum);
+}
 
-                                       if (place_for_reg_value != NULL)
-                                               __get_value(core, register_location, bits, place_for_reg_value);
+/**
+ * @brief Print information about mapped memory regions
+ *
+ * @param outputfile File handle for printing report.
+ * @param pid PID of the inspected process
+ */
+static void __crash_stack_print_maps(FILE* outputfile, pid_t pid)
+{
+       char file_path[PATH_MAX];
+       struct addr_node *head = NULL;
+       struct addr_node *t_node;
+       int fd;
+
+       snprintf(file_path, PATH_MAX, "/proc/%d/maps", pid);
+
+       if ((fd = open(file_path, O_RDONLY)) < 0) {
+               fprintf(errfile, "[crash-stack] cannot open %s\n", file_path);
+        } else {
+                /* parsing the maps to get code segment address*/
+                head = get_addr_list_from_maps(fd);
+                close(fd);
+        }
+       if (head == NULL) {
+               return;
+       }
 
-                                       register_location += bits / 8 + reglocs[i].pad;
-                               }
+       t_node = head;
+       fprintf(outputfile, "\nMaps Information\n");
+       while (t_node) {
+               if (!strncmp(STR_ANONY, t_node->fpath, STR_ANONY_LEN)) {
+                       t_node = t_node->next;
+               } else {
+                       fprintf(outputfile, "%16lx %16lx %s %s\n",
+                               (unsigned long)t_node->startaddr,
+                               (unsigned long)t_node->endaddr,
+                               t_node->perm, t_node->fpath);
+                       t_node = t_node->next;
+               }
+       }
+       fprintf(outputfile, "End of Maps Information\n");
+       free_all_nodes(head);
+}
+
+static struct addr_node *get_addr_list_from_maps(int fd)
+{
+        int fpath_len, result;
+        uintptr_t saddr;
+        uintptr_t eaddr;
+        char perm[PERM_LEN];
+        char path[PATH_MAX];
+        char addr[ADDR_LEN * 2 + 2];
+        char linebuf[BUF_SIZE];
+        struct addr_node *head = NULL;
+        struct addr_node *tail = NULL;
+        struct addr_node *t_node = NULL;
+
+        /* parsing the maps to get executable code address */
+        while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
+                memset(path, 0, PATH_MAX);
+                result = sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path);
+                if (result < 0)
+                        continue;
+                perm[PERM_LEN - 1] = 0;
+                /* rwxp */
+                if ((perm[2] == 'x' && path[0] == '/') ||
+                   (perm[1] == 'w' && path[0] != '/'))
+               {
+                       char* addr2 = strchr(addr, '-');
+                       *(addr2++) = '\0';
+                       /* add addr node to list */
+                       saddr = strtoul(addr, NULL, HEXA);
+                       /* ffff0000-ffff1000 */
+                       eaddr = strtoul(addr2, NULL, HEXA);
+                       /* make node and attach to the list */
+                       t_node = (struct addr_node *)mmap(0, sizeof(struct addr_node),
+                                                         PROT_READ | PROT_WRITE,
+                                                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+                       if (t_node == NULL) {
+                               fprintf(errfile, "error : mmap\n");
+                               return NULL;
+                       }
+                       memcpy(t_node->perm, perm, PERM_LEN);
+                       t_node->startaddr = saddr;
+                       t_node->endaddr = eaddr;
+                       t_node->fpath = NULL;
+                       fpath_len = strlen(path);
+                       if (fpath_len > 0) {
+                               t_node->fpath = (char *)mmap(0, fpath_len + 1,
+                                                            PROT_READ | PROT_WRITE,
+                                                            MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+                               memset(t_node->fpath, 0, fpath_len + 1);
+                               memcpy(t_node->fpath, path, fpath_len);
+                       } else {
+                               t_node->fpath = (char *)mmap(0, STR_ANONY_LEN,
+                                                            PROT_READ | PROT_WRITE,
+                                                            MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+                               memset(t_node->fpath, 0, STR_ANONY_LEN);
+                               memcpy(t_node->fpath, STR_ANONY, STR_ANONY_LEN);
                        }
-               } else 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;
-                       /* First: triplets of <mapping-start> <mapping-end> <offset-in-pages>
-                        *     count = values_cnt
-                        * Then the names of files.
-                        */
-                       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);
-                               __updateMapping(mappings, mapping_start, mapping_end,
-                                               offset_in_pages*page_size, filenames);
-                               filenames += strlen(filenames)+1;
+                       t_node->next = NULL;
+                       if (head == NULL) {
+                               head = t_node;
+                               tail = t_node;
+                       } else {
+                               tail->next = t_node;
+                               tail = t_node;
                        }
                }
-               pos = new_pos;
        }
-       ebl_closebackend(ebl);
-#else
-       fprintf(errfile, "Configured without support for core dump files\n");
-#endif
-       return notes;
+       return head;
+}
+
+static void free_all_nodes(struct addr_node *start)
+{
+       struct addr_node *t_node, *n_node;
+       int fpath_len;
+
+       if (start == NULL)
+               return;
+       t_node = start;
+       n_node = t_node->next;
+       while (t_node) {
+               if (t_node->fpath != NULL) {
+                       fpath_len = strlen(t_node->fpath);
+                       munmap(t_node->fpath, fpath_len + 1);
+               }
+               munmap(t_node, sizeof(struct addr_node));
+               if (n_node == NULL)
+                       break;
+               t_node = n_node;
+               n_node = n_node->next;
+       }
+}
+
+static char *fgets_fd(char *str, int len, int fd)
+{
+        char ch;
+        register char *cs;
+        int num = 0;
+
+        cs = str;
+        while (--len > 0 && (num = read(fd, &ch, 1) > 0)) {
+                if ((*cs++ = ch) == '\n')
+                        break;
+        }
+        *cs = '\0';
+        return (num == 0 && cs == str) ? NULL : str;
 }
 
 /**
- * @brief Prints call stack to the screen.
+ * @brief Print process and system memory information
  *
- * @param callstack gathered call stack database
- * @param dwfl dwfl handler
- * @param core ELF handler for the core dump file, NULL if live process analyzed
- * @param pid PID of the live process, 0 if core dump file analyzed
- * @param notes notes handler, NULL if live process analyzed
+ * @param outputfile File handle for printing report.
+ * @param pid PID of the inspected process
  */
-static void __print_callstack(Callstack *callstack, Dwfl *dwfl, Elf *core, pid_t pid,
-               Elf_Data *notes)
+static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid)
 {
-       fprintf(outputfile, "Call stack");
-       if (pid > 1) fprintf(outputfile, " for PID %d", pid);
-       fprintf(outputfile, ":\n");
+       char infoname[BUF_SIZE];
+       char memsize[BUF_SIZE];
+       char linebuf[BUF_SIZE];
+       char file_path[PATH_MAX];
+       int fd;
+
+       fprintf(outputfile, "\nMemory information\n");
+
+        if ((fd = open("/proc/meminfo", O_RDONLY)) < 0) {
+                fprintf(errfile, "[crash-stack] cannot open /proc/meminfo\n");
+        } else {
+                while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
+                        sscanf(linebuf, "%s %s %*s", infoname, memsize);
+                        if (strcmp("MemTotal:", infoname) == 0) {
+                                fprintf(outputfile, "%s %8s KB\n", infoname, memsize);
+                        } else if (strcmp("MemFree:", infoname) == 0) {
+                                fprintf(outputfile, "%s  %8s KB\n", infoname, memsize);
+                        } else if (strcmp("Buffers:", infoname) == 0) {
+                                fprintf(outputfile, "%s  %8s KB\n", infoname, memsize);
+                        } else if (strcmp("Cached:", infoname) == 0) {
+                                fprintf(outputfile, "%s   %8s KB\n", infoname, memsize);
+                                break;
+                        }
+                }
+                close(fd);
+        }
+
+       snprintf(file_path, PATH_MAX, "/proc/%d/status", pid);
+        if ((fd = open(file_path, O_RDONLY)) < 0) {
+                fprintf(errfile, "[crash-stack] cannot open %s\n", file_path);
+        } else {
+                while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
+                        sscanf(linebuf, "%s %s %*s", infoname, memsize);
+                        if (strcmp("VmPeak:", infoname) == 0) {
+                                fprintf(outputfile, "%s   %8s KB\n", infoname,
+                                                memsize);
+                        } else if (strcmp("VmSize:", infoname) == 0) {
+                                fprintf(outputfile, "%s   %8s KB\n", infoname,
+                                                memsize);
+                        } else if (strcmp("VmLck:", infoname) == 0) {
+                                fprintf(outputfile, "%s    %8s KB\n", infoname,
+                                                memsize);
+                        } else if (strcmp("VmPin:", infoname) == 0) {
+                                fprintf(outputfile, "%s    %8s KB\n", infoname,
+                                                memsize);
+                        } else if (strcmp("VmHWM:", infoname) == 0) {
+                                fprintf(outputfile, "%s    %8s KB\n",
+                                                infoname, memsize);
+                        } else if (strcmp("VmRSS:", infoname) == 0) {
+                                fprintf(outputfile, "%s    %8s KB\n",
+                                                infoname, memsize);
+                        } else if (strcmp("VmData:", infoname) == 0) {
+                                fprintf(outputfile, "%s   %8s KB\n",
+                                                infoname, memsize);
+                        } else if (strcmp("VmStk:", infoname) == 0) {
+                                fprintf(outputfile, "%s    %8s KB\n",
+                                                infoname, memsize);
+                        } else if (strcmp("VmExe:", infoname) == 0) {
+                                fprintf(outputfile, "%s    %8s KB\n",
+                                                infoname, memsize);
+                        } else if (strcmp("VmLib:", infoname) == 0) {
+                                fprintf(outputfile, "%s    %8s KB\n",
+                                                infoname, memsize);
+                        } else if (strcmp("VmPTE:", infoname) == 0) {
+                                fprintf(outputfile, "%s    %8s KB\n",
+                                                infoname, memsize);
+                        } else if (strcmp("VmSwap:", infoname) == 0) {
+                                fprintf(outputfile, "%s   %8s KB\n",
+                                                infoname, memsize);
+                                break;
+                        }
+                }
+                close(fd);
+        }
+}
 
-       char *dem_buffer = NULL;
-       size_t it;
-       for (it = 0; it != callstack->elems; ++it) {
-               if (sizeof(callstack->tab[0]) > 4)
-                       fprintf(outputfile, "0x%016llx: ", (long long)callstack->tab[it]);
-               else
-                       fprintf(outputfile, "0x%08x: ", (int32_t)callstack->tab[it]);
-               Dwfl_Module *module = dwfl_addrmodule(dwfl, callstack->tab[it]);
-               if (module) {
-                       char *demangled_symbol = 0;
-                       const char *symbol = dwfl_module_addrname(module, callstack->tab[it]);
-                       const char *fname = 0;
-                       const char *module_name = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
-                       char *symbol_from_elf = 0;
-                       if (symbol == NULL)
-                               symbol = symbol_from_elf = __try_symbol_from_elfs(core, notes, callstack->tab[it], &fname);
-                       if (symbol != 0 && symbol[0] == '_' && symbol[1] == 'Z') {
-                               int status = -1;
-
-                               demangled_symbol = __cxa_demangle(symbol, dem_buffer, NULL, &status);
-                               if (status == 0)
-                                       symbol = demangled_symbol;
-                       }
-                       if (symbol != 0)
-                               fprintf(outputfile, "%s()", symbol);
-                       else
-                               fprintf(outputfile, "<unknown>");
+/**
+ * @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 (demangled_symbol != 0)
-                               free(demangled_symbol);
+       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;
+       }
 
-                       if (symbol_from_elf != 0)
-                               free(symbol_from_elf);
+       threadnum = sb.st_nlink - 2;
 
-                       fprintf(outputfile, " from %s\n", fname != NULL ? fname : module_name);
+       if (threadnum > 1) {
+               dir = opendir(task_path);
+               if (!dir) {
+                       fprintf(errfile, "[crash-stack] cannot open %s\n", task_path);
+                       return -1;
                } else {
-                       fprintf(outputfile, "unknown function\n");
+                       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;
-
-       const char *core_file_name;
+       pid_t tid = 0;
+       char bufferfile_path[20] = "/tmp/crash.XXXXXX";
 
        prctl(PR_SET_DUMPABLE, 0);
 
@@ -667,6 +930,12 @@ int main(int argc, char **argv)
                case OPT_PID:
                        pid = atoi(optarg);
                        break;
+               case OPT_TID:
+                       tid = atoi(optarg);
+                       break;
+               case OPT_SIGNUM:
+                       signo = atoi(optarg);
+                       break;
                case OPT_OUTPUTFILE:
                        outputfile = fopen(optarg, "w");
                        break;
@@ -679,73 +948,85 @@ int main(int argc, char **argv)
        if (NULL == errfile) errfile = stderr;
        if (NULL == outputfile) outputfile = stdout;
 
-       core_file_name = argv[optind];
+       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;
 
        elf_version(EV_CURRENT);
 
        /* First, prepare dwfl and modules */
-       Elf *core = NULL;
-       int core_fd = -1;
        Dwfl *dwfl = NULL;
 
-       if (pid > 1)
-               dwfl = __open_dwfl_with_pid(pid);
-       else {
-               if (argc != 1) {
-                       fprintf(errfile,
-                                       "Usage: %s [--output file] [--erroutput file] [--pid <pid> | <core-file>]\n",
-                                       argv[0]);
-                       return 1;
-               }
+       /* Executable File Path */
+       __crash_stack_print_exe(outputfile, pid);
 
-               core_fd = open(core_file_name, O_RDONLY);
-               if (core_fd < 0) {
-                       perror(core_file_name);
-                       return 2;
-               }
+       /* Signal information */
+       __crash_stack_print_signal(signo);
 
-               core = elf_begin(core_fd, ELF_C_READ_MMAP, NULL);
-               if (core == NULL) {
-                       fprintf(errfile, "%s : Can't open ELF (%s)\n", core_file_name, elf_errmsg(-1));
-                       return 3;
-               }
+       /*
+        * 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);
 
-               dwfl = __open_dwfl_with_core(core, core_file_name);
+       /* 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 {
+               fprintf(errfile,
+                               "Usage: %s [--output file] [--erroutput file] [--pid <pid> [--tid <tid>]]\n",
+                               argv[0]);
+               return 1;
        }
 
        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;
-
-       /* Now, get registers */
-       if (pid > 1) {
-               if (-1 == __get_registers_ptrace(pid))
-                       return 3333;
-       } else {
-               notes = __get_registers_core(core, core_file_name, &mappings);
-               if (NULL == notes)
-                       return 2222;
-       }
+       if (-1 == __get_registers_ptrace(tid))
+               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);
+
+       /* Print registers */
+       _crash_stack_print_regs(outputfile);
 
-       _create_crash_stack(dwfl, core, pid, &mappings, &callstack);
+       /* Print pre-ptrace info */
+       __print_buffer_info(bufferfile, outputfile);
 
        /* Print the results */
-       __print_callstack(&callstack, dwfl, core, pid, notes);
+       __print_callstack(&callstack, tid);
 
        /* Clean up */
+       callstack_destructor(&callstack);
        dwfl_report_end(dwfl, NULL, NULL);
        dwfl_end(dwfl);
-       if (NULL != core) elf_end(core);
-       if (-1 != core_fd) close(core_fd);
 
        return 0;
 }