|
@@ -458,6 +458,124 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
|
|
|
return die_find_child(sp_die, __die_find_inline_cb, &addr, 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 {
|
|
|
+ line_walk_handler_t handler;
|
|
|
+ void *data;
|
|
|
+ int retval;
|
|
|
+};
|
|
|
+
|
|
|
+/* Walk on decl lines in given DIE */
|
|
|
+static int __die_walk_funclines(Dwarf_Die *sp_die,
|
|
|
+ line_walk_handler_t handler, void *data)
|
|
|
+{
|
|
|
+ const char *fname;
|
|
|
+ Dwarf_Addr addr;
|
|
|
+ int lineno, ret = 0;
|
|
|
+
|
|
|
+ /* 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) {
|
|
|
+ ret = handler(fname, lineno, addr, data);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+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, ¶m, 0);
|
|
|
+ ret = param.retval;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
struct __find_variable_param {
|
|
|
const char *name;
|
|
|
Dwarf_Addr addr;
|
|
@@ -1050,43 +1168,26 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-/* Find probe point from its line number */
|
|
|
-static int find_probe_point_by_line(struct probe_finder *pf)
|
|
|
+static int probe_point_line_walker(const char *fname, int lineno,
|
|
|
+ Dwarf_Addr addr, void *data)
|
|
|
{
|
|
|
- Dwarf_Lines *lines;
|
|
|
- Dwarf_Line *line;
|
|
|
- size_t nlines, i;
|
|
|
- Dwarf_Addr addr;
|
|
|
- int lineno;
|
|
|
- int ret = 0;
|
|
|
+ struct probe_finder *pf = data;
|
|
|
+ int ret;
|
|
|
|
|
|
- if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
|
|
|
- pr_warning("No source lines found.\n");
|
|
|
- return -ENOENT;
|
|
|
- }
|
|
|
+ if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
|
|
|
+ return 0;
|
|
|
|
|
|
- for (i = 0; i < nlines && ret == 0; i++) {
|
|
|
- line = dwarf_onesrcline(lines, i);
|
|
|
- if (dwarf_lineno(line, &lineno) != 0 ||
|
|
|
- lineno != pf->lno)
|
|
|
- continue;
|
|
|
+ pf->addr = addr;
|
|
|
+ ret = call_probe_finder(NULL, pf);
|
|
|
|
|
|
- /* TODO: Get fileno from line, but how? */
|
|
|
- if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (dwarf_lineaddr(line, &addr) != 0) {
|
|
|
- pr_warning("Failed to get the address of the line.\n");
|
|
|
- return -ENOENT;
|
|
|
- }
|
|
|
- pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
|
|
|
- (int)i, lineno, (uintmax_t)addr);
|
|
|
- pf->addr = addr;
|
|
|
+ /* Continue if no error, because the line will be in inline function */
|
|
|
+ return ret < 0 ?: 0;
|
|
|
+}
|
|
|
|
|
|
- ret = call_probe_finder(NULL, pf);
|
|
|
- /* Continuing, because target line might be inlined. */
|
|
|
- }
|
|
|
- return ret;
|
|
|
+/* Find probe point from its line number */
|
|
|
+static int find_probe_point_by_line(struct probe_finder *pf)
|
|
|
+{
|
|
|
+ return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
|
|
|
}
|
|
|
|
|
|
/* Find lines which match lazy pattern */
|
|
@@ -1140,15 +1241,31 @@ out_close:
|
|
|
return nlines;
|
|
|
}
|
|
|
|
|
|
+static int probe_point_lazy_walker(const char *fname, int lineno,
|
|
|
+ Dwarf_Addr addr, void *data)
|
|
|
+{
|
|
|
+ struct probe_finder *pf = data;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (!line_list__has_line(&pf->lcache, lineno) ||
|
|
|
+ strtailcmp(fname, pf->fname) != 0)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ pr_debug("Probe line found: line:%d addr:0x%llx\n",
|
|
|
+ lineno, (unsigned long long)addr);
|
|
|
+ pf->addr = addr;
|
|
|
+ ret = call_probe_finder(NULL, pf);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Continue if no error, because the lazy pattern will match
|
|
|
+ * to other lines
|
|
|
+ */
|
|
|
+ return ret < 0 ?: 0;
|
|
|
+}
|
|
|
+
|
|
|
/* Find probe points from lazy pattern */
|
|
|
static int 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_Die die_mem;
|
|
|
- int lineno;
|
|
|
int ret = 0;
|
|
|
|
|
|
if (list_empty(&pf->lcache)) {
|
|
@@ -1162,45 +1279,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
|
|
|
- pr_warning("No source lines found.\n");
|
|
|
- return -ENOENT;
|
|
|
- }
|
|
|
-
|
|
|
- for (i = 0; i < nlines && ret >= 0; i++) {
|
|
|
- line = dwarf_onesrcline(lines, i);
|
|
|
-
|
|
|
- if (dwarf_lineno(line, &lineno) != 0 ||
|
|
|
- !line_list__has_line(&pf->lcache, lineno))
|
|
|
- continue;
|
|
|
-
|
|
|
- /* TODO: Get fileno from line, but how? */
|
|
|
- if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (dwarf_lineaddr(line, &addr) != 0) {
|
|
|
- pr_debug("Failed to get the address of line %d.\n",
|
|
|
- lineno);
|
|
|
- continue;
|
|
|
- }
|
|
|
- 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;
|
|
|
- }
|
|
|
-
|
|
|
- pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
|
|
|
- (int)i, lineno, (unsigned long long)addr);
|
|
|
- pf->addr = addr;
|
|
|
-
|
|
|
- ret = call_probe_finder(sp_die, pf);
|
|
|
- /* Continuing, because target line might be inlined. */
|
|
|
- }
|
|
|
- /* TODO: deallocate lines, but how? */
|
|
|
- return ret;
|
|
|
+ return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
|
|
|
}
|
|
|
|
|
|
/* Callback parameter with return value */
|
|
@@ -1644,91 +1723,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
|
|
|
return line_list__add_line(&lr->line_list, lineno);
|
|
|
}
|
|
|
|
|
|
-/* Search function declaration lines */
|
|
|
-static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
|
|
|
+static int line_range_walk_cb(const char *fname, int lineno,
|
|
|
+ Dwarf_Addr addr __used,
|
|
|
+ void *data)
|
|
|
{
|
|
|
- struct dwarf_callback_param *param = data;
|
|
|
- struct line_finder *lf = param->data;
|
|
|
- const char *src;
|
|
|
- int lineno;
|
|
|
-
|
|
|
- src = dwarf_decl_file(sp_die);
|
|
|
- if (src && strtailcmp(src, lf->fname) != 0)
|
|
|
- return DWARF_CB_OK;
|
|
|
+ struct line_finder *lf = data;
|
|
|
|
|
|
- if (dwarf_decl_line(sp_die, &lineno) != 0 ||
|
|
|
+ if ((strtailcmp(fname, lf->fname) != 0) ||
|
|
|
(lf->lno_s > lineno || lf->lno_e < lineno))
|
|
|
- return DWARF_CB_OK;
|
|
|
+ return 0;
|
|
|
|
|
|
- param->retval = line_range_add_line(src, lineno, lf->lr);
|
|
|
- if (param->retval < 0)
|
|
|
- return DWARF_CB_ABORT;
|
|
|
- return DWARF_CB_OK;
|
|
|
-}
|
|
|
+ if (line_range_add_line(fname, lineno, lf->lr) < 0)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
-static int find_line_range_func_decl_lines(struct line_finder *lf)
|
|
|
-{
|
|
|
- struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
|
|
|
- dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, ¶m, 0);
|
|
|
- return param.retval;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/* Find line range from its line number */
|
|
|
static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
|
|
|
{
|
|
|
- Dwarf_Lines *lines;
|
|
|
- Dwarf_Line *line;
|
|
|
- size_t nlines, i;
|
|
|
- Dwarf_Addr addr;
|
|
|
- int lineno, ret = 0;
|
|
|
- const char *src;
|
|
|
- Dwarf_Die die_mem;
|
|
|
-
|
|
|
- line_list__init(&lf->lr->line_list);
|
|
|
- if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
|
|
|
- pr_warning("No source lines found.\n");
|
|
|
- return -ENOENT;
|
|
|
- }
|
|
|
-
|
|
|
- /* Search probable lines on lines list */
|
|
|
- for (i = 0; i < nlines; i++) {
|
|
|
- line = dwarf_onesrcline(lines, i);
|
|
|
- if (dwarf_lineno(line, &lineno) != 0 ||
|
|
|
- (lf->lno_s > lineno || lf->lno_e < lineno))
|
|
|
- continue;
|
|
|
-
|
|
|
- if (sp_die) {
|
|
|
- /* Address filtering 1: does sp_die include addr? */
|
|
|
- if (dwarf_lineaddr(line, &addr) != 0 ||
|
|
|
- !dwarf_haspc(sp_die, addr))
|
|
|
- continue;
|
|
|
-
|
|
|
- /* Address filtering 2: No child include addr? */
|
|
|
- if (die_find_inlinefunc(sp_die, addr, &die_mem))
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- /* TODO: Get fileno from line, but how? */
|
|
|
- src = dwarf_linesrc(line, NULL, NULL);
|
|
|
- if (strtailcmp(src, lf->fname) != 0)
|
|
|
- continue;
|
|
|
-
|
|
|
- ret = line_range_add_line(src, lineno, lf->lr);
|
|
|
- if (ret < 0)
|
|
|
- return ret;
|
|
|
- }
|
|
|
+ int ret;
|
|
|
|
|
|
- /*
|
|
|
- * Dwarf lines doesn't include function declarations. We have to
|
|
|
- * check functions list or given function.
|
|
|
- */
|
|
|
- if (sp_die) {
|
|
|
- src = dwarf_decl_file(sp_die);
|
|
|
- if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
|
|
|
- (lf->lno_s <= lineno && lf->lno_e >= lineno))
|
|
|
- ret = line_range_add_line(src, lineno, lf->lr);
|
|
|
- } else
|
|
|
- ret = find_line_range_func_decl_lines(lf);
|
|
|
+ ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
|
|
|
|
|
|
/* Update status */
|
|
|
if (ret >= 0)
|
|
@@ -1758,9 +1774,6 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
|
|
|
struct line_finder *lf = param->data;
|
|
|
struct line_range *lr = lf->lr;
|
|
|
|
|
|
- pr_debug("find (%llx) %s\n",
|
|
|
- (unsigned long long)dwarf_dieoffset(sp_die),
|
|
|
- dwarf_diename(sp_die));
|
|
|
if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
|
|
|
die_compare_name(sp_die, lr->function)) {
|
|
|
lf->fname = dwarf_decl_file(sp_die);
|