mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
perf probe: Move dwarf specific functions to dwarf-aux.c
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>
This commit is contained in:
parent
e47392bf9c
commit
6243b9dc4c
|
|
@ -1085,3 +1085,182 @@ int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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" */
|
/* 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_varname(Dwarf_Die *vr_die, struct strbuf *buf);
|
||||||
int die_get_var_range(Dwarf_Die *sp_die, 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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -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);
|
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)
|
static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)
|
||||||
{
|
{
|
||||||
struct perf_probe_point *pp = &pf->pev->point;
|
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;
|
return;
|
||||||
|
|
||||||
/* Compiled with optimization? */
|
/* Compiled with optimization? */
|
||||||
if (optimized_target(&pf->cu_die))
|
if (die_is_optimized_target(&pf->cu_die))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Don't know entrypc? */
|
/* 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",
|
"Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n",
|
||||||
pf->addr);
|
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)
|
static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user