4 #include <elfutils/libdwfl.h>
6 #include <elfutils/libebl.h>
12 #include <sys/prctl.h>
13 #include <linux/prctl.h>
14 #include "crash-stack.h"
16 #include <elfutils/version.h>
18 #include <sys/ptrace.h>
20 #include <sys/types.h>
23 static FILE *outputfile = NULL;
24 static FILE *errfile = NULL;
32 const struct option opts[] = {
33 { "pid", required_argument, 0, OPT_PID },
34 { "output", required_argument, 0, OPT_OUTPUTFILE },
35 { "erroutput", required_argument, 0, OPT_ERRFILE },
39 extern char *__cxa_demangle(const char *mangled_name, char *output_buffer,
40 size_t *length, int *status);
42 static int module_callback(Dwfl_Module *module, void **userdata,
43 const char *name, Dwarf_Addr address,
46 if (name != NULL && name[0] == '[') {
47 /* libdwfl couldn't get the module file - we will get it later from notes */
48 Mappings *mappings = arg;
49 if (mappings->elems < MAX_MAPPINGS_NUM) {
50 size_t elems = mappings->elems;
51 mappings->tab[elems].m_start = address;
52 mappings->tab[elems].m_end = 0;
53 mappings->tab[elems].m_offset = 0;
54 mappings->tab[elems].m_name = NULL;
55 mappings->tab[elems].m_fd = -1;
56 mappings->tab[elems].m_elf = 0;
63 static void getvalue(Elf *core, const void *from, size_t size, void *to)
65 Elf_Type type = ELF_T_BYTE;
67 case 8: type = ELF_T_BYTE; break;
68 case 16: type = ELF_T_HALF; break;
69 case 32: type = ELF_T_WORD; break;
70 case 64: type = ELF_T_XWORD; break;
72 fprintf(stderr, "getvalue for strange size: %llu\n", (unsigned long long)size);
78 .d_version = EV_CURRENT,
84 .d_buf = (void*)(from),
86 .d_version = out.d_version,
92 if (gelf_getclass(core) == ELFCLASS32)
93 data = elf32_xlatetom(&out, &in, elf_getident(core, NULL)[EI_DATA]);
95 data = elf64_xlatetom(&out, &in, elf_getident(core, NULL)[EI_DATA]);
97 fprintf(errfile, "failed to get value from core file\n");
100 static void parse_note_file(Elf *elf, const char *desc, uint64_t *values_cnt, uint64_t *page_size,
101 size_t *addr_size, const char **values, const char **filenames)
103 *addr_size = gelf_fsize(elf, ELF_T_ADDR, 1, EV_CURRENT);
104 getvalue(elf, desc, *addr_size*8, values_cnt);
105 getvalue(elf, desc + *addr_size, *addr_size*8, page_size);
106 /* First: triplets of <mapping-start> <mapping-end> <offset-in-pages>
108 * Then the names of files.
110 *values = desc + 2 * *addr_size;
111 *filenames = *values + 3 * *addr_size * *values_cnt;
114 static void get_mapping_item(Elf *elf, size_t addr_size, const void *item,
115 uint64_t *mapping_start, uint64_t *mapping_end, uint64_t *offset_in_pages)
117 getvalue(elf, item, addr_size*8, mapping_start);
118 getvalue(elf, item + addr_size, addr_size*8, mapping_end);
119 getvalue(elf, item + 2 * addr_size, addr_size*8, offset_in_pages);
122 static char *try_symbol_from_elfs(Elf *core, Elf_Data *notes, uintptr_t address,
123 const char **module_name)
132 while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
133 if (nhdr.n_type == NT_FILE) {
134 uint64_t values_cnt = 0, page_size = 0;
136 const char *filenames;
137 size_t addr_size = 0;
139 parse_note_file(core, notes->d_buf + desc_pos, &values_cnt, &page_size, &addr_size, &values, &filenames);
142 for (ii = 0; ii < values_cnt; ii++) {
143 uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
144 const char *item = values + 3 * addr_size * ii;
146 get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end, &offset_in_pages);
148 if (mapping_start <= address && address < mapping_end) {
151 fd = open(filenames, O_RDONLY);
155 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
163 *module_name = filenames;
165 while ((scn = elf_nextscn(elf, scn)) != NULL) {
167 GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
168 if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) {
169 Elf_Data *sdata = elf_getdata(scn, NULL);
170 unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ?
174 uintptr_t address_offset = address;
175 if (shdr->sh_type == SHT_DYNSYM)
176 address_offset -= mapping_start;
177 for (cnt = 0; cnt < nsyms; ++cnt) {
180 GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx);
181 if (sym != NULL && sym->st_shndx != SHN_UNDEF) {
182 if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) {
183 symbol = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name));
196 filenames += strlen(filenames)+1;
205 static Dwfl *open_dwfl_with_pid(pid_t pid)
210 if (ptrace(PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACEEXIT) != 0) {
211 fprintf(errfile, "PTRACE_SEIZE failed on PID %d: %m\n", pid);
215 ptrace(PTRACE_INTERRUPT, pid, 0, 0);
217 stopped_pid = waitpid(pid, &status, 0);
218 if (stopped_pid == -1 || stopped_pid != pid || !WIFSTOPPED(status)) {
219 fprintf(errfile, "waitpid failed: %m, stopped_pid=%d, status=%d\n", stopped_pid, status);
223 static const Dwfl_Callbacks proc_callbacks = {
224 .find_elf = dwfl_linux_proc_find_elf,
225 .find_debuginfo = dwfl_standard_find_debuginfo,
226 .section_address = NULL,
227 .debuginfo_path = NULL
230 Dwfl *dwfl = dwfl_begin(&proc_callbacks);
232 fprintf(errfile, "process %d : Can't start dwfl (%s)\n", pid, dwfl_errmsg(-1));
236 if (dwfl_linux_proc_report(dwfl, pid) < 0) {
237 fprintf(errfile, "process %d : dwfl report failed (%s)\n", pid, dwfl_errmsg(-1));
242 #if _ELFUTILS_PREREQ(0,158)
243 if (dwfl_linux_proc_attach(dwfl, pid, true) < 0) {
244 fprintf(errfile, "process %d : dwfl attach failed (%s)\n", pid, dwfl_errmsg(-1));
253 * This function will open core file regardless of WITH_CORE_DUMP setting.
254 * It may help with detecting issues with using dwfl even without support for dumps.
256 static Dwfl *open_dwfl_with_core(Elf *core, const char *core_file_name)
258 static const Dwfl_Callbacks core_callbacks = {
259 .find_elf = dwfl_build_id_find_elf,
260 .find_debuginfo = dwfl_standard_find_debuginfo,
261 .section_address = NULL,
262 .debuginfo_path = NULL
265 Dwfl *dwfl = dwfl_begin(&core_callbacks);
267 fprintf(errfile, "%s : Can't start dwfl (%s)\n", core_file_name, dwfl_errmsg(-1));
271 #if _ELFUTILS_PREREQ(0,158)
272 if (dwfl_core_file_report(dwfl, core, NULL) < 0)
274 if (dwfl_core_file_report(dwfl, core) < 0)
277 fprintf(errfile, "%s : dwfl report failed (%s)\n", core_file_name, dwfl_errmsg(-1));
282 #if _ELFUTILS_PREREQ(0,158)
283 if (dwfl_core_file_attach(dwfl, core) < 0) {
284 fprintf(errfile, "%s : dwfl attach failed (%s)\n", core_file_name, dwfl_errmsg(-1));
292 static int get_registers_ptrace(pid_t pid)
295 data.iov_base = crash_stack_get_memory_for_ptrace_registers( &data.iov_len );
297 if (NULL == data.iov_base) {
298 fprintf(errfile, "Cannot get memory for registers for ptrace (not implemented for this architecture\n");
302 if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &data) != 0) {
303 fprintf(errfile, "PTRACE_GETREGSET failed on PID %d: %m\n", pid);
307 crash_stack_set_ptrace_registers(data.iov_base);
312 #ifdef WITH_CORE_DUMP
313 static void updateMapping(Mappings *mappings, uint64_t mapping_start, uint64_t mapping_end,
314 uint64_t offset, const char *name)
317 for (i = 0; i < mappings->elems; i++) {
318 if (mappings->tab[i].m_start == mapping_start) {
319 mappings->tab[i].m_end = mapping_end;
320 mappings->tab[i].m_name = name;
321 mappings->tab[i].m_offset = offset;
322 mappings->tab[i].m_fd = open(name, O_RDONLY);
323 mappings->tab[i].m_elf = elf_begin(mappings->tab[i].m_fd, ELF_C_READ_MMAP, NULL);
330 static Elf_Data *get_registers_core(Elf *core, const char *core_file_name, Mappings *mappings)
332 Elf_Data *notes = NULL;
333 #ifdef WITH_CORE_DUMP
335 GElf_Phdr *phdr = gelf_getphdr(core, 0, &mem);
337 if (phdr == NULL || phdr->p_type != PT_NOTE) {
338 fprintf(errfile, "%s : Missing note section at the first position in core file\n",
343 notes = elf_getdata_rawchunk(core, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR);
345 fprintf(errfile, "%s : error getting notes (%s)\n", core_file_name, dwfl_errmsg(-1));
349 Ebl *ebl = ebl_openbackend(core);
351 fprintf(errfile, "%s : Can't initialize ebl\n", core_file_name);
361 /* registers should be in the first note! */
362 while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
363 if (nhdr.n_type == NT_PRSTATUS && !got_regs) {
364 GElf_Word regs_offset;
366 const Ebl_Register_Location *reglocs;
368 const Ebl_Core_Item *items;
372 if (0 == ebl_core_note(ebl, &nhdr, "CORE", ®s_offset, &nregloc,
373 ®locs, &nitems, &items)) {
375 "%s : error parsing notes (built with different build of libebl?)\n",
380 const char *regs_location = (const char *)(notes->d_buf) + pos + desc_pos
384 for (i = 0; i < nregloc; i++) {
385 const char *register_location = regs_location + reglocs[i].offset;
387 for (regnum = reglocs[i].regno;
388 regnum < reglocs[i].regno + reglocs[i].count;
392 const char *prefix = 0;
393 const char *setname = 0;
395 ssize_t ret = ebl_register_info(ebl, regnum, regname,
396 sizeof(regname), &prefix, &setname,
399 fprintf(errfile, "%s : can't get register info\n", core_file_name);
402 void *place_for_reg_value = get_place_for_register_value(regname, regnum);
404 if (place_for_reg_value != NULL)
405 getvalue(core, register_location, bits, place_for_reg_value);
407 register_location += bits / 8 + reglocs[i].pad;
410 } else if (nhdr.n_type == NT_FILE) {
411 uint64_t values_cnt = 0, page_size = 0;
413 const char *filenames;
414 size_t addr_size = 0;
416 parse_note_file(core, notes->d_buf + desc_pos, &values_cnt, &page_size,
417 &addr_size, &values, &filenames);
420 /* First: triplets of <mapping-start> <mapping-end> <offset-in-pages>
422 * Then the names of files.
424 for (ii = 0; ii < values_cnt; ii++) {
425 uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
426 const char *item = values + 3 * addr_size * ii;
428 get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end,
430 updateMapping(mappings, mapping_start, mapping_end,
431 offset_in_pages*page_size, filenames);
432 filenames += strlen(filenames)+1;
437 ebl_closebackend(ebl);
439 fprintf(errfile, "Configured without support for core dump files\n");
444 static void printCallstack(Callstack *callstack, Dwfl *dwfl, Elf *core, pid_t pid,
447 fprintf(outputfile, "Call stack");
448 if (pid > 1) fprintf(outputfile, " for PID %d", pid);
449 fprintf(outputfile, ":\n");
451 char *dem_buffer = NULL;
453 for (it = 0; it != callstack->elems; ++it) {
454 if (sizeof(callstack->tab[0]) > 4)
455 fprintf(outputfile, "0x%016llx: ", (long long)callstack->tab[it]);
457 fprintf(outputfile, "0x%08x: ", (int32_t)callstack->tab[it]);
458 Dwfl_Module *module = dwfl_addrmodule(dwfl, callstack->tab[it]);
460 char *demangled_symbol = 0;
461 const char *symbol = dwfl_module_addrname(module, callstack->tab[it]);
462 const char *fname = 0;
463 const char *module_name = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
464 char *symbol_from_elf = 0;
466 symbol = symbol_from_elf = try_symbol_from_elfs(core, notes, callstack->tab[it], &fname);
467 if (symbol != 0 && symbol[0] == '_' && symbol[1] == 'Z') {
470 demangled_symbol = __cxa_demangle(symbol, dem_buffer, NULL, &status);
472 symbol = demangled_symbol;
475 fprintf(outputfile, "%s()", symbol);
477 fprintf(outputfile, "<unknown>");
479 if (demangled_symbol != 0)
480 free(demangled_symbol);
482 if (symbol_from_elf != 0)
483 free(symbol_from_elf);
485 fprintf(outputfile, " from %s\n", fname != NULL ? fname : module_name);
487 fprintf(outputfile, "unknown function\n");
492 int main(int argc, char **argv)
497 const char *core_file_name;
499 prctl(PR_SET_DUMPABLE, 0);
501 while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) {
507 outputfile = fopen(optarg, "w");
510 errfile = fopen(optarg, "w");
515 if (NULL == errfile) errfile = stderr;
516 if (NULL == outputfile) outputfile = stdout;
518 core_file_name = argv[optind];
521 elf_version(EV_CURRENT);
523 /* First, prepare dwfl and modules */
529 dwfl = open_dwfl_with_pid(pid);
533 "Usage: %s [--output file] [--erroutput file] [--pid <pid> | <core-file>]\n",
538 core_fd = open(core_file_name, O_RDONLY);
540 perror(core_file_name);
544 core = elf_begin(core_fd, ELF_C_READ_MMAP, NULL);
546 fprintf(errfile, "%s : Can't open ELF (%s)\n", core_file_name, elf_errmsg(-1));
550 dwfl = open_dwfl_with_core(core, core_file_name);
559 dwfl_getmodules(dwfl, module_callback, &mappings, 0);
562 /* Now, get registers */
564 if (-1 == get_registers_ptrace(pid))
567 notes = get_registers_core(core, core_file_name, &mappings);
572 /* Unwind call stack */
575 create_crash_stack(dwfl, core, pid, &mappings, &callstack);
577 /* Print the results */
578 printCallstack(&callstack, dwfl, core, pid, notes);
581 dwfl_report_end(dwfl, NULL, NULL);
583 if (NULL != core) elf_end(core);
584 if (-1 != core_fd) close(core_fd);