summaryrefslogtreecommitdiff
path: root/tools/perf/util/probe-finder.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-07-22 16:44:39 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-22 16:44:39 -0700
commit4d4abdcb1dee03a4f9d6d2021622ed07e14dfd17 (patch)
tree4ed4c74b70240451065165fda5fb2059f8c6b1e5 /tools/perf/util/probe-finder.c
parent0342cbcfced2ee937d7c8e1c63f3d3082da7c7dc (diff)
parent7fcfd1abd6480d3b9ef17f5759c175e036e835cf (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (123 commits) perf: Remove the nmi parameter from the oprofile_perf backend x86, perf: Make copy_from_user_nmi() a library function perf: Remove perf_event_attr::type check x86, perf: P4 PMU - Fix typos in comments and style cleanup perf tools: Make test use the preset debugfs path perf tools: Add automated tests for events parsing perf tools: De-opt the parse_events function perf script: Fix display of IP address for non-callchain path perf tools: Fix endian conversion reading event attr from file header perf tools: Add missing 'node' alias to the hw_cache[] array perf probe: Support adding probes on offline kernel modules perf probe: Add probed module in front of function perf probe: Introduce debuginfo to encapsulate dwarf information perf-probe: Move dwarf library routines to dwarf-aux.{c, h} perf probe: Remove redundant dwarf functions perf probe: Move strtailcmp to string.c perf probe: Rename DIE_FIND_CB_FOUND to DIE_FIND_CB_END tracing/kprobe: Update symbol reference when loading module tracing/kprobes: Support module init function probing kprobes: Return -ENOENT if probe point doesn't exist ...
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r--tools/perf/util/probe-finder.c752
1 files changed, 102 insertions, 650 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 3b9d0b800d5c..3e44a3e36519 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -43,21 +43,6 @@
/* Kprobe tracer basic type is up to u64 */
#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 */
/* Add a line to line number list */
@@ -131,29 +116,37 @@ static const Dwfl_Callbacks offline_callbacks = {
};
/* 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;
- 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)
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:
- 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)
@@ -189,597 +182,81 @@ static const Dwfl_Callbacks kernel_callbacks = {
};
/* 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 */
- 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 */
- if (!dbg) {
+ if (!self->dbg) {
pr_debug("Failed to find kernel dwarf at %lx\n",
(unsigned long)addr);
- dwfl_end(*dwflp);
- *dwflp = NULL;
+ dwfl_end(self->dwfl);
+ memset(self, 0, sizeof(*self));
+ return -ENOENT;
}
- return dbg;
+
+ return 0;
}
#else
/* 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");
if (!path) {
pr_err("Failed to find vmlinux path\n");
- return NULL;
+ return -ENOENT;
}
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
-/* 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;
- 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;
- /* 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, &param, 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;
Dwarf_Die type;
char buf[16];
+ int bsize, boffs, total;
int ret;
/* TODO: check all types */
@@ -906,11 +384,15 @@ static int convert_variable_type(Dwarf_Die *vr_die,
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 */
- 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;
}
@@ -958,10 +440,11 @@ static int convert_variable_type(Dwarf_Die *vr_die,
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 */
return 0;
+ ret = BYTES_TO_BITS(ret);
/* Check the bitwidth */
if (ret > MAX_BASIC_TYPE_BITS) {
@@ -1025,7 +508,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
else
*ref_ptr = ref;
}
- ref->offset += die_get_byte_size(&type) * field->index;
+ ref->offset += dwarf_bytesize(&type) * field->index;
if (!field->next)
/* Save vr_die for converting types */
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 (!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) {
pr_warning("Failed to find probe point in any "
"functions.\n");
@@ -1504,28 +986,18 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
}
/* 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;
Dwarf_Off off, noff;
size_t cuhl;
Dwarf_Die *diep;
- Dwarf *dbg = NULL;
- Dwfl *dwfl;
- Dwarf_Addr bias; /* Currently ignored */
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)
/* Get the call frame information from this dwarf */
- pf->cfi = dwarf_getcfi(dbg);
+ pf->cfi = dwarf_getcfi(self->dbg);
#endif
off = 0;
@@ -1544,7 +1016,8 @@ static int find_probes(int fd, struct probe_finder *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) {
ret = probe_point_search_cb(&pf->sp_die, &probe_param);
if (ret)
@@ -1553,9 +1026,9 @@ static int find_probes(int fd, struct probe_finder *pf)
}
/* 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 */
- diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
+ diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die);
if (!diep)
continue;
@@ -1582,8 +1055,6 @@ static int find_probes(int fd, struct probe_finder *pf)
found:
line_list__free(&pf->lcache);
- if (dwfl)
- dwfl_end(dwfl);
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 */
-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 = {
.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.ntevs = 0;
- ret = find_probes(fd, &tf.pf);
+ ret = debuginfo__find_probes(self, &tf.pf);
if (ret < 0) {
free(*tevs);
*tevs = NULL;
@@ -1739,9 +1211,10 @@ out:
}
/* 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 = {
.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.nvls = 0;
- ret = find_probes(fd, &af.pf);
+ ret = debuginfo__find_probes(self, &af.pf);
if (ret < 0) {
/* Free vlist for error */
while (af.nvls--) {
@@ -1774,28 +1247,19 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev,
}
/* 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 *dbg = NULL;
- Dwfl *dwfl = NULL;
- Dwarf_Addr _addr, baseaddr, bias = 0;
+ Dwarf_Addr _addr, baseaddr;
const char *fname = NULL, *func = NULL, *tmp;
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 */
- addr += bias;
+ addr += self->bias;
+
/* 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",
addr);
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 */
/* 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 */
tmp = dwarf_diename(&spdie);
if (!tmp ||
@@ -1871,8 +1335,6 @@ post:
}
}
end:
- if (dwfl)
- dwfl_end(dwfl);
if (ret == 0 && (fname || func))
ret = 1; /* Found a point */
return ret;
@@ -1982,26 +1444,15 @@ static int find_line_range_by_func(struct line_finder *lf)
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};
int ret = 0;
Dwarf_Off off = 0, noff;
size_t cuhl;
Dwarf_Die *diep;
- Dwarf *dbg = NULL;
- Dwfl *dwfl;
- Dwarf_Addr bias; /* Currently ignored */
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 */
if (lr->function) {
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 = {
.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) {
line_range_search_cb(&lf.sp_die, &line_range_param);
if (lf.found)
@@ -2020,11 +1472,12 @@ int find_line_range(int fd, struct line_range *lr)
/* Loop on CUs (Compilation Unit) */
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;
/* 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)
continue;
@@ -2058,7 +1511,6 @@ found:
}
pr_debug("path: %s\n", lr->path);
- dwfl_end(dwfl);
return (ret < 0) ? ret : lf.found;
}