|
@@ -43,21 +43,6 @@
|
|
/* Kprobe tracer basic type is up to u64 */
|
|
/* Kprobe tracer basic type is up to u64 */
|
|
#define MAX_BASIC_TYPE_BITS 64
|
|
#define MAX_BASIC_TYPE_BITS 64
|
|
|
|
|
|
-/*
|
|
|
|
- * Compare the tail of two strings.
|
|
|
|
- * Return 0 if whole of either string is same as another's tail part.
|
|
|
|
- */
|
|
|
|
-static int strtailcmp(const char *s1, const char *s2)
|
|
|
|
-{
|
|
|
|
- int i1 = strlen(s1);
|
|
|
|
- int i2 = strlen(s2);
|
|
|
|
- while (--i1 >= 0 && --i2 >= 0) {
|
|
|
|
- if (s1[i1] != s2[i2])
|
|
|
|
- return s1[i1] - s2[i2];
|
|
|
|
- }
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/* Line number list operations */
|
|
/* Line number list operations */
|
|
|
|
|
|
/* Add a line to line number list */
|
|
/* Add a line to line number list */
|
|
@@ -131,29 +116,37 @@ static const Dwfl_Callbacks offline_callbacks = {
|
|
};
|
|
};
|
|
|
|
|
|
/* Get a Dwarf from offline image */
|
|
/* Get a Dwarf from offline image */
|
|
-static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
|
|
|
|
|
|
+static int debuginfo__init_offline_dwarf(struct debuginfo *self,
|
|
|
|
+ const char *path)
|
|
{
|
|
{
|
|
Dwfl_Module *mod;
|
|
Dwfl_Module *mod;
|
|
- Dwarf *dbg = NULL;
|
|
|
|
|
|
+ int fd;
|
|
|
|
|
|
- if (!dwflp)
|
|
|
|
- return NULL;
|
|
|
|
|
|
+ fd = open(path, O_RDONLY);
|
|
|
|
+ if (fd < 0)
|
|
|
|
+ return fd;
|
|
|
|
|
|
- *dwflp = dwfl_begin(&offline_callbacks);
|
|
|
|
- if (!*dwflp)
|
|
|
|
- return NULL;
|
|
|
|
|
|
+ self->dwfl = dwfl_begin(&offline_callbacks);
|
|
|
|
+ if (!self->dwfl)
|
|
|
|
+ goto error;
|
|
|
|
|
|
- mod = dwfl_report_offline(*dwflp, "", "", fd);
|
|
|
|
|
|
+ mod = dwfl_report_offline(self->dwfl, "", "", fd);
|
|
if (!mod)
|
|
if (!mod)
|
|
goto error;
|
|
goto error;
|
|
|
|
|
|
- dbg = dwfl_module_getdwarf(mod, bias);
|
|
|
|
- if (!dbg) {
|
|
|
|
|
|
+ self->dbg = dwfl_module_getdwarf(mod, &self->bias);
|
|
|
|
+ if (!self->dbg)
|
|
|
|
+ goto error;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
error:
|
|
error:
|
|
- dwfl_end(*dwflp);
|
|
|
|
- *dwflp = NULL;
|
|
|
|
- }
|
|
|
|
- return dbg;
|
|
|
|
|
|
+ if (self->dwfl)
|
|
|
|
+ dwfl_end(self->dwfl);
|
|
|
|
+ else
|
|
|
|
+ close(fd);
|
|
|
|
+ memset(self, 0, sizeof(*self));
|
|
|
|
+
|
|
|
|
+ return -ENOENT;
|
|
}
|
|
}
|
|
|
|
|
|
#if _ELFUTILS_PREREQ(0, 148)
|
|
#if _ELFUTILS_PREREQ(0, 148)
|
|
@@ -189,597 +182,81 @@ static const Dwfl_Callbacks kernel_callbacks = {
|
|
};
|
|
};
|
|
|
|
|
|
/* Get a Dwarf from live kernel image */
|
|
/* Get a Dwarf from live kernel image */
|
|
-static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
|
|
|
|
- Dwarf_Addr *bias)
|
|
|
|
|
|
+static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
|
|
|
|
+ Dwarf_Addr addr)
|
|
{
|
|
{
|
|
- Dwarf *dbg;
|
|
|
|
-
|
|
|
|
- if (!dwflp)
|
|
|
|
- return NULL;
|
|
|
|
-
|
|
|
|
- *dwflp = dwfl_begin(&kernel_callbacks);
|
|
|
|
- if (!*dwflp)
|
|
|
|
- return NULL;
|
|
|
|
|
|
+ self->dwfl = dwfl_begin(&kernel_callbacks);
|
|
|
|
+ if (!self->dwfl)
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
/* Load the kernel dwarves: Don't care the result here */
|
|
/* Load the kernel dwarves: Don't care the result here */
|
|
- dwfl_linux_kernel_report_kernel(*dwflp);
|
|
|
|
- dwfl_linux_kernel_report_modules(*dwflp);
|
|
|
|
|
|
+ dwfl_linux_kernel_report_kernel(self->dwfl);
|
|
|
|
+ dwfl_linux_kernel_report_modules(self->dwfl);
|
|
|
|
|
|
- dbg = dwfl_addrdwarf(*dwflp, addr, bias);
|
|
|
|
|
|
+ self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias);
|
|
/* Here, check whether we could get a real dwarf */
|
|
/* Here, check whether we could get a real dwarf */
|
|
- if (!dbg) {
|
|
|
|
|
|
+ if (!self->dbg) {
|
|
pr_debug("Failed to find kernel dwarf at %lx\n",
|
|
pr_debug("Failed to find kernel dwarf at %lx\n",
|
|
(unsigned long)addr);
|
|
(unsigned long)addr);
|
|
- dwfl_end(*dwflp);
|
|
|
|
- *dwflp = NULL;
|
|
|
|
|
|
+ dwfl_end(self->dwfl);
|
|
|
|
+ memset(self, 0, sizeof(*self));
|
|
|
|
+ return -ENOENT;
|
|
}
|
|
}
|
|
- return dbg;
|
|
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
#else
|
|
#else
|
|
/* With older elfutils, this just support kernel module... */
|
|
/* With older elfutils, this just support kernel module... */
|
|
-static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp,
|
|
|
|
- Dwarf_Addr *bias)
|
|
|
|
|
|
+static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
|
|
|
|
+ Dwarf_Addr addr __used)
|
|
{
|
|
{
|
|
- int fd;
|
|
|
|
const char *path = kernel_get_module_path("kernel");
|
|
const char *path = kernel_get_module_path("kernel");
|
|
|
|
|
|
if (!path) {
|
|
if (!path) {
|
|
pr_err("Failed to find vmlinux path\n");
|
|
pr_err("Failed to find vmlinux path\n");
|
|
- return NULL;
|
|
|
|
|
|
+ return -ENOENT;
|
|
}
|
|
}
|
|
|
|
|
|
pr_debug2("Use file %s for debuginfo\n", path);
|
|
pr_debug2("Use file %s for debuginfo\n", path);
|
|
- fd = open(path, O_RDONLY);
|
|
|
|
- if (fd < 0)
|
|
|
|
- return NULL;
|
|
|
|
-
|
|
|
|
- return dwfl_init_offline_dwarf(fd, dwflp, bias);
|
|
|
|
|
|
+ return debuginfo__init_offline_dwarf(self, path);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-/* Dwarf wrappers */
|
|
|
|
-
|
|
|
|
-/* Find the realpath of the target file. */
|
|
|
|
-static 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;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Get DW_AT_comp_dir (should be NULL with older gcc) */
|
|
|
|
-static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
|
|
|
|
-{
|
|
|
|
- Dwarf_Attribute attr;
|
|
|
|
- if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
|
|
|
|
- return NULL;
|
|
|
|
- return dwarf_formstring(&attr);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Get a line number and file name for given address */
|
|
|
|
-static int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
|
|
|
|
- const char **fname, int *lineno)
|
|
|
|
-{
|
|
|
|
- Dwarf_Line *line;
|
|
|
|
- Dwarf_Addr laddr;
|
|
|
|
-
|
|
|
|
- line = dwarf_getsrc_die(cudie, (Dwarf_Addr)addr);
|
|
|
|
- if (line && dwarf_lineaddr(line, &laddr) == 0 &&
|
|
|
|
- addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) {
|
|
|
|
- *fname = dwarf_linesrc(line, NULL, NULL);
|
|
|
|
- if (!*fname)
|
|
|
|
- /* line number is useless without filename */
|
|
|
|
- *lineno = 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return *lineno ?: -ENOENT;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Compare diename and tname */
|
|
|
|
-static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
|
|
|
|
-{
|
|
|
|
- const char *name;
|
|
|
|
- name = dwarf_diename(dw_die);
|
|
|
|
- return name ? (strcmp(tname, name) == 0) : false;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Get callsite line number of inline-function instance */
|
|
|
|
-static int die_get_call_lineno(Dwarf_Die *in_die)
|
|
|
|
-{
|
|
|
|
- Dwarf_Attribute attr;
|
|
|
|
- Dwarf_Word ret;
|
|
|
|
-
|
|
|
|
- if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
|
|
|
|
- return -ENOENT;
|
|
|
|
-
|
|
|
|
- dwarf_formudata(&attr, &ret);
|
|
|
|
- return (int)ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Get type die */
|
|
|
|
-static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
|
|
|
|
-{
|
|
|
|
- Dwarf_Attribute attr;
|
|
|
|
-
|
|
|
|
- if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
|
|
|
|
- dwarf_formref_die(&attr, die_mem))
|
|
|
|
- return die_mem;
|
|
|
|
- else
|
|
|
|
- return NULL;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Get a type die, but skip qualifiers */
|
|
|
|
-static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
|
|
|
|
-{
|
|
|
|
- int tag;
|
|
|
|
-
|
|
|
|
- do {
|
|
|
|
- vr_die = die_get_type(vr_die, die_mem);
|
|
|
|
- if (!vr_die)
|
|
|
|
- break;
|
|
|
|
- tag = dwarf_tag(vr_die);
|
|
|
|
- } while (tag == DW_TAG_const_type ||
|
|
|
|
- tag == DW_TAG_restrict_type ||
|
|
|
|
- tag == DW_TAG_volatile_type ||
|
|
|
|
- tag == DW_TAG_shared_type);
|
|
|
|
-
|
|
|
|
- return vr_die;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Get a type die, but skip qualifiers and typedef */
|
|
|
|
-static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
|
|
|
|
-{
|
|
|
|
- do {
|
|
|
|
- vr_die = __die_get_real_type(vr_die, die_mem);
|
|
|
|
- } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
|
|
|
|
-
|
|
|
|
- return vr_die;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
|
|
|
|
- Dwarf_Word *result)
|
|
|
|
-{
|
|
|
|
- Dwarf_Attribute attr;
|
|
|
|
-
|
|
|
|
- if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
|
|
|
|
- dwarf_formudata(&attr, result) != 0)
|
|
|
|
- return -ENOENT;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static bool die_is_signed_type(Dwarf_Die *tp_die)
|
|
|
|
-{
|
|
|
|
- Dwarf_Word ret;
|
|
|
|
-
|
|
|
|
- if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
|
|
|
|
- return false;
|
|
|
|
-
|
|
|
|
- return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
|
|
|
|
- ret == DW_ATE_signed_fixed);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int die_get_byte_size(Dwarf_Die *tp_die)
|
|
|
|
-{
|
|
|
|
- Dwarf_Word ret;
|
|
|
|
-
|
|
|
|
- if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret))
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- return (int)ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int die_get_bit_size(Dwarf_Die *tp_die)
|
|
|
|
-{
|
|
|
|
- Dwarf_Word ret;
|
|
|
|
-
|
|
|
|
- if (die_get_attr_udata(tp_die, DW_AT_bit_size, &ret))
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- return (int)ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int die_get_bit_offset(Dwarf_Die *tp_die)
|
|
|
|
-{
|
|
|
|
- Dwarf_Word ret;
|
|
|
|
-
|
|
|
|
- if (die_get_attr_udata(tp_die, DW_AT_bit_offset, &ret))
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- return (int)ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Get data_member_location offset */
|
|
|
|
-static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
|
|
|
|
-{
|
|
|
|
- Dwarf_Attribute attr;
|
|
|
|
- Dwarf_Op *expr;
|
|
|
|
- size_t nexpr;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
|
|
|
|
- return -ENOENT;
|
|
|
|
-
|
|
|
|
- if (dwarf_formudata(&attr, offs) != 0) {
|
|
|
|
- /* DW_AT_data_member_location should be DW_OP_plus_uconst */
|
|
|
|
- ret = dwarf_getlocation(&attr, &expr, &nexpr);
|
|
|
|
- if (ret < 0 || nexpr == 0)
|
|
|
|
- return -ENOENT;
|
|
|
|
-
|
|
|
|
- if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
|
|
|
|
- pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
|
|
|
|
- expr[0].atom, nexpr);
|
|
|
|
- return -ENOTSUP;
|
|
|
|
- }
|
|
|
|
- *offs = (Dwarf_Word)expr[0].number;
|
|
|
|
- }
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Return values for die_find callbacks */
|
|
|
|
-enum {
|
|
|
|
- DIE_FIND_CB_FOUND = 0, /* End of Search */
|
|
|
|
- DIE_FIND_CB_CHILD = 1, /* Search only children */
|
|
|
|
- DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
|
|
|
|
- DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-/* Search a child die */
|
|
|
|
-static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
|
|
|
|
- int (*callback)(Dwarf_Die *, void *),
|
|
|
|
- void *data, Dwarf_Die *die_mem)
|
|
|
|
|
|
+struct debuginfo *debuginfo__new(const char *path)
|
|
{
|
|
{
|
|
- Dwarf_Die child_die;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- ret = dwarf_child(rt_die, die_mem);
|
|
|
|
- if (ret != 0)
|
|
|
|
|
|
+ struct debuginfo *self = zalloc(sizeof(struct debuginfo));
|
|
|
|
+ if (!self)
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
- do {
|
|
|
|
- ret = callback(die_mem, data);
|
|
|
|
- if (ret == DIE_FIND_CB_FOUND)
|
|
|
|
- return die_mem;
|
|
|
|
-
|
|
|
|
- if ((ret & DIE_FIND_CB_CHILD) &&
|
|
|
|
- die_find_child(die_mem, callback, data, &child_die)) {
|
|
|
|
- memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
|
|
|
|
- return die_mem;
|
|
|
|
- }
|
|
|
|
- } while ((ret & DIE_FIND_CB_SIBLING) &&
|
|
|
|
- dwarf_siblingof(die_mem, die_mem) == 0);
|
|
|
|
-
|
|
|
|
- return NULL;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-struct __addr_die_search_param {
|
|
|
|
- Dwarf_Addr addr;
|
|
|
|
- Dwarf_Die *die_mem;
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
|
|
|
|
-{
|
|
|
|
- struct __addr_die_search_param *ad = data;
|
|
|
|
-
|
|
|
|
- if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
|
|
|
|
- dwarf_haspc(fn_die, ad->addr)) {
|
|
|
|
- memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
|
|
|
|
- return DWARF_CB_ABORT;
|
|
|
|
|
|
+ if (debuginfo__init_offline_dwarf(self, path) < 0) {
|
|
|
|
+ free(self);
|
|
|
|
+ self = NULL;
|
|
}
|
|
}
|
|
- return DWARF_CB_OK;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Search a real subprogram including this line, */
|
|
|
|
-static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
|
|
|
|
- Dwarf_Die *die_mem)
|
|
|
|
-{
|
|
|
|
- struct __addr_die_search_param ad;
|
|
|
|
- ad.addr = addr;
|
|
|
|
- ad.die_mem = die_mem;
|
|
|
|
- /* dwarf_getscopes can't find subprogram. */
|
|
|
|
- if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
|
|
|
|
- return NULL;
|
|
|
|
- else
|
|
|
|
- return die_mem;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* die_find callback for inline function search */
|
|
|
|
-static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
|
|
|
|
-{
|
|
|
|
- Dwarf_Addr *addr = data;
|
|
|
|
-
|
|
|
|
- if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
|
|
|
|
- dwarf_haspc(die_mem, *addr))
|
|
|
|
- return DIE_FIND_CB_FOUND;
|
|
|
|
|
|
|
|
- return DIE_FIND_CB_CONTINUE;
|
|
|
|
|
|
+ return self;
|
|
}
|
|
}
|
|
|
|
|
|
-/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
|
|
|
|
-static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
|
|
|
|
- Dwarf_Die *die_mem)
|
|
|
|
|
|
+struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
|
|
{
|
|
{
|
|
- Dwarf_Die tmp_die;
|
|
|
|
-
|
|
|
|
- sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die);
|
|
|
|
- if (!sp_die)
|
|
|
|
|
|
+ struct debuginfo *self = zalloc(sizeof(struct debuginfo));
|
|
|
|
+ if (!self)
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
- /* Inlined function could be recursive. Trace it until fail */
|
|
|
|
- while (sp_die) {
|
|
|
|
- memcpy(die_mem, sp_die, sizeof(Dwarf_Die));
|
|
|
|
- sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr,
|
|
|
|
- &tmp_die);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return die_mem;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Walker on lines (Note: line number will not be sorted) */
|
|
|
|
-typedef int (* line_walk_handler_t) (const char *fname, int lineno,
|
|
|
|
- Dwarf_Addr addr, void *data);
|
|
|
|
-
|
|
|
|
-struct __line_walk_param {
|
|
|
|
- const char *fname;
|
|
|
|
- line_walk_handler_t handler;
|
|
|
|
- void *data;
|
|
|
|
- int retval;
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
|
|
|
|
-{
|
|
|
|
- struct __line_walk_param *lw = data;
|
|
|
|
- Dwarf_Addr addr;
|
|
|
|
- int lineno;
|
|
|
|
-
|
|
|
|
- if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
|
|
|
|
- lineno = die_get_call_lineno(in_die);
|
|
|
|
- if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
|
|
|
|
- lw->retval = lw->handler(lw->fname, lineno, addr,
|
|
|
|
- lw->data);
|
|
|
|
- if (lw->retval != 0)
|
|
|
|
- return DIE_FIND_CB_FOUND;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return DIE_FIND_CB_SIBLING;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Walk on lines of blocks included in given DIE */
|
|
|
|
-static int __die_walk_funclines(Dwarf_Die *sp_die,
|
|
|
|
- line_walk_handler_t handler, void *data)
|
|
|
|
-{
|
|
|
|
- struct __line_walk_param lw = {
|
|
|
|
- .handler = handler,
|
|
|
|
- .data = data,
|
|
|
|
- .retval = 0,
|
|
|
|
- };
|
|
|
|
- Dwarf_Die die_mem;
|
|
|
|
- Dwarf_Addr addr;
|
|
|
|
- int lineno;
|
|
|
|
-
|
|
|
|
- /* Handle function declaration line */
|
|
|
|
- lw.fname = dwarf_decl_file(sp_die);
|
|
|
|
- if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
|
|
|
|
- dwarf_entrypc(sp_die, &addr) == 0) {
|
|
|
|
- lw.retval = handler(lw.fname, lineno, addr, data);
|
|
|
|
- if (lw.retval != 0)
|
|
|
|
- goto done;
|
|
|
|
- }
|
|
|
|
- die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
|
|
|
|
-done:
|
|
|
|
- return lw.retval;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
|
|
|
|
-{
|
|
|
|
- struct __line_walk_param *lw = data;
|
|
|
|
-
|
|
|
|
- lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
|
|
|
|
- if (lw->retval != 0)
|
|
|
|
- return DWARF_CB_ABORT;
|
|
|
|
-
|
|
|
|
- return DWARF_CB_OK;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
|
|
|
|
- * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
|
|
|
|
- */
|
|
|
|
-static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
|
|
|
|
- void *data)
|
|
|
|
-{
|
|
|
|
- Dwarf_Lines *lines;
|
|
|
|
- Dwarf_Line *line;
|
|
|
|
- Dwarf_Addr addr;
|
|
|
|
- const char *fname;
|
|
|
|
- int lineno, ret = 0;
|
|
|
|
- Dwarf_Die die_mem, *cu_die;
|
|
|
|
- size_t nlines, i;
|
|
|
|
-
|
|
|
|
- /* Get the CU die */
|
|
|
|
- if (dwarf_tag(pdie) == DW_TAG_subprogram)
|
|
|
|
- cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
|
|
|
|
- else
|
|
|
|
- cu_die = pdie;
|
|
|
|
- if (!cu_die) {
|
|
|
|
- pr_debug2("Failed to get CU from subprogram\n");
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Get lines list in the CU */
|
|
|
|
- if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
|
|
|
|
- pr_debug2("Failed to get source lines on this CU.\n");
|
|
|
|
- return -ENOENT;
|
|
|
|
- }
|
|
|
|
- pr_debug2("Get %zd lines from this CU\n", nlines);
|
|
|
|
-
|
|
|
|
- /* Walk on the lines on lines list */
|
|
|
|
- for (i = 0; i < nlines; i++) {
|
|
|
|
- line = dwarf_onesrcline(lines, i);
|
|
|
|
- if (line == NULL ||
|
|
|
|
- dwarf_lineno(line, &lineno) != 0 ||
|
|
|
|
- dwarf_lineaddr(line, &addr) != 0) {
|
|
|
|
- pr_debug2("Failed to get line info. "
|
|
|
|
- "Possible error in debuginfo.\n");
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- /* Filter lines based on address */
|
|
|
|
- if (pdie != cu_die)
|
|
|
|
- /*
|
|
|
|
- * Address filtering
|
|
|
|
- * The line is included in given function, and
|
|
|
|
- * no inline block includes it.
|
|
|
|
- */
|
|
|
|
- if (!dwarf_haspc(pdie, addr) ||
|
|
|
|
- die_find_inlinefunc(pdie, addr, &die_mem))
|
|
|
|
- continue;
|
|
|
|
- /* Get source line */
|
|
|
|
- fname = dwarf_linesrc(line, NULL, NULL);
|
|
|
|
-
|
|
|
|
- ret = handler(fname, lineno, addr, data);
|
|
|
|
- if (ret != 0)
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Dwarf lines doesn't include function declarations and inlined
|
|
|
|
- * subroutines. We have to check functions list or given function.
|
|
|
|
- */
|
|
|
|
- if (pdie != cu_die)
|
|
|
|
- ret = __die_walk_funclines(pdie, handler, data);
|
|
|
|
- else {
|
|
|
|
- struct __line_walk_param param = {
|
|
|
|
- .handler = handler,
|
|
|
|
- .data = data,
|
|
|
|
- .retval = 0,
|
|
|
|
- };
|
|
|
|
- dwarf_getfuncs(cu_die, __die_walk_culines_cb, ¶m, 0);
|
|
|
|
- ret = param.retval;
|
|
|
|
|
|
+ if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) {
|
|
|
|
+ free(self);
|
|
|
|
+ self = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-struct __find_variable_param {
|
|
|
|
- const char *name;
|
|
|
|
- Dwarf_Addr addr;
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
|
|
|
|
-{
|
|
|
|
- struct __find_variable_param *fvp = data;
|
|
|
|
- int tag;
|
|
|
|
-
|
|
|
|
- tag = dwarf_tag(die_mem);
|
|
|
|
- if ((tag == DW_TAG_formal_parameter ||
|
|
|
|
- tag == DW_TAG_variable) &&
|
|
|
|
- die_compare_name(die_mem, fvp->name))
|
|
|
|
- return DIE_FIND_CB_FOUND;
|
|
|
|
-
|
|
|
|
- if (dwarf_haspc(die_mem, fvp->addr))
|
|
|
|
- return DIE_FIND_CB_CONTINUE;
|
|
|
|
- else
|
|
|
|
- return DIE_FIND_CB_SIBLING;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Find a variable called 'name' at given address */
|
|
|
|
-static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
|
|
|
|
- Dwarf_Addr addr, Dwarf_Die *die_mem)
|
|
|
|
-{
|
|
|
|
- struct __find_variable_param fvp = { .name = name, .addr = addr};
|
|
|
|
-
|
|
|
|
- return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
|
|
|
|
- die_mem);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
|
|
|
|
-{
|
|
|
|
- const char *name = data;
|
|
|
|
-
|
|
|
|
- if ((dwarf_tag(die_mem) == DW_TAG_member) &&
|
|
|
|
- die_compare_name(die_mem, name))
|
|
|
|
- return DIE_FIND_CB_FOUND;
|
|
|
|
-
|
|
|
|
- return DIE_FIND_CB_SIBLING;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Find a member called 'name' */
|
|
|
|
-static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
|
|
|
|
- Dwarf_Die *die_mem)
|
|
|
|
-{
|
|
|
|
- return die_find_child(st_die, __die_find_member_cb, (void *)name,
|
|
|
|
- die_mem);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Get the name of given variable DIE */
|
|
|
|
-static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
|
|
|
|
-{
|
|
|
|
- Dwarf_Die type;
|
|
|
|
- int tag, ret, ret2;
|
|
|
|
- const char *tmp = "";
|
|
|
|
-
|
|
|
|
- if (__die_get_real_type(vr_die, &type) == NULL)
|
|
|
|
- return -ENOENT;
|
|
|
|
-
|
|
|
|
- tag = dwarf_tag(&type);
|
|
|
|
- if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
|
|
|
|
- tmp = "*";
|
|
|
|
- else if (tag == DW_TAG_subroutine_type) {
|
|
|
|
- /* Function pointer */
|
|
|
|
- ret = snprintf(buf, len, "(function_type)");
|
|
|
|
- return (ret >= len) ? -E2BIG : ret;
|
|
|
|
- } else {
|
|
|
|
- if (!dwarf_diename(&type))
|
|
|
|
- return -ENOENT;
|
|
|
|
- if (tag == DW_TAG_union_type)
|
|
|
|
- tmp = "union ";
|
|
|
|
- else if (tag == DW_TAG_structure_type)
|
|
|
|
- tmp = "struct ";
|
|
|
|
- /* Write a base name */
|
|
|
|
- ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
|
|
|
|
- return (ret >= len) ? -E2BIG : ret;
|
|
|
|
- }
|
|
|
|
- ret = die_get_typename(&type, buf, len);
|
|
|
|
- if (ret > 0) {
|
|
|
|
- ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
|
|
|
|
- ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
|
|
|
|
- }
|
|
|
|
- return ret;
|
|
|
|
|
|
+ return self;
|
|
}
|
|
}
|
|
|
|
|
|
-/* Get the name and type of given variable DIE, stored as "type\tname" */
|
|
|
|
-static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
|
|
|
|
|
|
+void debuginfo__delete(struct debuginfo *self)
|
|
{
|
|
{
|
|
- int ret, ret2;
|
|
|
|
-
|
|
|
|
- ret = die_get_typename(vr_die, buf, len);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- pr_debug("Failed to get type, make it unknown.\n");
|
|
|
|
- ret = snprintf(buf, len, "(unknown_type)");
|
|
|
|
|
|
+ if (self) {
|
|
|
|
+ if (self->dwfl)
|
|
|
|
+ dwfl_end(self->dwfl);
|
|
|
|
+ free(self);
|
|
}
|
|
}
|
|
- if (ret > 0) {
|
|
|
|
- ret2 = snprintf(buf + ret, len - ret, "\t%s",
|
|
|
|
- dwarf_diename(vr_die));
|
|
|
|
- ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
|
|
|
|
- }
|
|
|
|
- return ret;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -897,6 +374,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
|
|
struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
|
|
struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
|
|
Dwarf_Die type;
|
|
Dwarf_Die type;
|
|
char buf[16];
|
|
char buf[16];
|
|
|
|
+ int bsize, boffs, total;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
/* TODO: check all types */
|
|
/* TODO: check all types */
|
|
@@ -906,11 +384,15 @@ static int convert_variable_type(Dwarf_Die *vr_die,
|
|
return (tvar->type == NULL) ? -ENOMEM : 0;
|
|
return (tvar->type == NULL) ? -ENOMEM : 0;
|
|
}
|
|
}
|
|
|
|
|
|
- if (die_get_bit_size(vr_die) != 0) {
|
|
|
|
|
|
+ bsize = dwarf_bitsize(vr_die);
|
|
|
|
+ if (bsize > 0) {
|
|
/* This is a bitfield */
|
|
/* This is a bitfield */
|
|
- ret = snprintf(buf, 16, "b%d@%d/%zd", die_get_bit_size(vr_die),
|
|
|
|
- die_get_bit_offset(vr_die),
|
|
|
|
- BYTES_TO_BITS(die_get_byte_size(vr_die)));
|
|
|
|
|
|
+ boffs = dwarf_bitoffset(vr_die);
|
|
|
|
+ total = dwarf_bytesize(vr_die);
|
|
|
|
+ if (boffs < 0 || total < 0)
|
|
|
|
+ return -ENOENT;
|
|
|
|
+ ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs,
|
|
|
|
+ BYTES_TO_BITS(total));
|
|
goto formatted;
|
|
goto formatted;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -958,10 +440,11 @@ static int convert_variable_type(Dwarf_Die *vr_die,
|
|
return (tvar->type == NULL) ? -ENOMEM : 0;
|
|
return (tvar->type == NULL) ? -ENOMEM : 0;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = BYTES_TO_BITS(die_get_byte_size(&type));
|
|
|
|
- if (!ret)
|
|
|
|
|
|
+ ret = dwarf_bytesize(&type);
|
|
|
|
+ if (ret <= 0)
|
|
/* No size ... try to use default type */
|
|
/* No size ... try to use default type */
|
|
return 0;
|
|
return 0;
|
|
|
|
+ ret = BYTES_TO_BITS(ret);
|
|
|
|
|
|
/* Check the bitwidth */
|
|
/* Check the bitwidth */
|
|
if (ret > MAX_BASIC_TYPE_BITS) {
|
|
if (ret > MAX_BASIC_TYPE_BITS) {
|
|
@@ -1025,7 +508,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
|
|
else
|
|
else
|
|
*ref_ptr = ref;
|
|
*ref_ptr = ref;
|
|
}
|
|
}
|
|
- ref->offset += die_get_byte_size(&type) * field->index;
|
|
|
|
|
|
+ ref->offset += dwarf_bytesize(&type) * field->index;
|
|
if (!field->next)
|
|
if (!field->next)
|
|
/* Save vr_die for converting types */
|
|
/* Save vr_die for converting types */
|
|
memcpy(die_mem, vr_die, sizeof(*die_mem));
|
|
memcpy(die_mem, vr_die, sizeof(*die_mem));
|
|
@@ -1245,8 +728,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
|
|
|
|
|
|
/* If no real subprogram, find a real one */
|
|
/* If no real subprogram, find a real one */
|
|
if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
|
|
if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
|
|
- sp_die = die_find_real_subprogram(&pf->cu_die,
|
|
|
|
- pf->addr, &die_mem);
|
|
|
|
|
|
+ sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem);
|
|
if (!sp_die) {
|
|
if (!sp_die) {
|
|
pr_warning("Failed to find probe point in any "
|
|
pr_warning("Failed to find probe point in any "
|
|
"functions.\n");
|
|
"functions.\n");
|
|
@@ -1504,28 +986,18 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
|
|
}
|
|
}
|
|
|
|
|
|
/* Find probe points from debuginfo */
|
|
/* Find probe points from debuginfo */
|
|
-static int find_probes(int fd, struct probe_finder *pf)
|
|
|
|
|
|
+static int debuginfo__find_probes(struct debuginfo *self,
|
|
|
|
+ struct probe_finder *pf)
|
|
{
|
|
{
|
|
struct perf_probe_point *pp = &pf->pev->point;
|
|
struct perf_probe_point *pp = &pf->pev->point;
|
|
Dwarf_Off off, noff;
|
|
Dwarf_Off off, noff;
|
|
size_t cuhl;
|
|
size_t cuhl;
|
|
Dwarf_Die *diep;
|
|
Dwarf_Die *diep;
|
|
- Dwarf *dbg = NULL;
|
|
|
|
- Dwfl *dwfl;
|
|
|
|
- Dwarf_Addr bias; /* Currently ignored */
|
|
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
- dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
|
|
|
|
- if (!dbg) {
|
|
|
|
- pr_warning("No debug information found in the vmlinux - "
|
|
|
|
- "please rebuild with CONFIG_DEBUG_INFO=y.\n");
|
|
|
|
- close(fd); /* Without dwfl_end(), fd isn't closed. */
|
|
|
|
- return -EBADF;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
#if _ELFUTILS_PREREQ(0, 142)
|
|
#if _ELFUTILS_PREREQ(0, 142)
|
|
/* Get the call frame information from this dwarf */
|
|
/* Get the call frame information from this dwarf */
|
|
- pf->cfi = dwarf_getcfi(dbg);
|
|
|
|
|
|
+ pf->cfi = dwarf_getcfi(self->dbg);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
off = 0;
|
|
off = 0;
|
|
@@ -1544,7 +1016,8 @@ static int find_probes(int fd, struct probe_finder *pf)
|
|
.data = pf,
|
|
.data = pf,
|
|
};
|
|
};
|
|
|
|
|
|
- dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0);
|
|
|
|
|
|
+ dwarf_getpubnames(self->dbg, pubname_search_cb,
|
|
|
|
+ &pubname_param, 0);
|
|
if (pubname_param.found) {
|
|
if (pubname_param.found) {
|
|
ret = probe_point_search_cb(&pf->sp_die, &probe_param);
|
|
ret = probe_point_search_cb(&pf->sp_die, &probe_param);
|
|
if (ret)
|
|
if (ret)
|
|
@@ -1553,9 +1026,9 @@ static int find_probes(int fd, struct probe_finder *pf)
|
|
}
|
|
}
|
|
|
|
|
|
/* Loop on CUs (Compilation Unit) */
|
|
/* Loop on CUs (Compilation Unit) */
|
|
- while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
|
|
|
|
|
|
+ while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
|
|
/* Get the DIE(Debugging Information Entry) of this CU */
|
|
/* Get the DIE(Debugging Information Entry) of this CU */
|
|
- diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
|
|
|
|
|
|
+ diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die);
|
|
if (!diep)
|
|
if (!diep)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
@@ -1582,8 +1055,6 @@ static int find_probes(int fd, struct probe_finder *pf)
|
|
|
|
|
|
found:
|
|
found:
|
|
line_list__free(&pf->lcache);
|
|
line_list__free(&pf->lcache);
|
|
- if (dwfl)
|
|
|
|
- dwfl_end(dwfl);
|
|
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -1629,8 +1100,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
|
|
}
|
|
}
|
|
|
|
|
|
/* Find probe_trace_events specified by perf_probe_event from debuginfo */
|
|
/* Find probe_trace_events specified by perf_probe_event from debuginfo */
|
|
-int find_probe_trace_events(int fd, struct perf_probe_event *pev,
|
|
|
|
- struct probe_trace_event **tevs, int max_tevs)
|
|
|
|
|
|
+int debuginfo__find_trace_events(struct debuginfo *self,
|
|
|
|
+ struct perf_probe_event *pev,
|
|
|
|
+ struct probe_trace_event **tevs, int max_tevs)
|
|
{
|
|
{
|
|
struct trace_event_finder tf = {
|
|
struct trace_event_finder tf = {
|
|
.pf = {.pev = pev, .callback = add_probe_trace_event},
|
|
.pf = {.pev = pev, .callback = add_probe_trace_event},
|
|
@@ -1645,7 +1117,7 @@ int find_probe_trace_events(int fd, struct perf_probe_event *pev,
|
|
tf.tevs = *tevs;
|
|
tf.tevs = *tevs;
|
|
tf.ntevs = 0;
|
|
tf.ntevs = 0;
|
|
|
|
|
|
- ret = find_probes(fd, &tf.pf);
|
|
|
|
|
|
+ ret = debuginfo__find_probes(self, &tf.pf);
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
free(*tevs);
|
|
free(*tevs);
|
|
*tevs = NULL;
|
|
*tevs = NULL;
|
|
@@ -1739,9 +1211,10 @@ out:
|
|
}
|
|
}
|
|
|
|
|
|
/* Find available variables at given probe point */
|
|
/* Find available variables at given probe point */
|
|
-int find_available_vars_at(int fd, struct perf_probe_event *pev,
|
|
|
|
- struct variable_list **vls, int max_vls,
|
|
|
|
- bool externs)
|
|
|
|
|
|
+int debuginfo__find_available_vars_at(struct debuginfo *self,
|
|
|
|
+ struct perf_probe_event *pev,
|
|
|
|
+ struct variable_list **vls,
|
|
|
|
+ int max_vls, bool externs)
|
|
{
|
|
{
|
|
struct available_var_finder af = {
|
|
struct available_var_finder af = {
|
|
.pf = {.pev = pev, .callback = add_available_vars},
|
|
.pf = {.pev = pev, .callback = add_available_vars},
|
|
@@ -1756,7 +1229,7 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev,
|
|
af.vls = *vls;
|
|
af.vls = *vls;
|
|
af.nvls = 0;
|
|
af.nvls = 0;
|
|
|
|
|
|
- ret = find_probes(fd, &af.pf);
|
|
|
|
|
|
+ ret = debuginfo__find_probes(self, &af.pf);
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
/* Free vlist for error */
|
|
/* Free vlist for error */
|
|
while (af.nvls--) {
|
|
while (af.nvls--) {
|
|
@@ -1774,28 +1247,19 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev,
|
|
}
|
|
}
|
|
|
|
|
|
/* Reverse search */
|
|
/* Reverse search */
|
|
-int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
|
|
|
|
|
|
+int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
|
|
|
|
+ struct perf_probe_point *ppt)
|
|
{
|
|
{
|
|
Dwarf_Die cudie, spdie, indie;
|
|
Dwarf_Die cudie, spdie, indie;
|
|
- Dwarf *dbg = NULL;
|
|
|
|
- Dwfl *dwfl = NULL;
|
|
|
|
- Dwarf_Addr _addr, baseaddr, bias = 0;
|
|
|
|
|
|
+ Dwarf_Addr _addr, baseaddr;
|
|
const char *fname = NULL, *func = NULL, *tmp;
|
|
const char *fname = NULL, *func = NULL, *tmp;
|
|
int baseline = 0, lineno = 0, ret = 0;
|
|
int baseline = 0, lineno = 0, ret = 0;
|
|
|
|
|
|
- /* Open the live linux kernel */
|
|
|
|
- dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
|
|
|
|
- if (!dbg) {
|
|
|
|
- pr_warning("No debug information found in the vmlinux - "
|
|
|
|
- "please rebuild with CONFIG_DEBUG_INFO=y.\n");
|
|
|
|
- ret = -EINVAL;
|
|
|
|
- goto end;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/* Adjust address with bias */
|
|
/* Adjust address with bias */
|
|
- addr += bias;
|
|
|
|
|
|
+ addr += self->bias;
|
|
|
|
+
|
|
/* Find cu die */
|
|
/* Find cu die */
|
|
- if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
|
|
|
|
|
|
+ if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) {
|
|
pr_warning("Failed to find debug information for address %lx\n",
|
|
pr_warning("Failed to find debug information for address %lx\n",
|
|
addr);
|
|
addr);
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
@@ -1807,7 +1271,7 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
|
|
/* Don't care whether it failed or not */
|
|
/* Don't care whether it failed or not */
|
|
|
|
|
|
/* Find a corresponding function (name, baseline and baseaddr) */
|
|
/* Find a corresponding function (name, baseline and baseaddr) */
|
|
- if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
|
|
|
|
|
|
+ if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) {
|
|
/* Get function entry information */
|
|
/* Get function entry information */
|
|
tmp = dwarf_diename(&spdie);
|
|
tmp = dwarf_diename(&spdie);
|
|
if (!tmp ||
|
|
if (!tmp ||
|
|
@@ -1871,8 +1335,6 @@ post:
|
|
}
|
|
}
|
|
}
|
|
}
|
|
end:
|
|
end:
|
|
- if (dwfl)
|
|
|
|
- dwfl_end(dwfl);
|
|
|
|
if (ret == 0 && (fname || func))
|
|
if (ret == 0 && (fname || func))
|
|
ret = 1; /* Found a point */
|
|
ret = 1; /* Found a point */
|
|
return ret;
|
|
return ret;
|
|
@@ -1982,26 +1444,15 @@ static int find_line_range_by_func(struct line_finder *lf)
|
|
return param.retval;
|
|
return param.retval;
|
|
}
|
|
}
|
|
|
|
|
|
-int find_line_range(int fd, struct line_range *lr)
|
|
|
|
|
|
+int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr)
|
|
{
|
|
{
|
|
struct line_finder lf = {.lr = lr, .found = 0};
|
|
struct line_finder lf = {.lr = lr, .found = 0};
|
|
int ret = 0;
|
|
int ret = 0;
|
|
Dwarf_Off off = 0, noff;
|
|
Dwarf_Off off = 0, noff;
|
|
size_t cuhl;
|
|
size_t cuhl;
|
|
Dwarf_Die *diep;
|
|
Dwarf_Die *diep;
|
|
- Dwarf *dbg = NULL;
|
|
|
|
- Dwfl *dwfl;
|
|
|
|
- Dwarf_Addr bias; /* Currently ignored */
|
|
|
|
const char *comp_dir;
|
|
const char *comp_dir;
|
|
|
|
|
|
- dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
|
|
|
|
- if (!dbg) {
|
|
|
|
- pr_warning("No debug information found in the vmlinux - "
|
|
|
|
- "please rebuild with CONFIG_DEBUG_INFO=y.\n");
|
|
|
|
- close(fd); /* Without dwfl_end(), fd isn't closed. */
|
|
|
|
- return -EBADF;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/* Fastpath: lookup by function name from .debug_pubnames section */
|
|
/* Fastpath: lookup by function name from .debug_pubnames section */
|
|
if (lr->function) {
|
|
if (lr->function) {
|
|
struct pubname_callback_param pubname_param = {
|
|
struct pubname_callback_param pubname_param = {
|
|
@@ -2010,7 +1461,8 @@ int find_line_range(int fd, struct line_range *lr)
|
|
struct dwarf_callback_param line_range_param = {
|
|
struct dwarf_callback_param line_range_param = {
|
|
.data = (void *)&lf, .retval = 0};
|
|
.data = (void *)&lf, .retval = 0};
|
|
|
|
|
|
- dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0);
|
|
|
|
|
|
+ dwarf_getpubnames(self->dbg, pubname_search_cb,
|
|
|
|
+ &pubname_param, 0);
|
|
if (pubname_param.found) {
|
|
if (pubname_param.found) {
|
|
line_range_search_cb(&lf.sp_die, &line_range_param);
|
|
line_range_search_cb(&lf.sp_die, &line_range_param);
|
|
if (lf.found)
|
|
if (lf.found)
|
|
@@ -2020,11 +1472,12 @@ int find_line_range(int fd, struct line_range *lr)
|
|
|
|
|
|
/* Loop on CUs (Compilation Unit) */
|
|
/* Loop on CUs (Compilation Unit) */
|
|
while (!lf.found && ret >= 0) {
|
|
while (!lf.found && ret >= 0) {
|
|
- if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0)
|
|
|
|
|
|
+ if (dwarf_nextcu(self->dbg, off, &noff, &cuhl,
|
|
|
|
+ NULL, NULL, NULL) != 0)
|
|
break;
|
|
break;
|
|
|
|
|
|
/* Get the DIE(Debugging Information Entry) of this CU */
|
|
/* Get the DIE(Debugging Information Entry) of this CU */
|
|
- diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
|
|
|
|
|
|
+ diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die);
|
|
if (!diep)
|
|
if (!diep)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
@@ -2058,7 +1511,6 @@ found:
|
|
}
|
|
}
|
|
|
|
|
|
pr_debug("path: %s\n", lr->path);
|
|
pr_debug("path: %s\n", lr->path);
|
|
- dwfl_end(dwfl);
|
|
|
|
return (ret < 0) ? ret : lf.found;
|
|
return (ret < 0) ? ret : lf.found;
|
|
}
|
|
}
|
|
|
|
|