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>
21 * @brief This file contains Main module of call stack unwinding program
23 * Crash-stack is a single purpose program. Its duty is to show call stack
24 * of a crashed program. Crash-stack must be called with proper arguments:
25 * either core dump file name or PID of a crashed program.
30 #include <elfutils/libdwfl.h>
32 * In case the program is compiled with core dumps, the license may switch to GPL2.
35 #include <elfutils/libebl.h>
41 #include <sys/prctl.h>
42 #include <linux/prctl.h>
43 #include "crash-stack.h"
45 #include <elfutils/version.h>
47 #include <sys/ptrace.h>
49 #include <sys/types.h>
52 #include <sys/syscall.h>
54 static siginfo_t __siginfo;
55 static FILE *outputfile = NULL; ///< global output stream
56 static FILE *errfile = NULL; ///< global error stream
59 * @brief definitions for getopt options: identifiers
69 * @brief definitions for getopt options: full specifications
71 const struct option opts[] = {
72 { "pid", required_argument, 0, OPT_PID },
73 { "tid", required_argument, 0, OPT_TID },
74 { "output", required_argument, 0, OPT_OUTPUTFILE },
75 { "erroutput", required_argument, 0, OPT_ERRFILE },
80 * __cxa_demangle() is taken from libstdc++, however there is no header that we
81 * can take a declaration from. Importing through 'extern' allows using it.
84 extern char *__cxa_demangle(const char *mangled_name, char *output_buffer,
85 size_t *length, int *status);
89 * @brief A callback for dwfl_getmodules().
91 * This callback is called once for every module discovered by dwfl_getmodules().
93 * @param module the dwfl module
94 * @param userdata unused, required by dwfl_getmodules()
95 * @param name name of the module
96 * @param address address of the module
97 * @param arg 4th argument to dwfl_getmodules is passed here
99 static int __module_callback(Dwfl_Module *module, void **userdata,
100 const char *name, Dwarf_Addr address,
103 if (name != NULL && name[0] == '[') {
104 /* libdwfl couldn't get the module file - we will get it later from notes */
105 Mappings *mappings = arg;
106 if (mappings->elems < MAX_MAPPINGS_NUM) {
107 size_t elems = mappings->elems;
108 mappings->tab[elems].m_start = address;
109 mappings->tab[elems].m_end = 0;
110 mappings->tab[elems].m_offset = 0;
111 mappings->tab[elems].m_name = NULL;
112 mappings->tab[elems].m_fd = -1;
113 mappings->tab[elems].m_elf = 0;
121 * @brief Reads a value of specified size from core dump file.
123 * @param core ELF handler for the core dump file
124 * @param from the source address in the ELF file
125 * @param size size of the value in bits
126 * @param to the address of allocated memory, where the value will be copied
128 static void __get_value(Elf *core, const void *from, size_t size, void *to)
130 Elf_Type type = ELF_T_BYTE;
132 case 8: type = ELF_T_BYTE; break;
133 case 16: type = ELF_T_HALF; break;
134 case 32: type = ELF_T_WORD; break;
135 case 64: type = ELF_T_XWORD; break;
137 fprintf(stderr, "__get_value for strange size: %llu\n", (unsigned long long)size);
143 .d_version = EV_CURRENT,
149 .d_buf = (void*)(from),
150 .d_type = out.d_type,
151 .d_version = out.d_version,
152 .d_size = out.d_size,
157 if (gelf_getclass(core) == ELFCLASS32)
158 data = elf32_xlatetom(&out, &in, elf_getident(core, NULL)[EI_DATA]);
160 data = elf64_xlatetom(&out, &in, elf_getident(core, NULL)[EI_DATA]);
162 fprintf(errfile, "failed to get value from core file\n");
166 * @brief gets number of values, page size, address size, values and names from ELF notes
168 * @remarks This is very specific for organization of notes part in ELF files
170 * @param elf ELF handler - may be core file
171 * @param desc address of ELF notes descriptor
172 * @param[out] values_cnt a place for number of values
173 * @param[out] page_size a place for page size
174 * @param[out] addr_size a place for address size
175 * @param[out] values a place for address of values
176 * @param[out] filenames a place for address of filenames
178 static void __parse_note_file(Elf *elf, const char *desc, uint64_t *values_cnt, uint64_t *page_size,
179 size_t *addr_size, const char **values, const char **filenames)
181 *addr_size = gelf_fsize(elf, ELF_T_ADDR, 1, EV_CURRENT);
182 __get_value(elf, desc, *addr_size*8, values_cnt);
183 __get_value(elf, desc + *addr_size, *addr_size*8, page_size);
184 /* First: triplets of <mapping-start> <mapping-end> <offset-in-pages>
186 * Then the names of files.
188 *values = desc + 2 * *addr_size;
189 *filenames = *values + 3 * *addr_size * *values_cnt;
193 * @brief Simple accessor for mapping items in ELF files
195 * @remarks This is very specific for organization of notes part in ELF files
197 * @param elf ELF handler - may be core file
198 * @param addr_size size of addresses in this ELF
199 * @param item address of mapping item to get data from
200 * @param[out] mapping_start value of the start of the mapping
201 * @param[out] mapping_end value of the end of the mapping
202 * @param[out] offset_in_pages number of pages of offset in the file
204 static void __get_mapping_item(Elf *elf, size_t addr_size, const void *item,
205 uint64_t *mapping_start, uint64_t *mapping_end, uint64_t *offset_in_pages)
207 __get_value(elf, item, addr_size*8, mapping_start);
208 __get_value(elf, item + addr_size, addr_size*8, mapping_end);
209 __get_value(elf, item + 2 * addr_size, addr_size*8, offset_in_pages);
213 * @brief Tries to get symbol name from ELF files
215 * @remarks This function is used in case that symbol name is not available by libelf,
216 * e.g. when old libelf version does not take into account some modules.
218 * @param core ELF handler for the core dump file
219 * @param notes notes descriptor from core file
220 * @param address address to get symbol name for
221 * @param[out] module_name name of the module of the found symbol. Not touched when
222 * symbol is not found
223 * @return name of the symbol or NULL if not found
225 static char *__try_symbol_from_elfs(Elf *core, Elf_Data *notes, uintptr_t address,
226 const char **module_name)
235 while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
236 if (nhdr.n_type == NT_FILE) {
237 uint64_t values_cnt = 0, page_size = 0;
239 const char *filenames;
240 size_t addr_size = 0;
242 __parse_note_file(core, notes->d_buf + desc_pos, &values_cnt,
243 &page_size, &addr_size, &values, &filenames);
246 for (ii = 0; ii < values_cnt; ii++) {
247 uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
248 const char *item = values + 3 * addr_size * ii;
250 __get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end,
253 if (mapping_start <= address && address < mapping_end) {
256 fd = open(filenames, O_RDONLY);
260 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
268 *module_name = filenames;
270 while ((scn = elf_nextscn(elf, scn)) != NULL) {
272 GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
273 if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) {
274 Elf_Data *sdata = elf_getdata(scn, NULL);
275 unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ?
279 uintptr_t address_offset = address;
280 if (shdr->sh_type == SHT_DYNSYM)
281 address_offset -= mapping_start;
282 for (cnt = 0; cnt < nsyms; ++cnt) {
285 GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx);
286 if (sym != NULL && sym->st_shndx != SHN_UNDEF) {
287 if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) {
288 symbol = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name));
301 filenames += strlen(filenames)+1;
311 * @brief Opens libdwfl for using with live process
313 * @param pid pid of the process to attach to
314 * @return Dwfl handle
316 static Dwfl *__open_dwfl_with_pid(pid_t pid)
321 if (ptrace(PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACEEXIT) != 0) {
322 fprintf(errfile, "PTRACE_SEIZE failed on PID %d: %m\n", pid);
327 ptrace(PTRACE_INTERRUPT, pid, 0, 0);
329 stopped_pid = waitpid(pid, &status, 0);
330 if (stopped_pid == -1 || stopped_pid != pid || !WIFSTOPPED(status)) {
331 fprintf(errfile, "waitpid failed: %m, stopped_pid=%d, status=%d\n", stopped_pid, status);
335 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &__siginfo) != 0)
338 static const Dwfl_Callbacks proc_callbacks = {
339 .find_elf = dwfl_linux_proc_find_elf,
340 .find_debuginfo = dwfl_standard_find_debuginfo,
341 .section_address = NULL,
342 .debuginfo_path = NULL
345 Dwfl *dwfl = dwfl_begin(&proc_callbacks);
347 fprintf(errfile, "process %d : Can't start dwfl (%s)\n", pid, dwfl_errmsg(-1));
351 if (dwfl_linux_proc_report(dwfl, pid) < 0) {
352 fprintf(errfile, "process %d : dwfl report failed (%s)\n", pid, dwfl_errmsg(-1));
357 #if _ELFUTILS_PREREQ(0,158)
358 if (dwfl_linux_proc_attach(dwfl, pid, true) < 0) {
359 fprintf(errfile, "process %d : dwfl attach failed (%s)\n", pid, dwfl_errmsg(-1));
368 * @brief Opens libdwfl for using with core dump file
370 * @remarks This function will open core file regardless of WITH_CORE_DUMP setting.
371 * It may help with detecting issues with using dwfl even without support
374 * @param core elf handler for the core dump file
375 * @param core_file_name name of the core file; needed only for diagnostics
376 * @return Dwfl handle
378 static Dwfl *__open_dwfl_with_core(Elf *core, const char *core_file_name)
380 static const Dwfl_Callbacks core_callbacks = {
381 .find_elf = dwfl_build_id_find_elf,
382 .find_debuginfo = dwfl_standard_find_debuginfo,
383 .section_address = NULL,
384 .debuginfo_path = NULL
387 Dwfl *dwfl = dwfl_begin(&core_callbacks);
389 fprintf(errfile, "%s : Can't start dwfl (%s)\n", core_file_name, dwfl_errmsg(-1));
393 #if _ELFUTILS_PREREQ(0,158)
394 if (dwfl_core_file_report(dwfl, core, NULL) < 0)
396 if (dwfl_core_file_report(dwfl, core) < 0)
399 fprintf(errfile, "%s : dwfl report failed (%s)\n", core_file_name, dwfl_errmsg(-1));
404 #if _ELFUTILS_PREREQ(0,158)
405 if (dwfl_core_file_attach(dwfl, core) < 0) {
406 fprintf(errfile, "%s : dwfl attach failed (%s)\n", core_file_name, dwfl_errmsg(-1));
415 * @brief Gets registers information for live process
417 * @param pid pid of the live process
418 * @return 0 on success, -1 otherwise
420 static int __get_registers_ptrace(pid_t pid)
423 data.iov_base = _crash_stack_get_memory_for_ptrace_registers(&data.iov_len);
425 if (NULL == data.iov_base) {
426 fprintf(errfile, "Cannot get memory for registers for ptrace (not implemented for this architecture\n");
430 if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &data) != 0) {
431 fprintf(errfile, "PTRACE_GETREGSET failed on PID %d: %m\n", pid);
435 _crash_stack_set_ptrace_registers(data.iov_base);
441 * @brief Get information about the signal that stopped the process
443 * @param pid pid of the live process
444 * @return 0 on success, -1 otherwise
446 static int __get_signal_ptrace(pid_t pid)
448 const char* const signal_table[] = {
449 [SIGHUP]="SIGHUP", [SIGINT]="SIGINT", [SIGQUIT]="SIGQUIT",
450 [SIGILL]="SIGILL", [SIGTRAP]="SIGTRAP", [SIGABRT]="SIGABRT",
451 [SIGIOT]="SIGIOT", [SIGBUS]="SIGBUS", [SIGFPE]="SIGFPE",
452 [SIGKILL]="SIGKILL", [SIGUSR1]="SIGUSR1", [SIGSEGV]="SIGSEGV",
453 [SIGUSR2]="SIGUSR2", [SIGPIPE]="SIGPIPE", [SIGALRM]="SIGALRM",
454 [SIGTERM]="SIGTERM", [SIGSTKFLT]="SIGSTKFLT", [SIGCHLD]="SIGCHLD",
455 [SIGCONT]="SIGCONT", [SIGSTOP]="SIGSTOP", [SIGTSTP]="SIGTSTP",
456 [SIGTTIN]="SIGTTIN", [SIGTTOU]="SIGTTOU", [SIGURG]="SIGURG",
457 [SIGXCPU]="SIGXCPU", [SIGXFSZ]="SIGXFSZ", [SIGVTALRM]="SIGVTALRM",
458 [SIGPROF]="SIGPROF", [SIGWINCH]="SIGWINCH", [SIGIO]="SIGIO",
459 [SIGPWR]="SIGPWR", [SIGSYS]="SIGSYS", [SIGUNUSED]="SIGUNUSED",
462 printf("Signal: %d\n"
466 signal_table[__siginfo.si_signo],
468 switch (__siginfo.si_code) {
471 printf("\tsignal sent by %s (sent by pid %d, uid %d)",
472 __siginfo.si_code == SI_TKILL ? "tkill" : "kill",
473 __siginfo.si_pid, __siginfo.si_uid);
476 printf("\tsignal sent by the kernel\n");
482 #ifdef WITH_CORE_DUMP
484 * @brief Helper function for updating mappings.
486 * @remarks Old versions of libelf not always extract full information about modules.
487 * For such cases we maintain mappings for every module. Those mappings
488 * may be updated while reading notes from core file.
490 * @param mappings mappings database
491 * @param mapping_start address of the mapped start of the module; module is identified
493 * @param mapping_end address of the end of the module; needed to compute module boundaries
494 * @param offset offset within core file - unused
495 * @param name file name of the module
497 static void __updateMapping(Mappings *mappings, uint64_t mapping_start, uint64_t mapping_end,
498 uint64_t offset, const char *name)
501 for (i = 0; i < mappings->elems; i++) {
502 if (mappings->tab[i].m_start == mapping_start) {
503 mappings->tab[i].m_end = mapping_end;
504 mappings->tab[i].m_name = name;
505 mappings->tab[i].m_offset = offset;
506 mappings->tab[i].m_fd = open(name, O_RDONLY);
507 mappings->tab[i].m_elf = elf_begin(mappings->tab[i].m_fd, ELF_C_READ_MMAP, NULL);
515 * @brief Gets registers from core dump
517 * @param core ELF handler for the core dump file
518 * @param core_file_name name of the core file; needed only for diagnostics
519 * @param mappings mappings database
520 * @return notes handler, NULL on error
522 static Elf_Data *__get_registers_core(Elf *core, const char *core_file_name, Mappings *mappings)
524 Elf_Data *notes = NULL;
525 /* The part below uses libebl. In case WITH_CORE_DUMP is enabled, the license
526 * may switch to GPL2.
528 #ifdef WITH_CORE_DUMP
530 GElf_Phdr *phdr = gelf_getphdr(core, 0, &mem);
532 if (phdr == NULL || phdr->p_type != PT_NOTE) {
533 fprintf(errfile, "%s : Missing note section at the first position in core file\n",
538 notes = elf_getdata_rawchunk(core, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR);
540 fprintf(errfile, "%s : error getting notes (%s)\n", core_file_name, dwfl_errmsg(-1));
544 Ebl *ebl = ebl_openbackend(core);
546 fprintf(errfile, "%s : Can't initialize ebl\n", core_file_name);
556 /* registers should be in the first note! */
557 while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
558 if (nhdr.n_type == NT_PRSTATUS && !got_regs) {
559 GElf_Word regs_offset;
561 const Ebl_Register_Location *reglocs;
563 const Ebl_Core_Item *items;
567 if (0 == ebl_core_note(ebl, &nhdr, "CORE", ®s_offset, &nregloc,
568 ®locs, &nitems, &items)) {
570 "%s : error parsing notes (built with different build of libebl?)\n",
575 const char *regs_location = (const char *)(notes->d_buf) + pos + desc_pos
579 for (i = 0; i < nregloc; i++) {
580 const char *register_location = regs_location + reglocs[i].offset;
582 for (regnum = reglocs[i].regno;
583 regnum < reglocs[i].regno + reglocs[i].count;
587 const char *prefix = 0;
588 const char *setname = 0;
590 ssize_t ret = ebl_register_info(ebl, regnum, regname,
591 sizeof(regname), &prefix, &setname,
594 fprintf(errfile, "%s : can't get register info\n", core_file_name);
597 void *place_for_reg_value = _get_place_for_register_value(regname, regnum);
599 if (place_for_reg_value != NULL)
600 __get_value(core, register_location, bits, place_for_reg_value);
602 register_location += bits / 8 + reglocs[i].pad;
605 } else if (nhdr.n_type == NT_FILE) {
606 uint64_t values_cnt = 0, page_size = 0;
608 const char *filenames;
609 size_t addr_size = 0;
611 __parse_note_file(core, notes->d_buf + desc_pos, &values_cnt, &page_size,
612 &addr_size, &values, &filenames);
615 /* First: triplets of <mapping-start> <mapping-end> <offset-in-pages>
617 * Then the names of files.
619 for (ii = 0; ii < values_cnt; ii++) {
620 uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
621 const char *item = values + 3 * addr_size * ii;
623 __get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end,
625 __updateMapping(mappings, mapping_start, mapping_end,
626 offset_in_pages*page_size, filenames);
627 filenames += strlen(filenames)+1;
632 ebl_closebackend(ebl);
634 fprintf(errfile, "Configured without support for core dump files\n");
640 * @brief Resolves procedure and module names using libdwfl
642 * @param proc_info gathered call stack element
643 * @param dwfl dwfl handler
645 static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl)
647 uintptr_t address = proc_info->addr;
648 Dwfl_Module *module = dwfl_addrmodule(dwfl, address);
651 const char *module_name = proc_info->module_name;
653 const char *fname = 0;
654 const char *module_name = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
656 proc_info->module_name = strdup(fname);
657 else if (module_name)
658 proc_info->module_name = strdup(module_name);
660 const char *symbol = proc_info->name;
662 symbol = dwfl_module_addrname(module, proc_info->addr);
664 proc_info->name = strdup(symbol);
670 * @brief Resolves procedure and module names using elfutils
672 * @param proc_info gathered call stack element
673 * @param core ELF handler for the core dump file, NULL if live process analyzed
674 * @param notes notes handler, NULL if live process analyzed
676 static void __resolve_symbols_from_elf(ProcInfo *proc_info, Elf *core, Elf_Data *notes)
678 const char *fname = 0;
679 char *symbol_from_elf = __try_symbol_from_elfs(core, notes, proc_info->addr, &fname);
680 if (!proc_info->module_name && fname)
681 proc_info->module_name = strdup(fname);
683 if (!proc_info->name && symbol_from_elf)
684 proc_info->name = symbol_from_elf;
688 * @brief Checks if symbol starts with '_Z' prefix
690 * @param symbol string to compare
692 static int is_symbol_demanglable(const char *symbol)
694 return symbol != 0 && (strlen(symbol) >= 2) &&
695 symbol[0] == '_' && symbol[1] == 'Z';
699 * @brief Replaces symbols with demangled
701 * @param proc_info gathered call stack element
703 static void __demangle_symbols(ProcInfo *proc_info)
706 char *dem_buffer = NULL;
707 char *demangled_symbol = __cxa_demangle(proc_info->name, dem_buffer, NULL, &status);
709 free(proc_info->name);
710 proc_info->name = demangled_symbol;
715 * @brief Resolves procedure and module name
717 * @param proc_info gathered call stack element
718 * @param dwfl dwfl handler
719 * @param core ELF handler for the core dump file, NULL if live process analyzed
720 * @param notes notes handler, NULL if live process analyzed
722 static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl, Elf *core, Elf_Data *notes)
724 if (!proc_info->module_name || !proc_info->name)
725 __resolve_symbols_from_dwfl(proc_info, dwfl);
727 if (!proc_info->module_name || !proc_info->name)
728 __resolve_symbols_from_elf(proc_info, core, notes);
730 if (is_symbol_demanglable(proc_info->name))
731 __demangle_symbols(proc_info);
735 * @brief Prints call stack element to the global outputfile.
737 * @param proc_info gathered call stack element
739 static void __print_proc_info(ProcInfo *proc_info)
741 if (proc_info->name) {
742 fprintf(outputfile, "%s ", proc_info->name);
743 if (proc_info->offset >= 0)
744 fprintf(outputfile, "+ 0x%x ", proc_info->offset);
746 if (sizeof(proc_info->addr) > 4)
747 fprintf(outputfile, "(0x%016llx)", (long long)proc_info->addr);
749 fprintf(outputfile, "(0x%08x)", (int32_t)proc_info->addr);
751 if (proc_info->module_name != 0)
752 fprintf(outputfile, " [%s]", proc_info->module_name);
754 fprintf(outputfile, "\n");
758 * @brief Prints call stack to the global outputfile.
760 * @param callstack gathered call stack database
761 * @param pid PID of the live process, 0 if core dump file analyzed
763 static void __print_callstack(Callstack *callstack, pid_t pid)
765 fprintf(outputfile, "\nCallstack Information");
767 fprintf(outputfile, " (PID:%d)", pid);
768 fprintf(outputfile, "\nCall Stack Count: %zu\n", callstack->elems);
771 for (it = 0; it != callstack->elems; ++it) {
772 fprintf(outputfile, "%2zu: ", it);
773 __print_proc_info(&callstack->proc[it]);
775 fprintf(outputfile, "End of Call Stack\n");
778 void callstack_constructor(Callstack *callstack)
781 callstack->elems = 0;
782 for (it = 0; it < (int)sizeof(callstack->proc)/sizeof(callstack->proc[0]); ++it) {
783 callstack->proc[it].offset = -1;
784 callstack->proc[it].name = 0;
785 callstack->proc[it].module_name = 0;
789 void callstack_destructor(Callstack *callstack)
792 for (it = 0; it < callstack->elems; ++it) {
793 free(callstack->proc[it].name);
794 free(callstack->proc[it].module_name);
796 fprintf(outputfile, "End of Call Stack\n");
800 * @brief Print thread information
802 * @param outputfile File handle for printing report.
803 * @param pid PID of the inspected process
804 * @param tid TID of the inspected thread
806 static void __crash_stack_print_threads(FILE* outputfile, pid_t pid, pid_t tid)
811 struct dirent *dentry=NULL;
812 char task_path[PATH_MAX];
816 snprintf(task_path, PATH_MAX, "/proc/%d/task", pid);
817 if (stat(task_path, &sb) == -1) {
821 threadnum = sb.st_nlink - 2;
824 fprintf(outputfile, "\nThreads Information\n");
826 "Threads: %d\nPID = %d TID = %d\n",
827 threadnum, pid, tid);
829 dir = opendir(task_path);
831 fprintf(stderr, "[crash-stack] cannot open %s\n", task_path);
833 while (readdir_r(dir, &entry, &dentry) == 0 && dentry) {
834 if (strcmp(dentry->d_name, ".") == 0 ||
835 strcmp(dentry->d_name, "..") == 0)
837 fprintf(outputfile, "%s ", dentry->d_name);
840 fprintf(outputfile, "\n");
847 * @brief Main function.
849 * Main module accepts two forms of launching:
851 * crash-stack core-dump-file
852 * crash-stack --pid pid
854 * The first form allows user to print call stack of a generated core dump file.
855 * The second form allows connecting to a live process and displaying its call stack.
856 * It might be also used for connecting to a process from system's core dump handler.
858 int main(int argc, char **argv)
864 const char *core_file_name;
866 prctl(PR_SET_DUMPABLE, 0);
868 while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) {
877 outputfile = fopen(optarg, "w");
880 errfile = fopen(optarg, "w");
885 if (NULL == errfile) errfile = stderr;
886 if (NULL == outputfile) outputfile = stdout;
888 core_file_name = argv[optind];
891 elf_version(EV_CURRENT);
893 /* First, prepare dwfl and modules */
899 dwfl = __open_dwfl_with_pid(pid);
903 "Usage: %s [--output file] [--erroutput file] [--pid <pid> | <core-file>]\n",
908 core_fd = open(core_file_name, O_RDONLY);
910 perror(core_file_name);
914 core = elf_begin(core_fd, ELF_C_READ_MMAP, NULL);
916 fprintf(errfile, "%s : Can't open ELF (%s)\n", core_file_name, elf_errmsg(-1));
920 dwfl = __open_dwfl_with_core(core, core_file_name);
929 dwfl_getmodules(dwfl, __module_callback, &mappings, 0);
932 /* Now, get registers */
934 if (-1 == __get_signal_ptrace(pid))
936 if (-1 == __get_registers_ptrace(pid))
939 notes = __get_registers_core(core, core_file_name, &mappings);
944 /* Unwind call stack */
946 callstack_constructor(&callstack);
948 _create_crash_stack(dwfl, core, pid, &mappings, &callstack);
950 for (it = 0; it != callstack.elems; ++it)
951 __resolve_symbols(&callstack.proc[it], dwfl, core, notes);
953 /* Print registers */
954 _crash_stack_print_regs(outputfile);
957 __crash_stack_print_threads(outputfile, pid, tid);
959 /* Print the results */
960 __print_callstack(&callstack, pid);
963 callstack_destructor(&callstack);
964 dwfl_report_end(dwfl, NULL, NULL);
966 if (NULL != core) elf_end(core);
967 if (-1 != core_fd) close(core_fd);