2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 * Authors: Adrian Szyndela <adrian.s@samsung.com>
17 * Łukasz Stelmach <l.stelmach@samsung.com>
18 * Rafał Pietruch <r.pietruch@samsung.com>
24 * @brief This file contains Main module of call stack unwinding program
26 * Crash-stack is a single purpose program. Its duty is to show call stack
27 * of a crashed program. Crash-stack must be called with proper arguments:
28 * PID of a crashed program.
30 #include "crash-stack.h"
36 #include <linux/prctl.h>
41 #include <sys/prctl.h>
42 #include <sys/ptrace.h>
44 #include <sys/syscall.h>
45 #include <sys/types.h>
50 #include <elfutils/version.h>
51 #include <elfutils/libdwfl.h>
53 #define BUF_SIZE (BUFSIZ)
57 #define STR_ANONY "[anony]"
58 #define STR_ANONY_LEN 8
60 static FILE *outputfile = NULL; ///< global output stream
61 static FILE *errfile = NULL; ///< global error stream
62 static FILE *bufferfile = NULL; ///< buffer file for ordering
65 * @brief definitions for getopt options: identifiers
76 * @brief definitions for getopt options: full specifications
78 const struct option opts[] = {
79 { "pid", required_argument, 0, OPT_PID },
80 { "tid", required_argument, 0, OPT_TID },
81 { "sig", required_argument, 0, OPT_SIGNUM },
82 { "output", required_argument, 0, OPT_OUTPUTFILE },
83 { "erroutput", required_argument, 0, OPT_ERRFILE },
88 * @brief container for information from /proc/PID/maps
95 struct addr_node *next;
98 /* helper functions for reading /proc/PID/maps */
99 static struct addr_node *get_addr_list_from_maps(int fd);
100 static void free_all_nodes(struct addr_node *start);
101 static char *fgets_fd(char *str, int len, int fd);
104 * __cxa_demangle() is taken from libstdc++, however there is no header that we
105 * can take a declaration from. Importing through 'extern' allows using it.
108 extern char *__cxa_demangle(const char *mangled_name, char *output_buffer,
109 size_t *length, int *status);
113 * @brief A callback for dwfl_getmodules().
115 * This callback is called once for every module discovered by dwfl_getmodules().
117 * @param module the dwfl module
118 * @param userdata unused, required by dwfl_getmodules()
119 * @param name name of the module
120 * @param address address of the module
121 * @param arg 4th argument to dwfl_getmodules is passed here
123 static int __module_callback(Dwfl_Module *module, void **userdata,
124 const char *name, Dwarf_Addr address,
130 static void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start)
134 const char *elf_name = proc_info->module_name;
135 Dwarf_Addr address = proc_info->addr;
137 fd = open(elf_name, O_RDONLY);
141 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
151 while ((scn = elf_nextscn(elf, scn)) != NULL && !found) {
153 GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
154 if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) {
155 Elf_Data *sdata = elf_getdata(scn, NULL);
156 unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ?
160 uintptr_t address_offset = address;
161 if (shdr->sh_type == SHT_DYNSYM)
162 address_offset -= mapping_start;
163 for (cnt = 0; cnt < nsyms; ++cnt) {
166 GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx);
167 if (sym != NULL && sym->st_shndx != SHN_UNDEF) {
168 if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) {
169 free(proc_info->name);
170 proc_info->name = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name));
171 proc_info->offset = address_offset - sym->st_value;
184 static int __attachable(pid_t pid, pid_t tid)
186 /* read /proc/<pid>/stat */
191 snprintf(buf, sizeof(buf), "/proc/%d/task/%d/stat", pid, tid);
197 /* check if status is D */
198 if (fscanf(f, "%*d %*s %c", &status) != 1) {
205 return status != 'D';
208 static void __print_proc_file(pid_t pid, pid_t tid, const char *name)
214 snprintf(buf, sizeof(buf), "/proc/%d/task/%d/%s", pid, tid, name);
216 fprintf(outputfile, "%s:\n", buf);
221 fprintf(errfile, "Failed to open %s: %m\n", buf);
225 while ((r = fread(buf, 1, sizeof(buf), f)) > 0)
227 fwrite(buf, r, 1, outputfile);
232 fprintf(outputfile, "\n");
235 static void __print_not_attachable_process_info(pid_t pid, pid_t tid)
237 fprintf(outputfile, "ERROR: can't attach to process %d, thread %d - thread is in uninterruptible sleep state\n", pid, tid);
238 fprintf(outputfile, "Giving some /proc info instead:\n\n");
239 __print_proc_file(pid, tid, "wchan");
240 fprintf(outputfile, "\n");
241 __print_proc_file(pid, tid, "syscall");
242 __print_proc_file(pid, tid, "stack");
246 * @brief Opens libdwfl for using with live process
248 * @param pid pid of the process to attach to
249 * @return Dwfl handle
251 static Dwfl *__open_dwfl_with_pid(pid_t pid, pid_t tid)
256 status = __attachable(pid, tid);
259 fprintf(errfile, "failed to read /proc/%d/task/%d/stat: %m\n", pid, tid);
265 __print_not_attachable_process_info(pid, tid);
269 if (ptrace(PTRACE_SEIZE, tid, NULL, PTRACE_O_TRACEEXIT) != 0) {
270 fprintf(errfile, "PTRACE_SEIZE failed on TID %d: %m\n", tid);
274 ptrace(PTRACE_INTERRUPT, tid, 0, 0);
276 stopped_pid = waitpid(tid, &status, __WALL);
277 if (stopped_pid == -1 || stopped_pid != tid || !WIFSTOPPED(status)) {
278 fprintf(errfile, "waitpid failed: %m, stopped_pid=%d, status=%d\n", stopped_pid, status);
282 static const Dwfl_Callbacks proc_callbacks = {
283 .find_elf = dwfl_linux_proc_find_elf,
284 .find_debuginfo = dwfl_standard_find_debuginfo,
285 .section_address = NULL,
286 .debuginfo_path = NULL
289 Dwfl *dwfl = dwfl_begin(&proc_callbacks);
291 fprintf(errfile, "process %d : Can't start dwfl (%s)\n", tid, dwfl_errmsg(-1));
295 if (dwfl_linux_proc_report(dwfl, tid) < 0) {
296 fprintf(errfile, "process %d : dwfl report failed (%s)\n", tid, dwfl_errmsg(-1));
301 #if _ELFUTILS_PREREQ(0,158)
302 if (dwfl_linux_proc_attach(dwfl, tid, true) < 0) {
303 fprintf(errfile, "process %d : dwfl attach failed (%s)\n", tid, dwfl_errmsg(-1));
312 * @brief Gets registers information for live process
314 * @param pid pid of the live process
315 * @return 0 on success, -1 otherwise
317 static int __get_registers_ptrace(pid_t pid)
320 data.iov_base = _crash_stack_get_memory_for_ptrace_registers(&data.iov_len);
322 if (NULL == data.iov_base) {
323 fprintf(errfile, "Cannot get memory for registers for ptrace (not implemented for this architecture\n");
327 if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &data) != 0) {
328 fprintf(errfile, "PTRACE_GETREGSET failed on PID %d: %m\n", pid);
332 _crash_stack_set_ptrace_registers(data.iov_base);
338 * @brief Print signal number causing dump
340 static void __crash_stack_print_signal(int signo)
342 const char* const signal_table[] = {
343 [SIGHUP]="SIGHUP", [SIGINT]="SIGINT", [SIGQUIT]="SIGQUIT",
344 [SIGILL]="SIGILL", [SIGTRAP]="SIGTRAP", [SIGABRT]="SIGABRT",
345 /* [SIGIOT]="SIGIOT", */ [SIGBUS]="SIGBUS", [SIGFPE]="SIGFPE",
346 [SIGKILL]="SIGKILL", [SIGUSR1]="SIGUSR1", [SIGSEGV]="SIGSEGV",
347 [SIGUSR2]="SIGUSR2", [SIGPIPE]="SIGPIPE", [SIGALRM]="SIGALRM",
348 [SIGTERM]="SIGTERM", [SIGSTKFLT]="SIGSTKFLT", [SIGCHLD]="SIGCHLD",
349 [SIGCONT]="SIGCONT", [SIGSTOP]="SIGSTOP", [SIGTSTP]="SIGTSTP",
350 [SIGTTIN]="SIGTTIN", [SIGTTOU]="SIGTTOU", [SIGURG]="SIGURG",
351 [SIGXCPU]="SIGXCPU", [SIGXFSZ]="SIGXFSZ", [SIGVTALRM]="SIGVTALRM",
352 [SIGPROF]="SIGPROF", [SIGWINCH]="SIGWINCH", [SIGIO]="SIGIO",
353 [SIGPWR]="SIGPWR", [SIGSYS]="SIGSYS", /* [SIGUNUSED]="SIGUNUSED", */
356 if (SIGHUP > signo || signo > SIGSYS) {
357 fprintf(errfile, "Invalid signal number: %d\n", signo);
361 printf("Signal: %d\n"
364 signal_table[signo]);
368 * @brief Resolves procedure and module names using libdwfl
370 * @param proc_info gathered call stack element
371 * @param dwfl dwfl handler
373 static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl)
375 uintptr_t address = proc_info->addr;
376 Dwfl_Module *module = dwfl_addrmodule(dwfl, address);
379 Dwarf_Addr mapping_start = 0;
380 const char *fname = 0;
381 const char *module_name = dwfl_module_info(module, NULL, &mapping_start, NULL, NULL, NULL, &fname, NULL);
383 proc_info->module_offset = address - mapping_start;
385 if (!proc_info->module_name) {
387 proc_info->module_name = strdup(fname);
388 else if (module_name)
389 proc_info->module_name = strdup(module_name);
392 const char *symbol = dwfl_module_addrname(module, address);
394 free(proc_info->name);
395 proc_info->name = strdup(symbol);
397 else if (proc_info->module_name != NULL) {
398 __find_symbol_in_elf(proc_info, mapping_start);
404 * @brief Checks if symbol starts with '_Z' prefix
406 * @param symbol string to compare
408 static int is_symbol_demanglable(const char *symbol)
410 return symbol != 0 && (strlen(symbol) >= 2) &&
411 symbol[0] == '_' && symbol[1] == 'Z';
415 * @brief Replaces symbols with demangled
417 * @param proc_info gathered call stack element
419 static void __demangle_symbols(ProcInfo *proc_info)
422 char *dem_buffer = NULL;
423 char *demangled_symbol = __cxa_demangle(proc_info->name, dem_buffer, NULL, &status);
425 free(proc_info->name);
426 proc_info->name = demangled_symbol;
431 * @brief Resolves procedure and module name
433 * @param proc_info gathered call stack element
434 * @param dwfl dwfl handler
435 * @param notes notes handler, NULL if live process analyzed
437 static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl)
439 __resolve_symbols_from_dwfl(proc_info, dwfl);
441 if (is_symbol_demanglable(proc_info->name))
442 __demangle_symbols(proc_info);
446 * @brief Prints call stack element to the global outputfile.
448 * @param proc_info gathered call stack element
450 static void __print_proc_info(ProcInfo *proc_info)
452 if (proc_info->name) {
453 fprintf(outputfile, "%s ", proc_info->name);
454 if (proc_info->offset >= 0)
455 fprintf(outputfile, "+ 0x%x ", proc_info->offset);
457 if (sizeof(proc_info->addr) > 4)
458 fprintf(outputfile, "(0x%016llx)", (long long)proc_info->addr);
460 fprintf(outputfile, "(0x%08x)", (int32_t)proc_info->addr);
462 if (proc_info->module_name != 0)
463 fprintf(outputfile, " [%s] + 0x%x", proc_info->module_name, proc_info->module_offset);
465 fprintf(outputfile, "\n");
469 * @brief Prints call stack to the global outputfile.
471 * @param callstack gathered call stack database
472 * @param pid PID of the live process
474 static void __print_callstack(Callstack *callstack, pid_t pid)
476 fprintf(outputfile, "\nCallstack Information");
477 fprintf(outputfile, " (PID:%d)", pid);
478 fprintf(outputfile, "\nCall Stack Count: %zu\n", callstack->elems);
481 for (it = 0; it != callstack->elems; ++it) {
482 fprintf(outputfile, "%2zu: ", it);
483 __print_proc_info(&callstack->proc[it]);
485 fprintf(outputfile, "End of Call Stack\n");
488 void callstack_constructor(Callstack *callstack)
491 callstack->elems = 0;
492 for (it = 0; it < (int)sizeof(callstack->proc)/sizeof(callstack->proc[0]); ++it) {
493 callstack->proc[it].offset = -1;
494 callstack->proc[it].name = 0;
495 callstack->proc[it].module_name = 0;
499 void callstack_destructor(Callstack *callstack)
502 for (it = 0; it < callstack->elems; ++it) {
503 free(callstack->proc[it].name);
504 free(callstack->proc[it].module_name);
509 * @brief Print full path of executable file
511 static void __crash_stack_print_exe(FILE* outputfile, pid_t pid)
514 char file_path[PATH_MAX];
515 char cmd_path[PATH_MAX];
517 snprintf(cmd_path, PATH_MAX, "/proc/%d/cmdline", pid);
518 if ((fd = open(cmd_path, O_RDONLY)) < 0)
521 if ((ret = read(fd, file_path, sizeof(file_path))) <= 0) {
525 file_path[ret] = '\0';
527 fprintf(outputfile, "Executable File Path: %s\n", file_path);
532 * @brief Print thread information
534 * @param outputfile File handle for printing report
535 * @param pid PID of the inspected process
536 * @param tid TID of the inspected thread
538 static void __crash_stack_print_threads(FILE* outputfile, pid_t pid, pid_t tid)
543 struct dirent *dentry=NULL;
544 char task_path[PATH_MAX];
548 snprintf(task_path, PATH_MAX, "/proc/%d/task", pid);
549 if (stat(task_path, &sb) == -1) {
553 threadnum = sb.st_nlink - 2;
556 fprintf(outputfile, "\nThreads Information\n");
558 "Threads: %d\nPID = %d TID = %d\n",
559 threadnum, pid, tid);
561 dir = opendir(task_path);
563 fprintf(errfile, "[crash-stack] cannot open %s\n", task_path);
565 while (readdir_r(dir, &entry, &dentry) == 0 && dentry) {
566 if (strcmp(dentry->d_name, ".") == 0 ||
567 strcmp(dentry->d_name, "..") == 0)
569 fprintf(outputfile, "%s ", dentry->d_name);
572 fprintf(outputfile, "\n");
579 * @brief Print information about mapped memory regions
581 * @param outputfile File handle for printing report.
582 * @param pid PID of the inspected process
584 static void __crash_stack_print_maps(FILE* outputfile, pid_t pid)
586 char file_path[PATH_MAX];
587 struct addr_node *head = NULL;
588 struct addr_node *t_node;
591 snprintf(file_path, PATH_MAX, "/proc/%d/maps", pid);
593 if ((fd = open(file_path, O_RDONLY)) < 0) {
594 fprintf(errfile, "[crash-stack] cannot open %s\n", file_path);
596 /* parsing the maps to get code segment address*/
597 head = get_addr_list_from_maps(fd);
605 fprintf(outputfile, "\nMaps Information\n");
607 if (!strncmp(STR_ANONY, t_node->fpath, STR_ANONY_LEN)) {
608 t_node = t_node->next;
610 fprintf(outputfile, "%16lx %16lx %s %s\n",
611 (unsigned long)t_node->startaddr,
612 (unsigned long)t_node->endaddr,
613 t_node->perm, t_node->fpath);
614 t_node = t_node->next;
617 fprintf(outputfile, "End of Maps Information\n");
618 free_all_nodes(head);
621 static struct addr_node *get_addr_list_from_maps(int fd)
623 int fpath_len, result;
628 char addr[ADDR_LEN * 2 + 2];
629 char linebuf[BUF_SIZE];
630 struct addr_node *head = NULL;
631 struct addr_node *tail = NULL;
632 struct addr_node *t_node = NULL;
634 /* parsing the maps to get executable code address */
635 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
636 memset(path, 0, PATH_MAX);
637 result = sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path);
640 perm[PERM_LEN - 1] = 0;
642 if ((perm[2] == 'x' && path[0] == '/') ||
643 (perm[1] == 'w' && path[0] != '/'))
645 char* addr2 = strchr(addr, '-');
647 /* add addr node to list */
648 saddr = strtoul(addr, NULL, HEXA);
649 /* ffff0000-ffff1000 */
650 eaddr = strtoul(addr2, NULL, HEXA);
651 /* make node and attach to the list */
652 t_node = (struct addr_node *)mmap(0, sizeof(struct addr_node),
653 PROT_READ | PROT_WRITE,
654 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
655 if (t_node == NULL) {
656 fprintf(errfile, "error : mmap\n");
659 memcpy(t_node->perm, perm, PERM_LEN);
660 t_node->startaddr = saddr;
661 t_node->endaddr = eaddr;
662 t_node->fpath = NULL;
663 fpath_len = strlen(path);
665 t_node->fpath = (char *)mmap(0, fpath_len + 1,
666 PROT_READ | PROT_WRITE,
667 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
668 memset(t_node->fpath, 0, fpath_len + 1);
669 memcpy(t_node->fpath, path, fpath_len);
671 t_node->fpath = (char *)mmap(0, STR_ANONY_LEN,
672 PROT_READ | PROT_WRITE,
673 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
674 memset(t_node->fpath, 0, STR_ANONY_LEN);
675 memcpy(t_node->fpath, STR_ANONY, STR_ANONY_LEN);
690 static void free_all_nodes(struct addr_node *start)
692 struct addr_node *t_node, *n_node;
698 n_node = t_node->next;
700 if (t_node->fpath != NULL) {
701 fpath_len = strlen(t_node->fpath);
702 munmap(t_node->fpath, fpath_len + 1);
704 munmap(t_node, sizeof(struct addr_node));
708 n_node = n_node->next;
712 static char *fgets_fd(char *str, int len, int fd)
719 while (--len > 0 && (num = read(fd, &ch, 1) > 0)) {
720 if ((*cs++ = ch) == '\n')
724 return (num == 0 && cs == str) ? NULL : str;
728 * @brief Print process and system memory information
730 * @param outputfile File handle for printing report.
731 * @param pid PID of the inspected process
733 static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid)
735 char infoname[BUF_SIZE];
736 char memsize[BUF_SIZE];
737 char linebuf[BUF_SIZE];
738 char file_path[PATH_MAX];
741 fprintf(outputfile, "\nMemory information\n");
743 if ((fd = open("/proc/meminfo", O_RDONLY)) < 0) {
744 fprintf(errfile, "[crash-stack] cannot open /proc/meminfo\n");
746 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
747 sscanf(linebuf, "%s %s %*s", infoname, memsize);
748 if (strcmp("MemTotal:", infoname) == 0) {
749 fprintf(outputfile, "%s %8s KB\n", infoname, memsize);
750 } else if (strcmp("MemFree:", infoname) == 0) {
751 fprintf(outputfile, "%s %8s KB\n", infoname, memsize);
752 } else if (strcmp("Buffers:", infoname) == 0) {
753 fprintf(outputfile, "%s %8s KB\n", infoname, memsize);
754 } else if (strcmp("Cached:", infoname) == 0) {
755 fprintf(outputfile, "%s %8s KB\n", infoname, memsize);
762 snprintf(file_path, PATH_MAX, "/proc/%d/status", pid);
763 if ((fd = open(file_path, O_RDONLY)) < 0) {
764 fprintf(errfile, "[crash-stack] cannot open %s\n", file_path);
766 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
767 sscanf(linebuf, "%s %s %*s", infoname, memsize);
768 if (strcmp("VmPeak:", infoname) == 0) {
769 fprintf(outputfile, "%s %8s KB\n", infoname,
771 } else if (strcmp("VmSize:", infoname) == 0) {
772 fprintf(outputfile, "%s %8s KB\n", infoname,
774 } else if (strcmp("VmLck:", infoname) == 0) {
775 fprintf(outputfile, "%s %8s KB\n", infoname,
777 } else if (strcmp("VmPin:", infoname) == 0) {
778 fprintf(outputfile, "%s %8s KB\n", infoname,
780 } else if (strcmp("VmHWM:", infoname) == 0) {
781 fprintf(outputfile, "%s %8s KB\n",
783 } else if (strcmp("VmRSS:", infoname) == 0) {
784 fprintf(outputfile, "%s %8s KB\n",
786 } else if (strcmp("VmData:", infoname) == 0) {
787 fprintf(outputfile, "%s %8s KB\n",
789 } else if (strcmp("VmStk:", infoname) == 0) {
790 fprintf(outputfile, "%s %8s KB\n",
792 } else if (strcmp("VmExe:", infoname) == 0) {
793 fprintf(outputfile, "%s %8s KB\n",
795 } else if (strcmp("VmLib:", infoname) == 0) {
796 fprintf(outputfile, "%s %8s KB\n",
798 } else if (strcmp("VmPTE:", infoname) == 0) {
799 fprintf(outputfile, "%s %8s KB\n",
801 } else if (strcmp("VmSwap:", infoname) == 0) {
802 fprintf(outputfile, "%s %8s KB\n",
812 * @brief Print information saved in buffer (bufferfile)
814 * @param bufferfile File handle for reading saved info.
815 * @param outputfile File handle for printing report.
817 static void __print_buffer_info(FILE* bufferfile, FILE *outputfile)
822 if (fseek(bufferfile, 0, SEEK_SET) < 0) {
823 fprintf(errfile, "Failed to fseek\n");
826 while ((cnt = fread(buf, sizeof(char), sizeof(buf), bufferfile)) != 0) {
827 if (cnt != fwrite(buf, sizeof(char), cnt, outputfile))
833 * @brief Check wchan of thread
835 * @param pid PID of the inspected process
836 * @param tid TID of the thread to check
838 static int check_thread_wchan(int pid, int tid)
841 char path[PATH_MAX], buf[100];
843 snprintf(path, PATH_MAX, "/proc/%d/task/%d/wchan", pid, tid);
844 fd = open(path, O_RDONLY);
846 fprintf(errfile, "[crash-stack] cannot open %s\n", path);
849 cnt = read(fd, buf, sizeof(buf));
850 if (cnt == -1 || cnt == sizeof(buf)) {
851 fprintf(errfile, "[crash-stack] read %s error\n", path);
858 if (strncmp("do_coredump", buf, sizeof(buf)) == 0)
865 * @brief Find crashed tid if tid was not offered
867 * @param pid PID of the inspected process
869 static int find_crash_tid(int pid)
875 struct dirent *dentry = NULL;
876 char task_path[PATH_MAX];
879 snprintf(task_path, PATH_MAX, "/proc/%d/task", pid);
880 if (stat(task_path, &sb) == -1) {
884 threadnum = sb.st_nlink - 2;
887 dir = opendir(task_path);
889 fprintf(errfile, "[crash-stack] cannot open %s\n", task_path);
892 while (readdir_r(dir, &entry, &dentry) == 0 && dentry) {
893 if (strcmp(dentry->d_name, ".") == 0 ||
894 strcmp(dentry->d_name, "..") == 0)
896 crash_tid = check_thread_wchan(pid,
897 atoi(dentry->d_name));
909 * @brief Main function.
911 * Main module accepts should be launched with:
913 * crash-stack --pid pid [--tid tid] [--sig sig]
915 * It allows connecting to a live process and displaying its call stack.
916 * It might be also used for connecting to a process from system's core dump handler.
918 int main(int argc, char **argv)
924 char bufferfile_path[20] = "/tmp/crash.XXXXXX";
926 prctl(PR_SET_DUMPABLE, 0);
928 while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) {
937 signo = atoi(optarg);
940 outputfile = fopen(optarg, "w");
943 errfile = fopen(optarg, "w");
948 if (NULL == errfile) errfile = stderr;
949 if (NULL == outputfile) outputfile = stdout;
952 if ((tid = find_crash_tid(pid)) < 0)
956 if (mkstemp(bufferfile_path) < 0) {
957 fprintf(errfile, "Failed to create buffer file.\n");
960 bufferfile = fopen(bufferfile_path, "w+");
961 unlink(bufferfile_path);
965 elf_version(EV_CURRENT);
967 /* First, prepare dwfl and modules */
970 /* Executable File Path */
971 __crash_stack_print_exe(outputfile, pid);
973 /* Signal information */
974 __crash_stack_print_signal(signo);
978 * Memory, thread, map info should be print in advance
979 * because some of them will be lost after ptrace analysis
982 /* Memory information */
983 __crash_stack_print_meminfo(bufferfile, pid);
986 __crash_stack_print_threads(bufferfile, pid, tid);
988 /* Maps information */
989 __crash_stack_print_maps(bufferfile, pid);
992 dwfl = __open_dwfl_with_pid(pid, tid);
995 "Usage: %s [--output file] [--erroutput file] [--pid <pid> [--tid <tid>]]\n",
1003 dwfl_getmodules(dwfl, __module_callback, NULL, 0);
1005 if (-1 == __get_registers_ptrace(tid))
1008 /* Unwind call stack */
1009 Callstack callstack;
1010 callstack_constructor(&callstack);
1012 _create_crash_stack(dwfl, tid, &callstack);
1014 for (it = 0; it != callstack.elems; ++it)
1015 __resolve_symbols(&callstack.proc[it], dwfl);
1017 /* Print registers */
1018 _crash_stack_print_regs(outputfile);
1020 /* Print pre-ptrace info */
1021 __print_buffer_info(bufferfile, outputfile);
1023 /* Print the results */
1024 __print_callstack(&callstack, tid);
1027 callstack_destructor(&callstack);
1028 dwfl_report_end(dwfl, NULL, NULL);