|
@@ -273,6 +273,25 @@ static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
|
|
|
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;
|
|
|
+}
|
|
|
+
|
|
|
/* Compare diename and tname */
|
|
|
static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
|
|
|
{
|
|
@@ -1704,11 +1723,9 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
|
|
|
Dwarf_Die cudie, spdie, indie;
|
|
|
Dwarf *dbg = NULL;
|
|
|
Dwfl *dwfl = NULL;
|
|
|
- Dwarf_Line *line;
|
|
|
- Dwarf_Addr laddr, eaddr, bias = 0;
|
|
|
- const char *tmp;
|
|
|
- int lineno, ret = 0;
|
|
|
- bool found = false;
|
|
|
+ Dwarf_Addr _addr, baseaddr, bias = 0;
|
|
|
+ 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);
|
|
@@ -1729,68 +1746,79 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
|
|
|
goto end;
|
|
|
}
|
|
|
|
|
|
- /* Find a corresponding line */
|
|
|
- line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
|
|
|
- if (line) {
|
|
|
- if (dwarf_lineaddr(line, &laddr) == 0 &&
|
|
|
- (Dwarf_Addr)addr == laddr &&
|
|
|
- dwarf_lineno(line, &lineno) == 0) {
|
|
|
- tmp = dwarf_linesrc(line, NULL, NULL);
|
|
|
- if (tmp) {
|
|
|
- ppt->line = lineno;
|
|
|
- ppt->file = strdup(tmp);
|
|
|
- if (ppt->file == NULL) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto end;
|
|
|
- }
|
|
|
- found = true;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ /* Find a corresponding line (filename and lineno) */
|
|
|
+ cu_find_lineinfo(&cudie, addr, &fname, &lineno);
|
|
|
+ /* Don't care whether it failed or not */
|
|
|
|
|
|
- /* Find a corresponding function */
|
|
|
+ /* Find a corresponding function (name, baseline and baseaddr) */
|
|
|
if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
|
|
|
+ /* Get function entry information */
|
|
|
tmp = dwarf_diename(&spdie);
|
|
|
- if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0)
|
|
|
- goto end;
|
|
|
-
|
|
|
- if (ppt->line) {
|
|
|
- if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
|
|
|
- &indie)) {
|
|
|
- /* addr in an inline function */
|
|
|
+ if (!tmp ||
|
|
|
+ dwarf_entrypc(&spdie, &baseaddr) != 0 ||
|
|
|
+ dwarf_decl_line(&spdie, &baseline) != 0)
|
|
|
+ goto post;
|
|
|
+ func = tmp;
|
|
|
+
|
|
|
+ if (addr == (unsigned long)baseaddr)
|
|
|
+ /* Function entry - Relative line number is 0 */
|
|
|
+ lineno = baseline;
|
|
|
+ else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
|
|
|
+ &indie)) {
|
|
|
+ if (dwarf_entrypc(&indie, &_addr) == 0 &&
|
|
|
+ _addr == addr)
|
|
|
+ /*
|
|
|
+ * addr is at an inline function entry.
|
|
|
+ * In this case, lineno should be the call-site
|
|
|
+ * line number.
|
|
|
+ */
|
|
|
+ lineno = die_get_call_lineno(&indie);
|
|
|
+ else {
|
|
|
+ /*
|
|
|
+ * addr is in an inline function body.
|
|
|
+ * Since lineno points one of the lines
|
|
|
+ * of the inline function, baseline should
|
|
|
+ * be the entry line of the inline function.
|
|
|
+ */
|
|
|
tmp = dwarf_diename(&indie);
|
|
|
- if (!tmp)
|
|
|
- goto end;
|
|
|
- ret = dwarf_decl_line(&indie, &lineno);
|
|
|
- } else {
|
|
|
- if (eaddr == addr) { /* Function entry */
|
|
|
- lineno = ppt->line;
|
|
|
- ret = 0;
|
|
|
- } else
|
|
|
- ret = dwarf_decl_line(&spdie, &lineno);
|
|
|
- }
|
|
|
- if (ret == 0) {
|
|
|
- /* Make a relative line number */
|
|
|
- ppt->line -= lineno;
|
|
|
- goto found;
|
|
|
+ if (tmp &&
|
|
|
+ dwarf_decl_line(&spdie, &baseline) == 0)
|
|
|
+ func = tmp;
|
|
|
}
|
|
|
}
|
|
|
- /* We don't have a line number, let's use offset */
|
|
|
- ppt->offset = addr - (unsigned long)eaddr;
|
|
|
-found:
|
|
|
- ppt->function = strdup(tmp);
|
|
|
+ }
|
|
|
+
|
|
|
+post:
|
|
|
+ /* Make a relative line number or an offset */
|
|
|
+ if (lineno)
|
|
|
+ ppt->line = lineno - baseline;
|
|
|
+ else if (func)
|
|
|
+ ppt->offset = addr - (unsigned long)baseaddr;
|
|
|
+
|
|
|
+ /* Duplicate strings */
|
|
|
+ if (func) {
|
|
|
+ ppt->function = strdup(func);
|
|
|
if (ppt->function == NULL) {
|
|
|
ret = -ENOMEM;
|
|
|
goto end;
|
|
|
}
|
|
|
- found = true;
|
|
|
}
|
|
|
-
|
|
|
+ if (fname) {
|
|
|
+ ppt->file = strdup(fname);
|
|
|
+ if (ppt->file == NULL) {
|
|
|
+ if (ppt->function) {
|
|
|
+ free(ppt->function);
|
|
|
+ ppt->function = NULL;
|
|
|
+ }
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto end;
|
|
|
+ }
|
|
|
+ }
|
|
|
end:
|
|
|
if (dwfl)
|
|
|
dwfl_end(dwfl);
|
|
|
- if (ret >= 0)
|
|
|
- ret = found ? 1 : 0;
|
|
|
+ if (ret == 0 && (fname || func))
|
|
|
+ ret = 1; /* Found a point */
|
|
|
return ret;
|
|
|
}
|
|
|
|