4 #include <elfutils/libdwfl.h>
5 #include <elfutils/libebl.h>
10 #include <sys/prctl.h>
11 #include <linux/prctl.h>
12 #include "crash-stack.h"
14 #include <elfutils/version.h>
16 #include <sys/ptrace.h>
18 #include <sys/types.h>
21 static FILE *outputfile = NULL;
22 static FILE *errfile = NULL;
30 const struct option opts[] = {
31 { "pid", required_argument, 0, OPT_PID },
32 { "output", required_argument, 0, OPT_OUTPUTFILE },
33 { "erroutput", required_argument, 0, OPT_ERRFILE },
37 extern char *__cxa_demangle(const char *mangled_name, char *output_buffer,
38 size_t *length, int *status);
40 static int module_callback(Dwfl_Module *module, void **userdata,
41 const char *name, Dwarf_Addr address,
44 if (name != NULL && name[0] == '[') {
45 /* libdwfl couldn't get the module file - we will get it later from notes */
46 Mappings *mappings = arg;
47 if (mappings->elems < MAX_MAPPINGS_NUM) {
48 size_t elems = mappings->elems;
49 mappings->tab[elems].m_start = address;
50 mappings->tab[elems].m_end = 0;
51 mappings->tab[elems].m_offset = 0;
52 mappings->tab[elems].m_name = NULL;
53 mappings->tab[elems].m_fd = -1;
54 mappings->tab[elems].m_elf = 0;
58 /* fprintf(errfile, "Got module %s @0x%llx\n", name, (long long)address);*/
62 static void getvalue(Elf *core, const void *from, size_t size, void *to)
66 .d_type = size == 32 ? ELF_T_WORD : ELF_T_XWORD,
67 .d_version = EV_CURRENT,
73 .d_buf = (void*)(from),
75 .d_version = out.d_version,
81 if (gelf_getclass(core) == ELFCLASS32)
82 data = elf32_xlatetom(&out, &in, elf_getident(core, NULL)[EI_DATA]);
84 data = elf64_xlatetom(&out, &in, elf_getident(core, NULL)[EI_DATA]);
86 fprintf(errfile, "failed to get value from core file\n");
89 static void updateMapping(Mappings *mappings, uint64_t mapping_start, uint64_t mapping_end,
90 uint64_t offset, const char *name)
93 for (i = 0; i < mappings->elems; i++) {
94 if (mappings->tab[i].m_start == mapping_start) {
95 mappings->tab[i].m_end = mapping_end;
96 mappings->tab[i].m_name = name;
97 mappings->tab[i].m_offset = offset;
98 mappings->tab[i].m_fd = open(name, O_RDONLY);
99 mappings->tab[i].m_elf = elf_begin(mappings->tab[i].m_fd, ELF_C_READ_MMAP, NULL);
105 static void parse_note_file(Elf *elf, const char *desc, uint64_t *values_cnt, uint64_t *page_size,
106 size_t *addr_size, const char **values, const char **filenames)
108 *addr_size = gelf_fsize(elf, ELF_T_ADDR, 1, EV_CURRENT);
109 getvalue(elf, desc, *addr_size*8, values_cnt);
110 getvalue(elf, desc + *addr_size, *addr_size*8, page_size);
111 /* First: triplets of <mapping-start> <mapping-end> <offset-in-pages>
113 * Then the names of files.
115 *values = desc + 2 * *addr_size;
116 *filenames = *values + 3 * *addr_size * *values_cnt;
119 static void get_mapping_item(Elf *elf, size_t addr_size, const void *item,
120 uint64_t *mapping_start, uint64_t *mapping_end, uint64_t *offset_in_pages)
122 getvalue(elf, item, addr_size*8, mapping_start);
123 getvalue(elf, item + addr_size, addr_size*8, mapping_end);
124 getvalue(elf, item + 2 * addr_size, addr_size*8, offset_in_pages);
127 static char *try_symbol_from_elfs(Elf *core, Elf_Data *notes, uintptr_t address,
128 const char **module_name)
137 while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
138 if (nhdr.n_type == NT_FILE) {
139 uint64_t values_cnt = 0, page_size = 0;
141 const char *filenames;
142 size_t addr_size = 0;
144 parse_note_file(core, notes->d_buf + desc_pos, &values_cnt, &page_size, &addr_size, &values, &filenames);
147 for (ii = 0; ii < values_cnt; ii++) {
148 uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
149 const char *item = values + 3 * addr_size * ii;
151 get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end, &offset_in_pages);
153 if (mapping_start <= address && address < mapping_end) {
156 fd = open(filenames, O_RDONLY);
160 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
168 *module_name = filenames;
170 while ((scn = elf_nextscn(elf, scn)) != NULL) {
172 GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
173 if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) {
174 Elf_Data *sdata = elf_getdata(scn, NULL);
175 unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ?
179 uintptr_t address_offset = address;
180 if (shdr->sh_type == SHT_DYNSYM)
181 address_offset -= mapping_start;
182 for (cnt = 0; cnt < nsyms; ++cnt) {
185 GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx);
186 if (sym != NULL && sym->st_shndx != SHN_UNDEF) {
187 if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) {
188 symbol = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name));
201 filenames += strlen(filenames)+1;
210 static Dwfl *open_dwfl_with_pid(pid_t pid)
215 if (ptrace(PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACEEXIT) != 0) {
216 fprintf(errfile, "PTRACE_SEIZE failed on PID %d: %m\n", pid);
220 ptrace(PTRACE_INTERRUPT, pid, 0, 0);
222 stopped_pid = waitpid(pid, &status, 0);
223 if (stopped_pid == -1 || stopped_pid != pid || !WIFSTOPPED(status)) {
224 fprintf(errfile, "waitpid failed: %m, stopped_pid=%d, status=%d\n", stopped_pid, status);
228 static const Dwfl_Callbacks proc_callbacks = {
229 .find_elf = dwfl_linux_proc_find_elf,
230 .find_debuginfo = dwfl_standard_find_debuginfo,
231 .section_address = NULL,
232 .debuginfo_path = NULL
235 Dwfl *dwfl = dwfl_begin(&proc_callbacks);
237 fprintf(errfile, "process %d : Can't start dwfl (%s)\n", pid, dwfl_errmsg(-1));
241 if (dwfl_linux_proc_report(dwfl, pid) < 0) {
242 fprintf(errfile, "process %d : dwfl report failed (%s)\n", pid, dwfl_errmsg(-1));
247 #if _ELFUTILS_PREREQ(0, 158)
248 if (dwfl_linux_proc_attach(dwfl, pid, true) < 0) {
249 fprintf(errfile, "process %d : dwfl attach failed (%s)\n", pid, dwfl_errmsg(-1));
257 static Dwfl *open_dwfl_with_core(Elf *core, const char *core_file_name)
259 static const Dwfl_Callbacks core_callbacks = {
260 .find_elf = dwfl_build_id_find_elf,
261 .find_debuginfo = dwfl_standard_find_debuginfo,
262 .section_address = NULL,
263 .debuginfo_path = NULL
266 Dwfl *dwfl = dwfl_begin(&core_callbacks);
268 fprintf(errfile, "%s : Can't start dwfl (%s)\n", core_file_name, dwfl_errmsg(-1));
272 #if _ELFUTILS_PREREQ(0, 158)
273 if (dwfl_core_file_report(dwfl, core, NULL) < 0)
275 if (dwfl_core_file_report(dwfl, core) < 0)
278 fprintf(errfile, "%s : dwfl report failed (%s)\n", core_file_name, dwfl_errmsg(-1));
283 #if _ELFUTILS_PREREQ(0, 158)
284 if (dwfl_core_file_attach(dwfl, core) < 0) {
285 fprintf(errfile, "%s : dwfl attach failed (%s)\n", core_file_name, dwfl_errmsg(-1));
293 static int get_registers_ptrace(pid_t pid)
296 uintptr_t regbuf[20];
298 data.iov_base = regbuf;
299 data.iov_len = sizeof(regbuf);
301 if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &data) != 0) {
302 fprintf(errfile, "PTRACE_GETREGSET failed on PID %d: %m\n", pid);
308 i * sizeof(regbuf[0]) < data.iov_len && i < sizeof(regbuf)/sizeof(regbuf[0]);
310 void *reg = get_place_for_register_value("", i);
313 memcpy(reg, ®buf[i], sizeof(regbuf[i]));
318 static Elf_Data *get_registers_core(Elf *core, const char *core_file_name, Mappings *mappings)
321 GElf_Phdr *phdr = gelf_getphdr(core, 0, &mem);
323 if (phdr == NULL || phdr->p_type != PT_NOTE) {
324 fprintf(errfile, "%s : Missing note section at the first position in core file\n",
329 Elf_Data *notes = elf_getdata_rawchunk(core, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR);
331 fprintf(errfile, "%s : error getting notes (%s)\n", core_file_name, dwfl_errmsg(-1));
335 Ebl *ebl = ebl_openbackend(core);
337 fprintf(errfile, "%s : Can't initialize ebl\n", core_file_name);
347 /* registers should be in the first note! */
348 while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) {
349 if (nhdr.n_type == NT_PRSTATUS && !got_regs) {
350 GElf_Word regs_offset;
352 const Ebl_Register_Location *reglocs;
354 const Ebl_Core_Item *items;
358 if (0 == ebl_core_note(ebl, &nhdr, "CORE", ®s_offset, &nregloc,
359 ®locs, &nitems, &items)) {
361 "%s : error parsing notes (built with different build of libebl?)\n",
366 const char *regs_location = (const char *)(notes->d_buf) + pos + desc_pos
370 for (i = 0; i < nregloc; i++) {
371 const char *register_location = regs_location + reglocs[i].offset;
373 for (regnum = reglocs[i].regno;
374 regnum < reglocs[i].regno + reglocs[i].count;
378 const char *prefix = 0;
379 const char *setname = 0;
381 ssize_t ret = ebl_register_info(ebl, regnum, regname,
382 sizeof(regname), &prefix, &setname,
385 fprintf(errfile, "%s : can't get register info\n", core_file_name);
388 void *place_for_reg_value = get_place_for_register_value(regname, regnum);
390 if (place_for_reg_value != NULL)
391 getvalue(core, register_location, bits, place_for_reg_value);
393 register_location += bits / 8 + reglocs[i].pad;
396 } else if (nhdr.n_type == NT_FILE) {
397 uint64_t values_cnt = 0, page_size = 0;
399 const char *filenames;
400 size_t addr_size = 0;
402 parse_note_file(core, notes->d_buf + desc_pos, &values_cnt, &page_size,
403 &addr_size, &values, &filenames);
406 /* First: triplets of <mapping-start> <mapping-end> <offset-in-pages>
408 * Then the names of files.
410 for (ii = 0; ii < values_cnt; ii++) {
411 uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
412 const char *item = values + 3 * addr_size * ii;
414 get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end,
416 updateMapping(mappings, mapping_start, mapping_end,
417 offset_in_pages*page_size, filenames);
418 filenames += strlen(filenames)+1;
423 ebl_closebackend(ebl);
427 static void printCallstack(Callstack *callstack, Dwfl *dwfl, Elf *core, pid_t pid,
430 fprintf(outputfile, "Call stack");
431 if (pid > 1) fprintf(outputfile, " for PID %d", pid);
432 fprintf(outputfile, ":\n");
434 char *dem_buffer = NULL;
436 for (it = 0; it != callstack->elems; ++it) {
437 if (sizeof(callstack->tab[0]) > 4)
438 fprintf(outputfile, "0x%016llx: ", (long long)callstack->tab[it]);
440 fprintf(outputfile, "0x%08x: ", (int32_t)callstack->tab[it]);
441 Dwfl_Module *module = dwfl_addrmodule(dwfl, callstack->tab[it]);
443 char *demangled_symbol = 0;
444 const char *symbol = dwfl_module_addrname(module, callstack->tab[it]);
445 const char *fname = 0;
446 const char *module_name = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
447 char *symbol_from_elf = 0;
449 symbol = symbol_from_elf = try_symbol_from_elfs(core, notes, callstack->tab[it], &fname);
450 if (symbol != 0 && symbol[0] == '_' && symbol[1] == 'Z') {
453 demangled_symbol = __cxa_demangle(symbol, dem_buffer, NULL, &status);
455 symbol = demangled_symbol;
458 fprintf(outputfile, "%s()", symbol);
460 fprintf(outputfile, "<unknown>");
462 if (demangled_symbol != 0)
463 free(demangled_symbol);
465 if (symbol_from_elf != 0)
466 free(symbol_from_elf);
468 fprintf(outputfile, " from %s\n", fname != NULL ? fname : module_name);
470 fprintf(outputfile, "unknown function\n");
475 int main(int argc, char **argv)
480 const char *core_file_name;
482 prctl(PR_SET_DUMPABLE, 0);
484 while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) {
490 outputfile = fopen(optarg, "w");
493 errfile = fopen(optarg, "w");
498 if (NULL == errfile) errfile = stderr;
499 if (NULL == outputfile) outputfile = stdout;
501 core_file_name = argv[optind];
504 elf_version(EV_CURRENT);
506 /* First, prepare dwfl and modules */
512 dwfl = open_dwfl_with_pid(pid);
516 "Usage: %s [--output file] [--erroutput file] [--pid <pid> | <core-file>]\n",
521 core_fd = open(core_file_name, O_RDONLY);
523 perror(core_file_name);
527 core = elf_begin(core_fd, ELF_C_READ_MMAP, NULL);
529 fprintf(errfile, "%s : Can't open ELF (%s)\n", core_file_name, elf_errmsg(-1));
533 dwfl = open_dwfl_with_core(core, core_file_name);
542 dwfl_getmodules(dwfl, module_callback, &mappings, 0);
545 /* Now, get registers */
547 if (-1 == get_registers_ptrace(pid))
550 notes = get_registers_core(core, core_file_name, &mappings);
555 /* Unwind call stack */
558 create_crash_stack(dwfl, core, pid, &mappings, &callstack);
560 /* Print the results */
561 printCallstack(&callstack, dwfl, core, pid, notes);
564 dwfl_report_end(dwfl, NULL, NULL);
566 if (NULL != core) elf_end(core);
567 if (-1 != core_fd) close(core_fd);