BT_HIDDEN int bt_dwarf_die_get_call_file(struct bt_dwarf_die *die, char **filename) { int ret; Dwarf_Sword file_no; const char *_filename = NULL; Dwarf_Files *src_files = NULL; Dwarf_Attribute *file_attr = NULL; struct bt_dwarf_die *cu_die = NULL; if (!die || !filename) { goto error; } file_attr = g_new0(Dwarf_Attribute, 1); if (!file_attr) { goto error; } file_attr = dwarf_attr(die->dwarf_die, DW_AT_call_file, file_attr); if (!file_attr) { goto error; } ret = dwarf_formsdata(file_attr, &file_no); if (ret) { goto error; } cu_die = bt_dwarf_die_create(die->cu); if (!cu_die) { goto error; } ret = dwarf_getsrcfiles(cu_die->dwarf_die, &src_files, NULL); if (ret) { goto error; } _filename = dwarf_filesrc(src_files, file_no, NULL, NULL); if (!_filename) { goto error; } *filename = strdup(_filename); bt_dwarf_die_destroy(cu_die); g_free(file_attr); return 0; error: bt_dwarf_die_destroy(cu_die); g_free(file_attr); return -1; }
/** * die_get_call_file - Get callsite file name of inlined function instance * @in_die: a DIE of an inlined function instance * * Get call-site file name of @in_die. This means from which file the inline * function is called. */ const char *die_get_call_file(Dwarf_Die *in_die) { Dwarf_Die cu_die; Dwarf_Files *files; int idx; idx = die_get_call_fileno(in_die); if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) || dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) return NULL; return dwarf_filesrc(files, idx, NULL, NULL); }
/** * cu_find_realpath - Find the realpath of the target file * @cu_die: A DIE(dwarf information entry) of CU(compilation Unit) * @fname: The tail filename of the target file * * Find the real(long) path of @fname in @cu_die. */ const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) { Dwarf_Files *files; size_t nfiles, i; const char *src = NULL; int ret; if (!fname) return NULL; ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); if (ret != 0) return NULL; for (i = 0; i < nfiles; i++) { src = dwarf_filesrc(files, i, NULL, NULL); if (strtailcmp(src, fname) == 0) break; } if (i == nfiles) return NULL; return src; }
static struct frame* unwind_thread(Dwfl *dwfl, unw_addr_space_t as, struct UCD_info *ui, int thread_no, struct expr_context *ctx) { info("thread %d:", thread_no); int i, ret; unw_cursor_t c, c_cfa; _UCD_select_thread(ui, thread_no); ret = unw_init_remote(&c, as, ui); fail_if(ret < 0, "unw_init_remote"); ret = unw_init_remote(&c_cfa, as, ui); fail_if(ret < 0, "unw_init_remote"); struct frame *head = NULL, *tail = NULL; /* infinite loop insurance */ int count = 1000; while (--count > 0) { unw_word_t ip; ret = unw_get_reg(&c, UNW_REG_IP, &ip); fail_if(ret < 0, "unw_get_reg"); if (ip == 0) break; unw_word_t off; char funcname[10*1024]; funcname[0] = '\0'; ret = unw_get_proc_name(&c, funcname, sizeof(funcname)-1, &off); if (ret < 0) { warn("unw_get_proc_name failed for IP %lx", (unsigned long)ip); } info("\t%llx %s", (unsigned long long)ip, funcname); /* According to spec[1], CFA is RSP of the previous frame. However, * libunwind returns CFA = RSP of the current frame. So we need to keep * track of the previous (i.e. next to be unwound) frame. * * [1] System V Application Binary Interface AMD64 Architecture * Processor Supplement * http://www.x86-64.org/documentation/abi.pdf */ ctx->cfa = 0; ret = unw_step(&c_cfa); if (ret > 0) { unw_word_t cfa; ret = unw_get_reg(&c_cfa, UNW_X86_64_CFA, &cfa); if (ret == 0) { ctx->cfa = (Dwarf_Addr)cfa; } } /* find compilation unit owning the IP */ Dwarf_Die *cu = dwfl_addrdie(dwfl, (Dwarf_Addr)ip, &(ctx->bias)); if (!cu) { warn("\t\tcannot find CU for ip %lx", (unsigned long)ip); goto synth_frame; } if (!supported_language(cu)) { warn("\t\tunsupported CU language"); goto synth_frame; } /* needed by child_variables */ Dwarf_Files *files; ret = dwarf_getsrcfiles(cu, &files, NULL); fail_if(ret == -1, "dwarf_getsrcfiles"); /* dwarf expression evaluation needs register values */ ctx->curs = &c; ctx->ip = (Dwarf_Addr)ip; /* TODO: subtract 1 as this is return address? */ /* TODO: we have CU - fall back to CU name if subprogram not found */ /* Following code deals with inlined functions, which do not have their * own stack frame. It is somewhat ugly due to two constraints: * - we want to produce at least one frame even if analyze_scopes * fails * - we may want to further process the frame that is returned the * last, i.e. the one that belongs to the non-inlined function */ Dwarf_Die *scopes; int nscopes = dwarf_getscopes(cu, (Dwarf_Addr)ip, &scopes); struct frame *frame = analyze_scopes(&scopes, &nscopes, ctx, files, false); if (frame == NULL) { goto synth_frame; } struct frame *last_frame; while (frame) { list_append(head, tail, frame); last_frame = frame; frame = analyze_scopes(&scopes, &nscopes, ctx, files, true); } frame = last_frame; /* frame->ip = (uint64_t)ip; */ goto next; synth_frame: /* synthesize frame even though we have no other information except * that it's there */ frame = xalloc(sizeof(*frame)); list_append(head, tail, frame); /* frame->ip = (uint64_t)ip; */ next: ret = unw_step(&c); fail_if(ret < 0, "unw_step"); if (ret == 0) break; } return head; }
int main (int argc, char *argv[]) { int result = 0; int cnt; for (cnt = 1; cnt < argc; ++cnt) { int fd = open (argv[cnt], O_RDONLY); Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); if (dbg == NULL) { printf ("%s not usable\n", argv[cnt]); result = 1; if (fd != -1) close (fd); continue; } Dwarf_Off o = 0; Dwarf_Off ncu; Dwarf_Off ao; size_t cuhl; uint8_t asz; uint8_t osz; while (dwarf_nextcu (dbg, o, &ncu, &cuhl, &ao, &asz, &osz) == 0) { printf ("cuhl = %zu, o = %llu, asz = %hhu, osz = %hhu, ncu = %llu\n", cuhl, (unsigned long long int) ao, asz, osz, (unsigned long long int) ncu); Dwarf_Die die_mem; Dwarf_Die *die = dwarf_offdie (dbg, o + cuhl, &die_mem); if (die == NULL) { printf ("%s: cannot get CU die\n", argv[cnt]); result = 1; break; } Dwarf_Files *files; size_t nfiles; if (dwarf_getsrcfiles (die, &files, &nfiles) != 0) { printf ("%s: cannot get files\n", argv[cnt]); result = 1; break; } for (int i = 0; i < nfiles; ++i) printf (" file[%d] = \"%s\"\n", i, dwarf_filesrc (files, i, NULL, NULL)); o = ncu; } dwarf_end (dbg); close (fd); } return result; }
static int process_cu (Dwarf_Die *cu_die) { Dwarf_Attribute attr; const char *name; const char *dir = NULL; Dwarf_Files *files; size_t n; int i; if (dwarf_tag (cu_die) != DW_TAG_compile_unit) { fprintf (stderr, "DIE isn't a compile unit"); return -1; } if (dwarf_attr (cu_die, DW_AT_name, &attr) == NULL) { fprintf(stderr, "CU doesn't have a DW_AT_name"); return -1; } name = dwarf_formstring (&attr); if (name == NULL) { fprintf(stderr, "Couldn't get DW_AT_name as string, %s", dwarf_errmsg (-1)); return -1; } if (dwarf_attr (cu_die, DW_AT_comp_dir, &attr) != NULL) { dir = dwarf_formstring (&attr); if (dir == NULL) { fprintf(stderr, "Couldn't get DW_AT_comp_die as string, %s", dwarf_errmsg (-1)); return -1; } } if (dir == NULL) printf ("%s\n", name); else printf ("%s/%s\n", dir, name); if (dwarf_getsrcfiles (cu_die, &files, &n) != 0) { fprintf(stderr, "Couldn't get CU file table, %s", dwarf_errmsg (-1)); return -1; } for (i = 1; i < n; i++) { const char *file = dwarf_filesrc (files, i, NULL, NULL); if (dir != NULL && file[0] != '/') printf ("\t%s/%s\n", dir, file); else printf ("\t%s\n", file); } return 0; }