perf probe: Introduce die_find_child() function
[cascardo/linux.git] / tools / perf / util / probe-finder.c
index 1b2124d..3942e14 100644 (file)
 #include <stdarg.h>
 #include <ctype.h>
 
+#include "string.h"
 #include "event.h"
 #include "debug.h"
 #include "util.h"
 #include "probe-finder.h"
 
 
-/* Dwarf_Die Linkage to parent Die */
-struct die_link {
-       struct die_link *parent;        /* Parent die */
-       Dwarf_Die die;                  /* Current die */
-};
-
-static Dwarf_Debug __dw_debug;
-static Dwarf_Error __dw_error;
-
 /*
  * Generic dwarf analysis helpers
  */
@@ -113,281 +105,213 @@ static int strtailcmp(const char *s1, const char *s2)
        return 0;
 }
 
-/* Find the fileno of the target file. */
-static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
-{
-       Dwarf_Signed cnt, i;
-       Dwarf_Unsigned found = 0;
-       char **srcs;
-       int ret;
+/* Line number list operations */
 
-       if (!fname)
-               return 0;
+/* Add a line to line number list */
+static void line_list__add_line(struct list_head *head, unsigned int line)
+{
+       struct line_node *ln;
+       struct list_head *p;
 
-       ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
-       if (ret == DW_DLV_OK) {
-               for (i = 0; i < cnt && !found; i++) {
-                       if (strtailcmp(srcs[i], fname) == 0)
-                               found = i + 1;
-                       dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
-               }
-               for (; i < cnt; i++)
-                       dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
-               dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
+       /* Reverse search, because new line will be the last one */
+       list_for_each_entry_reverse(ln, head, list) {
+               if (ln->line < line) {
+                       p = &ln->list;
+                       goto found;
+               } else if (ln->line == line)    /* Already exist */
+                       return ;
        }
-       if (found)
-               pr_debug("found fno: %d\n", (int)found);
-       return found;
-}
-
-static int cu_get_filename(Dwarf_Die cu_die, Dwarf_Unsigned fno, char **buf)
-{
-       Dwarf_Signed cnt, i;
-       char **srcs;
-       int ret = 0;
-
-       if (!buf || !fno)
-               return -EINVAL;
-
-       ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
-       if (ret == DW_DLV_OK) {
-               if ((Dwarf_Unsigned)cnt > fno - 1) {
-                       *buf = strdup(srcs[fno - 1]);
-                       ret = 0;
-                       pr_debug("found filename: %s\n", *buf);
-               } else
-                       ret = -ENOENT;
-               for (i = 0; i < cnt; i++)
-                       dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
-               dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
-       } else
-               ret = -EINVAL;
-       return ret;
+       /* List is empty, or the smallest entry */
+       p = head;
+found:
+       pr_debug("line list: add a line %u\n", line);
+       ln = xzalloc(sizeof(struct line_node));
+       ln->line = line;
+       INIT_LIST_HEAD(&ln->list);
+       list_add(&ln->list, p);
 }
 
-/* Compare diename and tname */
-static int die_compare_name(Dwarf_Die dw_die, const char *tname)
+/* Check if the line in line number list */
+static int line_list__has_line(struct list_head *head, unsigned int line)
 {
-       char *name;
-       int ret;
-       ret = dwarf_diename(dw_die, &name, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       if (ret == DW_DLV_OK) {
-               ret = strcmp(tname, name);
-               dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
-       } else
-               ret = -1;
-       return ret;
+       struct line_node *ln;
+
+       /* Reverse search, because new line will be the last one */
+       list_for_each_entry(ln, head, list)
+               if (ln->line == line)
+                       return 1;
+
+       return 0;
 }
 
-/* Check the address is in the subprogram(function). */
-static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr,
-                                Dwarf_Signed *offs)
+/* Init line number list */
+static void line_list__init(struct list_head *head)
 {
-       Dwarf_Addr lopc, hipc;
-       int ret;
+       INIT_LIST_HEAD(head);
+}
 
-       /* TODO: check ranges */
-       ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       if (ret == DW_DLV_NO_ENTRY)
-               return 0;
-       ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       if (lopc <= addr && addr < hipc) {
-               *offs = addr - lopc;
-               return 1;
-       } else
-               return 0;
+/* Free line number list */
+static void line_list__free(struct list_head *head)
+{
+       struct line_node *ln;
+       while (!list_empty(head)) {
+               ln = list_first_entry(head, struct line_node, list);
+               list_del(&ln->list);
+               free(ln);
+       }
 }
 
-/* Check the die is inlined function */
-static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
+/* Dwarf wrappers */
+
+/* Find the realpath of the target file. */
+static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
 {
-       /* TODO: check strictly */
-       Dwarf_Bool inl;
+       Dwarf_Files *files;
+       size_t nfiles, i;
+       const char *src = NULL;
        int ret;
 
-       ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       return inl;
+       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;
+       }
+       return src;
 }
 
-/* Get the offset of abstruct_origin */
-static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
+/* Compare diename and tname */
+static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
 {
-       Dwarf_Attribute attr;
-       Dwarf_Off cu_offs;
-       int ret;
-
-       ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       ret = dwarf_formref(attr, &cu_offs, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
-       return cu_offs;
+       const char *name;
+       name = dwarf_diename(dw_die);
+       DIE_IF(name == NULL);
+       return strcmp(tname, name);
 }
 
 /* Get entry pc(or low pc, 1st entry of ranges)  of the die */
-static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
+static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
 {
-       Dwarf_Attribute attr;
-       Dwarf_Addr addr;
-       Dwarf_Off offs;
-       Dwarf_Ranges *ranges;
-       Dwarf_Signed cnt;
+       Dwarf_Addr epc;
        int ret;
 
-       /* Try to get entry pc */
-       ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       if (ret == DW_DLV_OK) {
-               ret = dwarf_formaddr(attr, &addr, &__dw_error);
-               DIE_IF(ret != DW_DLV_OK);
-               dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
-               return addr;
-       }
-
-       /* Try to get low pc */
-       ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       if (ret == DW_DLV_OK)
-               return addr;
-
-       /* Try to get ranges */
-       ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       ret = dwarf_formref(attr, &offs, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
-                               &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       addr = ranges[0].dwr_addr1;
-       dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
-       return addr;
+       ret = dwarf_entrypc(dw_die, &epc);
+       DIE_IF(ret == -1);
+       return epc;
 }
 
-/*
- * Search a Die from Die tree.
- * Note: cur_link->die should be deallocated in this function.
- */
-static int __search_die_tree(struct die_link *cur_link,
-                            int (*die_cb)(struct die_link *, void *),
-                            void *data)
+/* 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 new_die;
-       struct die_link new_link;
+       Dwarf_Die child_die;
        int ret;
 
-       if (!die_cb)
-               return 0;
+       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;
 
-       /* Check current die */
-       while (!(ret = die_cb(cur_link, data))) {
-               /* Check child die */
-               ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
-               DIE_IF(ret == DW_DLV_ERROR);
-               if (ret == DW_DLV_OK) {
-                       new_link.parent = cur_link;
-                       new_link.die = new_die;
-                       ret = __search_die_tree(&new_link, die_cb, data);
-                       if (ret)
-                               break;
+               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);
 
-               /* Move to next sibling */
-               ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
-                                     &__dw_error);
-               DIE_IF(ret == DW_DLV_ERROR);
-               dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
-               cur_link->die = new_die;
-               if (ret == DW_DLV_NO_ENTRY)
-                       return 0;
-       }
-       dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
-       return ret;
+       return NULL;
 }
 
-/* Search a die in its children's die tree */
-static int search_die_from_children(Dwarf_Die parent_die,
-                                   int (*die_cb)(struct die_link *, void *),
-                                   void *data)
+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 die_link new_link;
-       int ret;
+       struct __addr_die_search_param *ad = data;
 
-       new_link.parent = NULL;
-       ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       if (ret == DW_DLV_OK)
-               return __search_die_tree(&new_link, die_cb, data);
-       else
-               return 0;
+       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;
+       }
+       return DWARF_CB_OK;
 }
 
-/* Find a locdesc corresponding to the address */
-static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
-                           Dwarf_Addr addr)
-{
-       Dwarf_Signed lcnt;
-       Dwarf_Locdesc **llbuf;
-       int ret, i;
-
-       ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       ret = DW_DLV_NO_ENTRY;
-       for (i = 0; i < lcnt; ++i) {
-               if (llbuf[i]->ld_lopc <= addr &&
-                   llbuf[i]->ld_hipc > addr) {
-                       memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
-                       desc->ld_s =
-                               malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
-                       DIE_IF(desc->ld_s == NULL);
-                       memcpy(desc->ld_s, llbuf[i]->ld_s,
-                               sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
-                       ret = DW_DLV_OK;
-                       break;
-               }
-               dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
-               dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
-       }
-       /* Releasing loop */
-       for (; i < lcnt; ++i) {
-               dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
-               dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
-       }
-       dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
-       return ret;
+/* 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;
 }
 
-/* Get decl_file attribute value (file number) */
-static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die)
+/* die_find callback for inline function search */
+static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
 {
-       Dwarf_Attribute attr;
-       Dwarf_Unsigned fno;
-       int ret;
+       Dwarf_Addr *addr = data;
+
+       if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
+           dwarf_haspc(die_mem, *addr))
+               return DIE_FIND_CB_FOUND;
 
-       ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       dwarf_formudata(attr, &fno, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
-       return fno;
+       return DIE_FIND_CB_CONTINUE;
 }
 
-/* Get decl_line attribute value (line number) */
-static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
+/* 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_Attribute attr;
-       Dwarf_Unsigned lno;
-       int ret;
+       return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
+}
 
-       ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       dwarf_formudata(attr, &lno, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
-       return lno;
+static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
+{
+       const char *name = data;
+       int tag;
+
+       tag = dwarf_tag(die_mem);
+       if ((tag == DW_TAG_formal_parameter ||
+            tag == DW_TAG_variable) &&
+           (die_compare_name(die_mem, name) == 0))
+               return DIE_FIND_CB_FOUND;
+
+       return DIE_FIND_CB_CONTINUE;
+}
+
+/* Find a variable called 'name' */
+static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
+                                   Dwarf_Die *die_mem)
+{
+       return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
+                             die_mem);
 }
 
 /*
@@ -395,47 +319,45 @@ static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
  */
 
 /* Show a location */
-static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
+static void show_location(Dwarf_Op *op, struct probe_finder *pf)
 {
-       Dwarf_Small op;
-       Dwarf_Unsigned regn;
-       Dwarf_Signed offs;
+       unsigned int regn;
+       Dwarf_Word offs = 0;
        int deref = 0, ret;
        const char *regs;
 
-       op = loc->lr_atom;
-
+       /* TODO: support CFA */
        /* If this is based on frame buffer, set the offset */
-       if (op == DW_OP_fbreg) {
+       if (op->atom == DW_OP_fbreg) {
+               if (pf->fb_ops == NULL)
+                       die("The attribute of frame base is not supported.\n");
                deref = 1;
-               offs = (Dwarf_Signed)loc->lr_number;
-               op = pf->fbloc.ld_s[0].lr_atom;
-               loc = &pf->fbloc.ld_s[0];
-       } else
-               offs = 0;
+               offs = op->number;
+               op = &pf->fb_ops[0];
+       }
 
-       if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
-               regn = op - DW_OP_breg0;
-               offs += (Dwarf_Signed)loc->lr_number;
+       if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
+               regn = op->atom - DW_OP_breg0;
+               offs += op->number;
                deref = 1;
-       } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
-               regn = op - DW_OP_reg0;
-       } else if (op == DW_OP_bregx) {
-               regn = loc->lr_number;
-               offs += (Dwarf_Signed)loc->lr_number2;
+       } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
+               regn = op->atom - DW_OP_reg0;
+       } else if (op->atom == DW_OP_bregx) {
+               regn = op->number;
+               offs += op->number2;
                deref = 1;
-       } else if (op == DW_OP_regx) {
-               regn = loc->lr_number;
+       } else if (op->atom == DW_OP_regx) {
+               regn = op->number;
        } else
-               die("Dwarf_OP %d is not supported.", op);
+               die("DW_OP %d is not supported.", op->atom);
 
        regs = get_arch_regstr(regn);
        if (!regs)
-               die("%lld exceeds max register number.", regn);
+               die("%u exceeds max register number.", regn);
 
        if (deref)
-               ret = snprintf(pf->buf, pf->len,
-                                " %s=%+lld(%s)", pf->var, offs, regs);
+               ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)",
+                              pf->var, (intmax_t)offs, regs);
        else
                ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
        DIE_IF(ret < 0);
@@ -443,52 +365,36 @@ static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
 }
 
 /* Show a variables in kprobe event format */
-static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
+static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 {
        Dwarf_Attribute attr;
-       Dwarf_Locdesc ld;
+       Dwarf_Op *expr;
+       size_t nexpr;
        int ret;
 
-       ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error);
-       if (ret != DW_DLV_OK)
+       if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
                goto error;
-       ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base));
-       if (ret != DW_DLV_OK)
+       /* TODO: handle more than 1 exprs */
+       ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
+       if (ret <= 0 || nexpr == 0)
                goto error;
-       /* TODO? */
-       DIE_IF(ld.ld_cents != 1);
-       show_location(&ld.ld_s[0], pf);
-       free(ld.ld_s);
-       dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+
+       show_location(expr, pf);
+       /* *expr will be cached in libdw. Don't free it. */
        return ;
 error:
+       /* TODO: Support const_value */
        die("Failed to find the location of %s at this address.\n"
            " Perhaps, it has been optimized out.", pf->var);
 }
 
-static int variable_callback(struct die_link *dlink, void *data)
-{
-       struct probe_finder *pf = (struct probe_finder *)data;
-       Dwarf_Half tag;
-       int ret;
-
-       ret = dwarf_tag(dlink->die, &tag, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       if ((tag == DW_TAG_formal_parameter ||
-            tag == DW_TAG_variable) &&
-           (die_compare_name(dlink->die, pf->var) == 0)) {
-               show_variable(dlink->die, pf);
-               return 1;
-       }
-       /* TODO: Support struct members and arrays */
-       return 0;
-}
-
 /* Find a variable in a subprogram die */
-static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
+static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
        int ret;
+       Dwarf_Die vr_die;
 
+       /* TODO: Support struct members and arrays */
        if (!is_c_varname(pf->var)) {
                /* Output raw parameters */
                ret = snprintf(pf->buf, pf->len, " %s", pf->var);
@@ -499,58 +405,51 @@ static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
 
        pr_debug("Searching '%s' variable in context.\n", pf->var);
        /* Search child die for local variables and parameters. */
-       ret = search_die_from_children(sp_die, variable_callback, pf);
-       if (!ret)
+       if (!die_find_variable(sp_die, pf->var, &vr_die))
                die("Failed to find '%s' in this function.", pf->var);
-}
 
-/* Get a frame base on the address */
-static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
-{
-       Dwarf_Attribute attr;
-       int ret;
-
-       ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-       ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
-       DIE_IF(ret != DW_DLV_OK);
-       dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
-}
-
-static void free_current_frame_base(struct probe_finder *pf)
-{
-       free(pf->fbloc.ld_s);
-       memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
+       show_variable(&vr_die, pf);
 }
 
 /* Show a probe point to output buffer */
-static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
-                           struct probe_finder *pf)
+static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
        struct probe_point *pp = pf->pp;
-       char *name;
+       Dwarf_Addr eaddr;
+       Dwarf_Die die_mem;
+       const char *name;
        char tmp[MAX_PROBE_BUFFER];
        int ret, i, len;
+       Dwarf_Attribute fb_attr;
+       size_t nops;
+
+       /* 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);
+               if (!sp_die)
+                       die("Probe point is not found in subprograms.");
+       }
 
        /* Output name of probe point */
-       ret = dwarf_diename(sp_die, &name, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       if (ret == DW_DLV_OK) {
-               ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
-                               (unsigned int)offs);
+       name = dwarf_diename(sp_die);
+       if (name) {
+               dwarf_entrypc(sp_die, &eaddr);
+               ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
+                               (unsigned long)(pf->addr - eaddr));
                /* Copy the function name if possible */
                if (!pp->function) {
-                       pp->function = strdup(name);
-                       pp->offset = offs;
+                       pp->function = xstrdup(name);
+                       pp->offset = (size_t)(pf->addr - eaddr);
                }
-               dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
        } else {
                /* This function has no name. */
-               ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr);
+               ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
+                              (uintmax_t)pf->addr);
                if (!pp->function) {
                        /* TODO: Use _stext */
-                       pp->function = strdup("");
-                       pp->offset = (int)pf->addr;
+                       pp->function = xstrdup("");
+                       pp->offset = (size_t)pf->addr;
                }
        }
        DIE_IF(ret < 0);
@@ -558,8 +457,14 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
        len = ret;
        pr_debug("Probe point found: %s\n", tmp);
 
+       /* Get the frame base attribute/ops */
+       dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
+       ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
+       if (ret <= 0 || nops == 0)
+               pf->fb_ops = NULL;
+
        /* Find each argument */
-       get_current_frame_base(sp_die, pf);
+       /* TODO: use dwarf_cfi_addrframe */
        for (i = 0; i < pp->nr_args; i++) {
                pf->var = pp->args[i];
                pf->buf = &tmp[len];
@@ -567,289 +472,324 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
                find_variable(sp_die, pf);
                len += strlen(pf->buf);
        }
-       free_current_frame_base(pf);
 
-       pp->probes[pp->found] = strdup(tmp);
+       /* *pf->fb_ops will be cached in libdw. Don't free it. */
+       pf->fb_ops = NULL;
+
+       if (pp->found == MAX_PROBES)
+               die("Too many( > %d) probe point found.\n", MAX_PROBES);
+
+       pp->probes[pp->found] = xstrdup(tmp);
        pp->found++;
 }
 
-static int probeaddr_callback(struct die_link *dlink, void *data)
+/* Find probe point from its line number */
+static void find_probe_point_by_line(struct probe_finder *pf)
 {
-       struct probe_finder *pf = (struct probe_finder *)data;
-       Dwarf_Half tag;
-       Dwarf_Signed offs;
+       Dwarf_Lines *lines;
+       Dwarf_Line *line;
+       size_t nlines, i;
+       Dwarf_Addr addr;
+       int lineno;
        int ret;
 
-       ret = dwarf_tag(dlink->die, &tag, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       /* Check the address is in this subprogram */
-       if (tag == DW_TAG_subprogram &&
-           die_within_subprogram(dlink->die, pf->addr, &offs)) {
-               show_probepoint(dlink->die, offs, pf);
-               return 1;
+       ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
+       DIE_IF(ret != 0);
+
+       for (i = 0; i < nlines; i++) {
+               line = dwarf_onesrcline(lines, i);
+               dwarf_lineno(line, &lineno);
+               if (lineno != pf->lno)
+                       continue;
+
+               /* TODO: Get fileno from line, but how? */
+               if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
+                       continue;
+
+               ret = dwarf_lineaddr(line, &addr);
+               DIE_IF(ret != 0);
+               pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
+                        (int)i, lineno, (uintmax_t)addr);
+               pf->addr = addr;
+
+               show_probe_point(NULL, pf);
+               /* Continuing, because target line might be inlined. */
        }
-       return 0;
 }
 
-/* Find probe point from its line number */
-static void find_probe_point_by_line(struct probe_finder *pf)
+/* Find lines which match lazy pattern */
+static int find_lazy_match_lines(struct list_head *head,
+                                const char *fname, const char *pat)
 {
-       Dwarf_Signed cnt, i, clm;
-       Dwarf_Line *lines;
-       Dwarf_Unsigned lineno = 0;
+       char *fbuf, *p1, *p2;
+       int fd, line, nlines = 0;
+       struct stat st;
+
+       fd = open(fname, O_RDONLY);
+       if (fd < 0)
+               die("failed to open %s", fname);
+       DIE_IF(fstat(fd, &st) < 0);
+       fbuf = xmalloc(st.st_size + 2);
+       DIE_IF(read(fd, fbuf, st.st_size) < 0);
+       close(fd);
+       fbuf[st.st_size] = '\n';        /* Dummy line */
+       fbuf[st.st_size + 1] = '\0';
+       p1 = fbuf;
+       line = 1;
+       while ((p2 = strchr(p1, '\n')) != NULL) {
+               *p2 = '\0';
+               if (strlazymatch(p1, pat)) {
+                       line_list__add_line(head, line);
+                       nlines++;
+               }
+               line++;
+               p1 = p2 + 1;
+       }
+       free(fbuf);
+       return nlines;
+}
+
+/* Find probe points from lazy pattern  */
+static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+       Dwarf_Lines *lines;
+       Dwarf_Line *line;
+       size_t nlines, i;
        Dwarf_Addr addr;
-       Dwarf_Unsigned fno;
+       Dwarf_Die die_mem;
+       int lineno;
        int ret;
 
-       ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
+       if (list_empty(&pf->lcache)) {
+               /* Matching lazy line pattern */
+               ret = find_lazy_match_lines(&pf->lcache, pf->fname,
+                                           pf->pp->lazy_line);
+               if (ret <= 0)
+                       die("No matched lines found in %s.", pf->fname);
+       }
 
-       for (i = 0; i < cnt; i++) {
-               ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
-               DIE_IF(ret != DW_DLV_OK);
-               if (fno != pf->fno)
+       ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
+       DIE_IF(ret != 0);
+       for (i = 0; i < nlines; i++) {
+               line = dwarf_onesrcline(lines, i);
+
+               dwarf_lineno(line, &lineno);
+               if (!line_list__has_line(&pf->lcache, lineno))
                        continue;
 
-               ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
-               DIE_IF(ret != DW_DLV_OK);
-               if (lineno != pf->lno)
+               /* TODO: Get fileno from line, but how? */
+               if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
                        continue;
 
-               ret = dwarf_lineoff(lines[i], &clm, &__dw_error);
-               DIE_IF(ret != DW_DLV_OK);
+               ret = dwarf_lineaddr(line, &addr);
+               DIE_IF(ret != 0);
+               if (sp_die) {
+                       /* Address filtering 1: does sp_die include addr? */
+                       if (!dwarf_haspc(sp_die, addr))
+                               continue;
+                       /* Address filtering 2: No child include addr? */
+                       if (die_find_inlinefunc(sp_die, addr, &die_mem))
+                               continue;
+               }
 
-               ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
-               DIE_IF(ret != DW_DLV_OK);
-               pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
-                        (int)i, (unsigned)lineno, (int)clm, addr);
+               pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
+                        (int)i, lineno, (unsigned long long)addr);
                pf->addr = addr;
-               /* Search a real subprogram including this line, */
-               ret = search_die_from_children(pf->cu_die,
-                                              probeaddr_callback, pf);
-               if (ret == 0)
-                       die("Probe point is not found in subprograms.");
+
+               show_probe_point(sp_die, pf);
                /* Continuing, because target line might be inlined. */
        }
-       dwarf_srclines_dealloc(__dw_debug, lines, cnt);
+       /* TODO: deallocate lines, but how? */
+}
+
+static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
+{
+       struct probe_finder *pf = (struct probe_finder *)data;
+       struct probe_point *pp = pf->pp;
+
+       if (pp->lazy_line)
+               find_probe_point_lazy(in_die, pf);
+       else {
+               /* Get probe address */
+               pf->addr = die_get_entrypc(in_die);
+               pf->addr += pp->offset;
+               pr_debug("found inline addr: 0x%jx\n",
+                        (uintmax_t)pf->addr);
+
+               show_probe_point(in_die, pf);
+       }
+
+       return DWARF_CB_OK;
 }
 
 /* Search function from function name */
-static int probefunc_callback(struct die_link *dlink, void *data)
+static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 {
        struct probe_finder *pf = (struct probe_finder *)data;
        struct probe_point *pp = pf->pp;
-       struct die_link *lk;
-       Dwarf_Signed offs;
-       Dwarf_Half tag;
-       int ret;
 
-       ret = dwarf_tag(dlink->die, &tag, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       if (tag == DW_TAG_subprogram) {
-               if (die_compare_name(dlink->die, pp->function) == 0) {
-                       if (pp->line) { /* Function relative line */
-                               pf->fno = die_get_decl_file(dlink->die);
-                               pf->lno = die_get_decl_line(dlink->die)
-                                        + pp->line;
-                               find_probe_point_by_line(pf);
-                               return 1;
-                       }
-                       if (die_inlined_subprogram(dlink->die)) {
-                               /* Inlined function, save it. */
-                               ret = dwarf_die_CU_offset(dlink->die,
-                                                         &pf->inl_offs,
-                                                         &__dw_error);
-                               DIE_IF(ret != DW_DLV_OK);
-                               pr_debug("inline definition offset %lld\n",
-                                        pf->inl_offs);
-                               return 0;       /* Continue to search */
-                       }
-                       /* Get probe address */
-                       pf->addr = die_get_entrypc(dlink->die);
+       /* Check tag and diename */
+       if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
+           die_compare_name(sp_die, pp->function) != 0)
+               return 0;
+
+       pf->fname = dwarf_decl_file(sp_die);
+       if (pp->line) { /* Function relative line */
+               dwarf_decl_line(sp_die, &pf->lno);
+               pf->lno += pp->line;
+               find_probe_point_by_line(pf);
+       } else if (!dwarf_func_inline(sp_die)) {
+               /* Real function */
+               if (pp->lazy_line)
+                       find_probe_point_lazy(sp_die, pf);
+               else {
+                       pf->addr = die_get_entrypc(sp_die);
                        pf->addr += pp->offset;
                        /* TODO: Check the address in this function */
-                       show_probepoint(dlink->die, pp->offset, pf);
-                       return 1; /* Exit; no same symbol in this CU. */
+                       show_probe_point(sp_die, pf);
                }
-       } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
-               if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
-                       /* Get probe address */
-                       pf->addr = die_get_entrypc(dlink->die);
-                       pf->addr += pp->offset;
-                       pr_debug("found inline addr: 0x%llx\n", pf->addr);
-                       /* Inlined function. Get a real subprogram */
-                       for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
-                               tag = 0;
-                               dwarf_tag(lk->die, &tag, &__dw_error);
-                               DIE_IF(ret == DW_DLV_ERROR);
-                               if (tag == DW_TAG_subprogram &&
-                                   !die_inlined_subprogram(lk->die))
-                                       goto found;
-                       }
-                       die("Failed to find real subprogram.");
-found:
-                       /* Get offset from subprogram */
-                       ret = die_within_subprogram(lk->die, pf->addr, &offs);
-                       DIE_IF(!ret);
-                       show_probepoint(lk->die, offs, pf);
-                       /* Continue to search */
-               }
-       }
-       return 0;
+       } else
+               /* Inlined function: search instances */
+               dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
+
+       return 1; /* Exit; no same symbol in this CU. */
 }
 
 static void find_probe_point_by_func(struct probe_finder *pf)
 {
-       search_die_from_children(pf->cu_die, probefunc_callback, pf);
+       dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
 }
 
 /* Find a probe point */
-int find_probepoint(int fd, struct probe_point *pp)
+int find_probe_point(int fd, struct probe_point *pp)
 {
-       Dwarf_Half addr_size = 0;
-       Dwarf_Unsigned next_cuh = 0;
-       int cu_number = 0, ret;
        struct probe_finder pf = {.pp = pp};
+       Dwarf_Off off, noff;
+       size_t cuhl;
+       Dwarf_Die *diep;
+       Dwarf *dbg;
 
-       ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
-       if (ret != DW_DLV_OK)
+       dbg = dwarf_begin(fd, DWARF_C_READ);
+       if (!dbg)
                return -ENOENT;
 
        pp->found = 0;
-       while (++cu_number) {
-               /* Search CU (Compilation Unit) */
-               ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
-                       &addr_size, &next_cuh, &__dw_error);
-               DIE_IF(ret == DW_DLV_ERROR);
-               if (ret == DW_DLV_NO_ENTRY)
-                       break;
-
+       off = 0;
+       line_list__init(&pf.lcache);
+       /* Loop on CUs (Compilation Unit) */
+       while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
                /* Get the DIE(Debugging Information Entry) of this CU */
-               ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error);
-               DIE_IF(ret != DW_DLV_OK);
+               diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
+               if (!diep)
+                       continue;
 
                /* Check if target file is included. */
                if (pp->file)
-                       pf.fno = cu_find_fileno(pf.cu_die, pp->file);
-
-               if (!pp->file || pf.fno) {
-                       /* Save CU base address (for frame_base) */
-                       ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error);
-                       DIE_IF(ret == DW_DLV_ERROR);
-                       if (ret == DW_DLV_NO_ENTRY)
-                               pf.cu_base = 0;
+                       pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
+               else
+                       pf.fname = NULL;
+
+               if (!pp->file || pf.fname) {
                        if (pp->function)
                                find_probe_point_by_func(&pf);
+                       else if (pp->lazy_line)
+                               find_probe_point_lazy(NULL, &pf);
                        else {
                                pf.lno = pp->line;
                                find_probe_point_by_line(&pf);
                        }
                }
-               dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE);
+               off = noff;
        }
-       ret = dwarf_finish(__dw_debug, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
+       line_list__free(&pf.lcache);
+       dwarf_end(dbg);
 
        return pp->found;
 }
 
-
-static void line_range_add_line(struct line_range *lr, unsigned int line)
-{
-       struct line_node *ln;
-       struct list_head *p;
-
-       /* Reverse search, because new line will be the last one */
-       list_for_each_entry_reverse(ln, &lr->line_list, list) {
-               if (ln->line < line) {
-                       p = &ln->list;
-                       goto found;
-               } else if (ln->line == line)    /* Already exist */
-                       return ;
-       }
-       /* List is empty, or the smallest entry */
-       p = &lr->line_list;
-found:
-       pr_debug("Debug: add a line %u\n", line);
-       ln = zalloc(sizeof(struct line_node));
-       DIE_IF(ln == NULL);
-       ln->line = line;
-       INIT_LIST_HEAD(&ln->list);
-       list_add(&ln->list, p);
-}
-
 /* Find line range from its line number */
-static void find_line_range_by_line(struct line_finder *lf)
+static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 {
-       Dwarf_Signed cnt, i;
-       Dwarf_Line *lines;
-       Dwarf_Unsigned lineno = 0;
-       Dwarf_Unsigned fno;
+       Dwarf_Lines *lines;
+       Dwarf_Line *line;
+       size_t nlines, i;
        Dwarf_Addr addr;
+       int lineno;
        int ret;
+       const char *src;
+       Dwarf_Die die_mem;
 
-       ret = dwarf_srclines(lf->cu_die, &lines, &cnt, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
-
-       for (i = 0; i < cnt; i++) {
-               ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
-               DIE_IF(ret != DW_DLV_OK);
-               if (fno != lf->fno)
-                       continue;
+       line_list__init(&lf->lr->line_list);
+       ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
+       DIE_IF(ret != 0);
 
-               ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
-               DIE_IF(ret != DW_DLV_OK);
+       for (i = 0; i < nlines; i++) {
+               line = dwarf_onesrcline(lines, i);
+               ret = dwarf_lineno(line, &lineno);
+               DIE_IF(ret != 0);
                if (lf->lno_s > lineno || lf->lno_e < lineno)
                        continue;
 
-               /* Filter line in the function address range */
-               if (lf->addr_s && lf->addr_e) {
-                       ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
-                       DIE_IF(ret != DW_DLV_OK);
-                       if (lf->addr_s > addr || lf->addr_e <= addr)
+               if (sp_die) {
+                       /* Address filtering 1: does sp_die include addr? */
+                       ret = dwarf_lineaddr(line, &addr);
+                       DIE_IF(ret != 0);
+                       if (!dwarf_haspc(sp_die, addr))
+                               continue;
+
+                       /* Address filtering 2: No child include addr? */
+                       if (die_find_inlinefunc(sp_die, addr, &die_mem))
                                continue;
                }
-               line_range_add_line(lf->lr, (unsigned int)lineno);
+
+               /* TODO: Get fileno from line, but how? */
+               src = dwarf_linesrc(line, NULL, NULL);
+               if (strtailcmp(src, lf->fname) != 0)
+                       continue;
+
+               /* Copy real path */
+               if (!lf->lr->path)
+                       lf->lr->path = xstrdup(src);
+               line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
        }
-       dwarf_srclines_dealloc(__dw_debug, lines, cnt);
+       /* Update status */
        if (!list_empty(&lf->lr->line_list))
                lf->found = 1;
+       else {
+               free(lf->lr->path);
+               lf->lr->path = NULL;
+       }
+}
+
+static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
+{
+       find_line_range_by_line(in_die, (struct line_finder *)data);
+       return DWARF_CB_ABORT;  /* No need to find other instances */
 }
 
 /* Search function from function name */
-static int linefunc_callback(struct die_link *dlink, void *data)
+static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
 {
        struct line_finder *lf = (struct line_finder *)data;
        struct line_range *lr = lf->lr;
-       Dwarf_Half tag;
-       int ret;
 
-       ret = dwarf_tag(dlink->die, &tag, &__dw_error);
-       DIE_IF(ret == DW_DLV_ERROR);
-       if (tag == DW_TAG_subprogram &&
-           die_compare_name(dlink->die, lr->function) == 0) {
-               /* Get the address range of this function */
-               ret = dwarf_highpc(dlink->die, &lf->addr_e, &__dw_error);
-               if (ret == DW_DLV_OK)
-                       ret = dwarf_lowpc(dlink->die, &lf->addr_s, &__dw_error);
-               DIE_IF(ret == DW_DLV_ERROR);
-               if (ret == DW_DLV_NO_ENTRY) {
-                       lf->addr_s = 0;
-                       lf->addr_e = 0;
-               }
-
-               lf->fno = die_get_decl_file(dlink->die);
-               lr->offset = die_get_decl_line(dlink->die);;
+       if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
+           die_compare_name(sp_die, lr->function) == 0) {
+               lf->fname = dwarf_decl_file(sp_die);
+               dwarf_decl_line(sp_die, &lr->offset);
+               pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
                lf->lno_s = lr->offset + lr->start;
                if (!lr->end)
-                       lf->lno_e = (Dwarf_Unsigned)-1;
+                       lf->lno_e = INT_MAX;
                else
                        lf->lno_e = lr->offset + lr->end;
                lr->start = lf->lno_s;
                lr->end = lf->lno_e;
-               find_line_range_by_line(lf);
-               /* If we find a target function, this should be end. */
-               lf->found = 1;
+               if (dwarf_func_inline(sp_die))
+                       dwarf_func_inline_instances(sp_die,
+                                                   line_range_inline_cb, lf);
+               else
+                       find_line_range_by_line(sp_die, lf);
                return 1;
        }
        return 0;
@@ -857,55 +797,55 @@ static int linefunc_callback(struct die_link *dlink, void *data)
 
 static void find_line_range_by_func(struct line_finder *lf)
 {
-       search_die_from_children(lf->cu_die, linefunc_callback, lf);
+       dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
 }
 
 int find_line_range(int fd, struct line_range *lr)
 {
-       Dwarf_Half addr_size = 0;
-       Dwarf_Unsigned next_cuh = 0;
+       struct line_finder lf = {.lr = lr, .found = 0};
        int ret;
-       struct line_finder lf = {.lr = lr};
+       Dwarf_Off off = 0, noff;
+       size_t cuhl;
+       Dwarf_Die *diep;
+       Dwarf *dbg;
 
-       ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
-       if (ret != DW_DLV_OK)
+       dbg = dwarf_begin(fd, DWARF_C_READ);
+       if (!dbg)
                return -ENOENT;
 
+       /* Loop on CUs (Compilation Unit) */
        while (!lf.found) {
-               /* Search CU (Compilation Unit) */
-               ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
-                       &addr_size, &next_cuh, &__dw_error);
-               DIE_IF(ret == DW_DLV_ERROR);
-               if (ret == DW_DLV_NO_ENTRY)
+               ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
+               if (ret != 0)
                        break;
 
                /* Get the DIE(Debugging Information Entry) of this CU */
-               ret = dwarf_siblingof(__dw_debug, 0, &lf.cu_die, &__dw_error);
-               DIE_IF(ret != DW_DLV_OK);
+               diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
+               if (!diep)
+                       continue;
 
                /* Check if target file is included. */
                if (lr->file)
-                       lf.fno = cu_find_fileno(lf.cu_die, lr->file);
+                       lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
+               else
+                       lf.fname = 0;
 
-               if (!lr->file || lf.fno) {
+               if (!lr->file || lf.fname) {
                        if (lr->function)
                                find_line_range_by_func(&lf);
                        else {
                                lf.lno_s = lr->start;
                                if (!lr->end)
-                                       lf.lno_e = (Dwarf_Unsigned)-1;
+                                       lf.lno_e = INT_MAX;
                                else
                                        lf.lno_e = lr->end;
-                               find_line_range_by_line(&lf);
+                               find_line_range_by_line(NULL, &lf);
                        }
-                       /* Get the real file path */
-                       if (lf.found)
-                               cu_get_filename(lf.cu_die, lf.fno, &lr->path);
                }
-               dwarf_dealloc(__dw_debug, lf.cu_die, DW_DLA_DIE);
+               off = noff;
        }
-       ret = dwarf_finish(__dw_debug, &__dw_error);
-       DIE_IF(ret != DW_DLV_OK);
+       pr_debug("path: %lx\n", (unsigned long)lr->path);
+       dwarf_end(dbg);
        return lf.found;
 }