perf probe: Move dwarf specific functions to dwarf-aux.c
authorRavi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Tue, 30 Aug 2016 08:39:37 +0000 (14:09 +0530)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 1 Sep 2016 15:42:26 +0000 (12:42 -0300)
Move generic dwarf related functions from util/probe-finder.c to
util/dwarf-aux.c. Functions name and their prototype are also changed
accordingly. No functionality changes.

Suggested-and-Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1472546377-25612-1-git-send-email-ravi.bangoria@linux.vnet.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/dwarf-aux.c
tools/perf/util/dwarf-aux.h
tools/perf/util/probe-finder.c

index a347b19..faec899 100644 (file)
@@ -1085,3 +1085,182 @@ int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,
        return -ENOTSUP;
 }
 #endif
+
+/*
+ * die_has_loclist - Check if DW_AT_location of @vr_die is a location list
+ * @vr_die: a variable DIE
+ */
+static bool die_has_loclist(Dwarf_Die *vr_die)
+{
+       Dwarf_Attribute loc;
+       int tag = dwarf_tag(vr_die);
+
+       if (tag != DW_TAG_formal_parameter &&
+           tag != DW_TAG_variable)
+               return false;
+
+       return (dwarf_attr_integrate(vr_die, DW_AT_location, &loc) &&
+               dwarf_whatform(&loc) == DW_FORM_sec_offset);
+}
+
+/*
+ * die_is_optimized_target - Check if target program is compiled with
+ * optimization
+ * @cu_die: a CU DIE
+ *
+ * For any object in given CU whose DW_AT_location is a location list,
+ * target program is compiled with optimization. This is applicable to
+ * clang as well.
+ */
+bool die_is_optimized_target(Dwarf_Die *cu_die)
+{
+       Dwarf_Die tmp_die;
+
+       if (die_has_loclist(cu_die))
+               return true;
+
+       if (!dwarf_child(cu_die, &tmp_die) &&
+           die_is_optimized_target(&tmp_die))
+               return true;
+
+       if (!dwarf_siblingof(cu_die, &tmp_die) &&
+           die_is_optimized_target(&tmp_die))
+               return true;
+
+       return false;
+}
+
+/*
+ * die_search_idx - Search index of given line address
+ * @lines: Line records of single CU
+ * @nr_lines: Number of @lines
+ * @addr: address we are looking for
+ * @idx: index to be set by this function (return value)
+ *
+ * Search for @addr by looping over every lines of CU. If address
+ * matches, set index of that line in @idx. Note that single source
+ * line can have multiple line records. i.e. single source line can
+ * have multiple index.
+ */
+static bool die_search_idx(Dwarf_Lines *lines, unsigned long nr_lines,
+                          Dwarf_Addr addr, unsigned long *idx)
+{
+       unsigned long i;
+       Dwarf_Addr tmp;
+
+       for (i = 0; i < nr_lines; i++) {
+               if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &tmp))
+                       return false;
+
+               if (tmp == addr) {
+                       *idx = i;
+                       return true;
+               }
+       }
+       return false;
+}
+
+/*
+ * die_get_postprologue_addr - Search next address after function prologue
+ * @entrypc_idx: entrypc index
+ * @lines: Line records of single CU
+ * @nr_lines: Number of @lines
+ * @hignpc: high PC address of function
+ * @postprologue_addr: Next address after function prologue (return value)
+ *
+ * Look for prologue-end marker. If there is no explicit marker, return
+ * address of next line record or next source line.
+ */
+static bool die_get_postprologue_addr(unsigned long entrypc_idx,
+                                     Dwarf_Lines *lines,
+                                     unsigned long nr_lines,
+                                     Dwarf_Addr highpc,
+                                     Dwarf_Addr *postprologue_addr)
+{
+       unsigned long i;
+       int entrypc_lno, lno;
+       Dwarf_Line *line;
+       Dwarf_Addr addr;
+       bool p_end;
+
+       /* entrypc_lno is actual source line number */
+       line = dwarf_onesrcline(lines, entrypc_idx);
+       if (dwarf_lineno(line, &entrypc_lno))
+               return false;
+
+       for (i = entrypc_idx; i < nr_lines; i++) {
+               line = dwarf_onesrcline(lines, i);
+
+               if (dwarf_lineaddr(line, &addr) ||
+                   dwarf_lineno(line, &lno)    ||
+                   dwarf_lineprologueend(line, &p_end))
+                       return false;
+
+               /* highpc is exclusive. [entrypc,highpc) */
+               if (addr >= highpc)
+                       break;
+
+               /* clang supports prologue-end marker */
+               if (p_end)
+                       break;
+
+               /* Actual next line in source */
+               if (lno != entrypc_lno)
+                       break;
+
+               /*
+                * Single source line can have multiple line records.
+                * For Example,
+                *     void foo() { printf("hello\n"); }
+                * contains two line records. One points to declaration and
+                * other points to printf() line. Variable 'lno' won't get
+                * incremented in this case but 'i' will.
+                */
+               if (i != entrypc_idx)
+                       break;
+       }
+
+       dwarf_lineaddr(line, postprologue_addr);
+       if (*postprologue_addr >= highpc)
+               dwarf_lineaddr(dwarf_onesrcline(lines, i - 1),
+                              postprologue_addr);
+
+       return true;
+}
+
+/*
+ * die_skip_prologue - Use next address after prologue as probe location
+ * @sp_die: a subprogram DIE
+ * @cu_die: a CU DIE
+ * @entrypc: entrypc of the function
+ *
+ * Function prologue prepares stack and registers before executing function
+ * logic. When target program is compiled without optimization, function
+ * parameter information is only valid after prologue. When we probe entrypc
+ * of the function, and try to record function parameter, it contains
+ * garbage value.
+ */
+void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
+                      Dwarf_Addr *entrypc)
+{
+       size_t nr_lines = 0;
+       unsigned long entrypc_idx = 0;
+       Dwarf_Lines *lines = NULL;
+       Dwarf_Addr postprologue_addr;
+       Dwarf_Addr highpc;
+
+       if (dwarf_highpc(sp_die, &highpc))
+               return;
+
+       if (dwarf_getsrclines(cu_die, &lines, &nr_lines))
+               return;
+
+       if (!die_search_idx(lines, nr_lines, *entrypc, &entrypc_idx))
+               return;
+
+       if (!die_get_postprologue_addr(entrypc_idx, lines, nr_lines,
+                                      highpc, &postprologue_addr))
+               return;
+
+       *entrypc = postprologue_addr;
+}
index dc0ce1a..8b6d2f8 100644 (file)
@@ -125,4 +125,12 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf);
 /* Get the name and type of given variable DIE, stored as "type\tname" */
 int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf);
 int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf);
+
+/* Check if target program is compiled with optimization */
+bool die_is_optimized_target(Dwarf_Die *cu_die);
+
+/* Use next address after prologue as probe location */
+void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
+                      Dwarf_Addr *entrypc);
+
 #endif
index 003ecad..8daca4f 100644 (file)
@@ -907,138 +907,6 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
        return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
 }
 
-static bool var_has_loclist(Dwarf_Die *cu_die)
-{
-       Dwarf_Attribute loc;
-       int tag = dwarf_tag(cu_die);
-
-       if (tag != DW_TAG_formal_parameter &&
-           tag != DW_TAG_variable)
-               return false;
-
-       return (dwarf_attr_integrate(cu_die, DW_AT_location, &loc) &&
-               dwarf_whatform(&loc) == DW_FORM_sec_offset);
-}
-
-/*
- * For any object in given CU whose DW_AT_location is a location list,
- * target program is compiled with optimization.
- */
-static bool optimized_target(Dwarf_Die *cu_die)
-{
-       Dwarf_Die tmp_die;
-
-       if (var_has_loclist(cu_die))
-               return true;
-
-       if (!dwarf_child(cu_die, &tmp_die) && optimized_target(&tmp_die))
-               return true;
-
-       if (!dwarf_siblingof(cu_die, &tmp_die) && optimized_target(&tmp_die))
-               return true;
-
-       return false;
-}
-
-static bool get_entrypc_idx(Dwarf_Lines *lines, unsigned long nr_lines,
-                           Dwarf_Addr pf_addr, unsigned long *entrypc_idx)
-{
-       unsigned long i;
-       Dwarf_Addr addr;
-
-       for (i = 0; i < nr_lines; i++) {
-               if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &addr))
-                       return false;
-
-               if (addr == pf_addr) {
-                       *entrypc_idx = i;
-                       return true;
-               }
-       }
-       return false;
-}
-
-static bool get_postprologue_addr(unsigned long entrypc_idx,
-                                 Dwarf_Lines *lines,
-                                 unsigned long nr_lines,
-                                 Dwarf_Addr highpc,
-                                 Dwarf_Addr *postprologue_addr)
-{
-       unsigned long i;
-       int entrypc_lno, lno;
-       Dwarf_Line *line;
-       Dwarf_Addr addr;
-       bool p_end;
-
-       /* entrypc_lno is actual source line number */
-       line = dwarf_onesrcline(lines, entrypc_idx);
-       if (dwarf_lineno(line, &entrypc_lno))
-               return false;
-
-       for (i = entrypc_idx; i < nr_lines; i++) {
-               line = dwarf_onesrcline(lines, i);
-
-               if (dwarf_lineaddr(line, &addr) ||
-                   dwarf_lineno(line, &lno)    ||
-                   dwarf_lineprologueend(line, &p_end))
-                       return false;
-
-               /* highpc is exclusive. [entrypc,highpc) */
-               if (addr >= highpc)
-                       break;
-
-               /* clang supports prologue-end marker */
-               if (p_end)
-                       break;
-
-               /* Actual next line in source */
-               if (lno != entrypc_lno)
-                       break;
-
-               /*
-                * Single source line can have multiple line records.
-                * For Example,
-                *     void foo() { printf("hello\n"); }
-                * contains two line records. One points to declaration and
-                * other points to printf() line. Variable 'lno' won't get
-                * incremented in this case but 'i' will.
-                */
-               if (i != entrypc_idx)
-                       break;
-       }
-
-       dwarf_lineaddr(line, postprologue_addr);
-       if (*postprologue_addr >= highpc)
-               dwarf_lineaddr(dwarf_onesrcline(lines, i - 1),
-                              postprologue_addr);
-
-       return true;
-}
-
-static void __skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)
-{
-       size_t nr_lines = 0;
-       unsigned long entrypc_idx = 0;
-       Dwarf_Lines *lines = NULL;
-       Dwarf_Addr postprologue_addr;
-       Dwarf_Addr highpc;
-
-       if (dwarf_highpc(sp_die, &highpc))
-               return;
-
-       if (dwarf_getsrclines(&pf->cu_die, &lines, &nr_lines))
-               return;
-
-       if (!get_entrypc_idx(lines, nr_lines, pf->addr, &entrypc_idx))
-               return;
-
-       if (!get_postprologue_addr(entrypc_idx, lines, nr_lines,
-                                  highpc, &postprologue_addr))
-               return;
-
-       pf->addr = postprologue_addr;
-}
-
 static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
        struct perf_probe_point *pp = &pf->pev->point;
@@ -1048,7 +916,7 @@ static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)
                return;
 
        /* Compiled with optimization? */
-       if (optimized_target(&pf->cu_die))
+       if (die_is_optimized_target(&pf->cu_die))
                return;
 
        /* Don't know entrypc? */
@@ -1068,7 +936,7 @@ static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)
                "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n",
                pf->addr);
 
-       __skip_prologue(sp_die, pf);
+       die_skip_prologue(sp_die, &pf->cu_die, &pf->addr);
 }
 
 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)