OSDN Git Service

perf probe: Fix to show function entry line as probe-able
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / tools / perf / util / dwarf-aux.c
index a509aa8..fd460ac 100644 (file)
@@ -294,20 +294,50 @@ bool die_is_func_def(Dwarf_Die *dw_die)
 }
 
 /**
+ * die_entrypc - Returns entry PC (the lowest address) of a DIE
+ * @dw_die: a DIE
+ * @addr: where to store entry PC
+ *
+ * Since dwarf_entrypc() does not return entry PC if the DIE has only address
+ * range, we have to use this to retrieve the lowest address from the address
+ * range attribute.
+ */
+int die_entrypc(Dwarf_Die *dw_die, Dwarf_Addr *addr)
+{
+       Dwarf_Addr base, end;
+
+       if (!addr)
+               return -EINVAL;
+
+       if (dwarf_entrypc(dw_die, addr) == 0)
+               return 0;
+
+       return dwarf_ranges(dw_die, 0, &base, addr, &end) < 0 ? -ENOENT : 0;
+}
+
+/**
  * die_is_func_instance - Ensure that this DIE is an instance of a subprogram
  * @dw_die: a DIE
  *
  * Ensure that this DIE is an instance (which has an entry address).
- * This returns true if @dw_die is a function instance. If not, you need to
- * call die_walk_instances() to find actual instances.
+ * This returns true if @dw_die is a function instance. If not, the @dw_die
+ * must be a prototype. You can use die_walk_instances() to find actual
+ * instances.
  **/
 bool die_is_func_instance(Dwarf_Die *dw_die)
 {
        Dwarf_Addr tmp;
+       Dwarf_Attribute attr_mem;
+       int tag = dwarf_tag(dw_die);
 
-       /* Actually gcc optimizes non-inline as like as inlined */
-       return !dwarf_func_inline(dw_die) && dwarf_entrypc(dw_die, &tmp) == 0;
+       if (tag != DW_TAG_subprogram &&
+           tag != DW_TAG_inlined_subroutine)
+               return false;
+
+       return dwarf_entrypc(dw_die, &tmp) == 0 ||
+               dwarf_attr(dw_die, DW_AT_ranges, &attr_mem) != NULL;
 }
+
 /**
  * die_get_data_member_location - Get the data-member offset
  * @mb_die: a DIE of a member of a data structure
@@ -584,6 +614,9 @@ static int __die_walk_instances_cb(Dwarf_Die *inst, void *data)
        Dwarf_Die *origin;
        int tmp;
 
+       if (!die_is_func_instance(inst))
+               return DIE_FIND_CB_CONTINUE;
+
        attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem);
        if (attr == NULL)
                return DIE_FIND_CB_CONTINUE;
@@ -655,15 +688,14 @@ static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
        if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
                fname = die_get_call_file(in_die);
                lineno = die_get_call_lineno(in_die);
-               if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
+               if (fname && lineno > 0 && die_entrypc(in_die, &addr) == 0) {
                        lw->retval = lw->callback(fname, lineno, addr, lw->data);
                        if (lw->retval != 0)
                                return DIE_FIND_CB_END;
                }
+               if (!lw->recursive)
+                       return DIE_FIND_CB_SIBLING;
        }
-       if (!lw->recursive)
-               /* Don't need to search recursively */
-               return DIE_FIND_CB_SIBLING;
 
        if (addr) {
                fname = dwarf_decl_file(in_die);
@@ -696,7 +728,7 @@ static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
        /* Handle function declaration line */
        fname = dwarf_decl_file(sp_die);
        if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
-           dwarf_entrypc(sp_die, &addr) == 0) {
+           die_entrypc(sp_die, &addr) == 0) {
                lw.retval = callback(fname, lineno, addr, data);
                if (lw.retval != 0)
                        goto done;
@@ -710,6 +742,10 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
 {
        struct __line_walk_param *lw = data;
 
+       /*
+        * Since inlined function can include another inlined function in
+        * the same file, we need to walk in it recursively.
+        */
        lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data);
        if (lw->retval != 0)
                return DWARF_CB_ABORT;
@@ -734,11 +770,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
        Dwarf_Lines *lines;
        Dwarf_Line *line;
        Dwarf_Addr addr;
-       const char *fname, *decf = NULL;
+       const char *fname, *decf = NULL, *inf = NULL;
        int lineno, ret = 0;
        int decl = 0, inl;
        Dwarf_Die die_mem, *cu_die;
        size_t nlines, i;
+       bool flag;
 
        /* Get the CU die */
        if (dwarf_tag(rt_die) != DW_TAG_compile_unit) {
@@ -769,6 +806,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
                                  "Possible error in debuginfo.\n");
                        continue;
                }
+               /* Skip end-of-sequence */
+               if (dwarf_lineendsequence(line, &flag) != 0 || flag)
+                       continue;
+               /* Skip Non statement line-info */
+               if (dwarf_linebeginstatement(line, &flag) != 0 || !flag)
+                       continue;
                /* Filter lines based on address */
                if (rt_die != cu_die) {
                        /*
@@ -778,13 +821,21 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
                         */
                        if (!dwarf_haspc(rt_die, addr))
                                continue;
+
                        if (die_find_inlinefunc(rt_die, addr, &die_mem)) {
+                               /* Call-site check */
+                               inf = die_get_call_file(&die_mem);
+                               if ((inf && !strcmp(inf, decf)) &&
+                                   die_get_call_lineno(&die_mem) == lineno)
+                                       goto found;
+
                                dwarf_decl_line(&die_mem, &inl);
                                if (inl != decl ||
                                    decf != dwarf_decl_file(&die_mem))
                                        continue;
                        }
                }
+found:
                /* Get source line */
                fname = dwarf_linesrc(line, NULL, NULL);
 
@@ -799,8 +850,9 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
         */
        if (rt_die != cu_die)
                /*
-                * Don't need walk functions recursively, because nested
-                * inlined functions don't have lines of the specified DIE.
+                * Don't need walk inlined functions recursively, because
+                * inner inlined functions don't have the lines of the
+                * specified function.
                 */
                ret = __die_walk_funclines(rt_die, false, callback, data);
        else {
@@ -981,7 +1033,7 @@ static int die_get_var_innermost_scope(Dwarf_Die *sp_die, Dwarf_Die *vr_die,
        bool first = true;
        const char *name;
 
-       ret = dwarf_entrypc(sp_die, &entry);
+       ret = die_entrypc(sp_die, &entry);
        if (ret)
                return ret;
 
@@ -1042,7 +1094,7 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf)
        bool first = true;
        const char *name;
 
-       ret = dwarf_entrypc(sp_die, &entry);
+       ret = die_entrypc(sp_die, &entry);
        if (ret)
                return ret;