perf probe: Fix to walk all inline instances
[linux-2.6.git] / tools / perf / util / probe-finder.c
index 3b9d0b8..d6d5768 100644 (file)
 /* 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)
+struct debuginfo *debuginfo__new(const char *path)
 {
-       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)
+       struct debuginfo *self = zalloc(sizeof(struct debuginfo));
+       if (!self)
                return NULL;
 
-       for (i = 0; i < nfiles; i++) {
-               src = dwarf_filesrc(files, i, NULL, NULL);
-               if (strtailcmp(src, fname) == 0)
-                       break;
+       if (debuginfo__init_offline_dwarf(self, path) < 0) {
+               free(self);
+               self = NULL;
        }
-       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;
+       return self;
 }
 
-/* Compare diename and tname */
-static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
+struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
 {
-       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
+       struct debuginfo *self = zalloc(sizeof(struct debuginfo));
+       if (!self)
                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;
+       if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) {
+               free(self);
+               self = NULL;
        }
-       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)
-{
-       Dwarf_Die child_die;
-       int ret;
-
-       ret = dwarf_child(rt_die, die_mem);
-       if (ret != 0)
-               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;
+       return self;
 }
 
-struct __addr_die_search_param {
-       Dwarf_Addr      addr;
-       Dwarf_Die       *die_mem;
-};
-
-static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
+void debuginfo__delete(struct debuginfo *self)
 {
-       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 (self) {
+               if (self->dwfl)
+                       dwfl_end(self->dwfl);
+               free(self);
        }
-       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;
-}
-
-/* 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)
-{
-       Dwarf_Die tmp_die;
-
-       sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die);
-       if (!sp_die)
-               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;
-       }
-
-       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;
-}
-
-/* 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)
-{
-       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 (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));
@@ -1177,6 +660,7 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
        else {
                /* Search upper class */
                nscopes = dwarf_getscopes_die(sp_die, &scopes);
+               ret = -ENOENT;
                while (nscopes-- > 1) {
                        pr_debug("Searching variables in %s\n",
                                 dwarf_diename(&scopes[nscopes]));
@@ -1185,14 +669,12 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
                                                 pf->pvar->var, 0,
                                                 &vr_die)) {
                                ret = convert_variable(&vr_die, pf);
-                               goto found;
+                               break;
                        }
                }
                if (scopes)
                        free(scopes);
-               ret = -ENOENT;
        }
-found:
        if (ret < 0)
                pr_warning("Failed to find '%s' in this function.\n",
                           pf->pvar->var);
@@ -1245,8 +727,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 +985,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 +1015,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 +1025,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 +1054,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 +1099,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 +1116,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 +1210,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 +1228,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 +1246,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 +1270,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 +1334,6 @@ post:
                }
        }
 end:
-       if (dwfl)
-               dwfl_end(dwfl);
        if (ret == 0 && (fname || func))
                ret = 1;        /* Found a point */
        return ret;
@@ -1932,7 +1393,13 @@ static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
        struct dwarf_callback_param *param = data;
 
        param->retval = find_line_range_by_line(in_die, param->data);
-       return DWARF_CB_ABORT;  /* No need to find other instances */
+
+       /*
+        * We have to check all instances of inlined function, because
+        * some execution paths can be optimized out depends on the
+        * function argument of instances
+        */
+       return DWARF_CB_OK;
 }
 
 /* Search function from function name */
@@ -1982,26 +1449,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 +1466,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 +1477,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 +1516,6 @@ found:
        }
 
        pr_debug("path: %s\n", lr->path);
-       dwfl_end(dwfl);
        return (ret < 0) ? ret : lf.found;
 }