|
@@ -273,12 +273,15 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
|
|
|
/*
|
|
|
* Convert a location into trace_arg.
|
|
|
* If tvar == NULL, this just checks variable can be converted.
|
|
|
+ * If fentry == true and vr_die is a parameter, do huristic search
|
|
|
+ * for the location fuzzed by function entry mcount.
|
|
|
*/
|
|
|
static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
|
|
|
- Dwarf_Op *fb_ops,
|
|
|
+ Dwarf_Op *fb_ops, Dwarf_Die *sp_die,
|
|
|
struct probe_trace_arg *tvar)
|
|
|
{
|
|
|
Dwarf_Attribute attr;
|
|
|
+ Dwarf_Addr tmp = 0;
|
|
|
Dwarf_Op *op;
|
|
|
size_t nops;
|
|
|
unsigned int regn;
|
|
@@ -291,12 +294,29 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
|
|
|
goto static_var;
|
|
|
|
|
|
/* TODO: handle more than 1 exprs */
|
|
|
- if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
|
|
|
- dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
|
|
|
- nops == 0) {
|
|
|
- /* TODO: Support const_value */
|
|
|
+ if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
|
|
|
+ return -EINVAL; /* Broken DIE ? */
|
|
|
+ if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) {
|
|
|
+ ret = dwarf_entrypc(sp_die, &tmp);
|
|
|
+ if (ret || addr != tmp ||
|
|
|
+ dwarf_tag(vr_die) != DW_TAG_formal_parameter ||
|
|
|
+ dwarf_highpc(sp_die, &tmp))
|
|
|
+ return -ENOENT;
|
|
|
+ /*
|
|
|
+ * This is fuzzed by fentry mcount. We try to find the
|
|
|
+ * parameter location at the earliest address.
|
|
|
+ */
|
|
|
+ for (addr += 1; addr <= tmp; addr++) {
|
|
|
+ if (dwarf_getlocation_addr(&attr, addr, &op,
|
|
|
+ &nops, 1) > 0)
|
|
|
+ goto found;
|
|
|
+ }
|
|
|
return -ENOENT;
|
|
|
}
|
|
|
+found:
|
|
|
+ if (nops == 0)
|
|
|
+ /* TODO: Support const_value */
|
|
|
+ return -ENOENT;
|
|
|
|
|
|
if (op->atom == DW_OP_addr) {
|
|
|
static_var:
|
|
@@ -600,7 +620,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
|
|
|
dwarf_diename(vr_die));
|
|
|
|
|
|
ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
|
|
|
- pf->tvar);
|
|
|
+ &pf->sp_die, pf->tvar);
|
|
|
if (ret == -ENOENT)
|
|
|
pr_err("Failed to find the location of %s at this address.\n"
|
|
|
" Perhaps, it has been optimized out.\n", pf->pvar->var);
|
|
@@ -1148,13 +1168,15 @@ struct local_vars_finder {
|
|
|
static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
|
|
|
{
|
|
|
struct local_vars_finder *vf = data;
|
|
|
+ struct probe_finder *pf = vf->pf;
|
|
|
int tag;
|
|
|
|
|
|
tag = dwarf_tag(die_mem);
|
|
|
if (tag == DW_TAG_formal_parameter ||
|
|
|
tag == DW_TAG_variable) {
|
|
|
if (convert_variable_location(die_mem, vf->pf->addr,
|
|
|
- vf->pf->fb_ops, NULL) == 0) {
|
|
|
+ vf->pf->fb_ops, &pf->sp_die,
|
|
|
+ NULL) == 0) {
|
|
|
vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
|
|
|
if (vf->args[vf->nargs].var == NULL) {
|
|
|
vf->ret = -ENOMEM;
|
|
@@ -1302,7 +1324,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
|
|
|
if (tag == DW_TAG_formal_parameter ||
|
|
|
tag == DW_TAG_variable) {
|
|
|
ret = convert_variable_location(die_mem, af->pf.addr,
|
|
|
- af->pf.fb_ops, NULL);
|
|
|
+ af->pf.fb_ops, &af->pf.sp_die,
|
|
|
+ NULL);
|
|
|
if (ret == 0) {
|
|
|
ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
|
|
|
pr_debug2("Add new var: %s\n", buf);
|