probe-finder.c (ebfe1068f9ca4d0f25beca7a65d652380c40f226) probe-finder.c (9ef0438a957937bf0edc26d58bce891034ff9e30)
1/*
2 * probe-finder.c : C expression to kprobe event converter
3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or

--- 259 unchanged lines hidden (view full) ---

268 if (ref != NULL)
269 ref->offset = offs;
270 return ref;
271}
272
273/*
274 * Convert a location into trace_arg.
275 * If tvar == NULL, this just checks variable can be converted.
1/*
2 * probe-finder.c : C expression to kprobe event converter
3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or

--- 259 unchanged lines hidden (view full) ---

268 if (ref != NULL)
269 ref->offset = offs;
270 return ref;
271}
272
273/*
274 * Convert a location into trace_arg.
275 * If tvar == NULL, this just checks variable can be converted.
276 * If fentry == true and vr_die is a parameter, do huristic search
277 * for the location fuzzed by function entry mcount.
276 */
277static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
278 */
279static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
278 Dwarf_Op *fb_ops,
280 Dwarf_Op *fb_ops, Dwarf_Die *sp_die,
279 struct probe_trace_arg *tvar)
280{
281 Dwarf_Attribute attr;
281 struct probe_trace_arg *tvar)
282{
283 Dwarf_Attribute attr;
284 Dwarf_Addr tmp = 0;
282 Dwarf_Op *op;
283 size_t nops;
284 unsigned int regn;
285 Dwarf_Word offs = 0;
286 bool ref = false;
287 const char *regs;
288 int ret;
289
290 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
291 goto static_var;
292
293 /* TODO: handle more than 1 exprs */
285 Dwarf_Op *op;
286 size_t nops;
287 unsigned int regn;
288 Dwarf_Word offs = 0;
289 bool ref = false;
290 const char *regs;
291 int ret;
292
293 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
294 goto static_var;
295
296 /* TODO: handle more than 1 exprs */
294 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
295 dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
296 nops == 0) {
297 /* TODO: Support const_value */
297 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
298 return -EINVAL; /* Broken DIE ? */
299 if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) {
300 ret = dwarf_entrypc(sp_die, &tmp);
301 if (ret || addr != tmp ||
302 dwarf_tag(vr_die) != DW_TAG_formal_parameter ||
303 dwarf_highpc(sp_die, &tmp))
304 return -ENOENT;
305 /*
306 * This is fuzzed by fentry mcount. We try to find the
307 * parameter location at the earliest address.
308 */
309 for (addr += 1; addr <= tmp; addr++) {
310 if (dwarf_getlocation_addr(&attr, addr, &op,
311 &nops, 1) > 0)
312 goto found;
313 }
298 return -ENOENT;
299 }
314 return -ENOENT;
315 }
316found:
317 if (nops == 0)
318 /* TODO: Support const_value */
319 return -ENOENT;
300
301 if (op->atom == DW_OP_addr) {
302static_var:
303 if (!tvar)
304 return 0;
305 /* Static variables on memory (not stack), make @varname */
306 ret = strlen(dwarf_diename(vr_die));
307 tvar->value = zalloc(ret + 2);

--- 250 unchanged lines hidden (view full) ---

558 if (!ref) {
559 pr_warning("Structure on a register is not "
560 "supported yet.\n");
561 return -ENOTSUP;
562 }
563 }
564
565 if (die_find_member(&type, field->name, die_mem) == NULL) {
320
321 if (op->atom == DW_OP_addr) {
322static_var:
323 if (!tvar)
324 return 0;
325 /* Static variables on memory (not stack), make @varname */
326 ret = strlen(dwarf_diename(vr_die));
327 tvar->value = zalloc(ret + 2);

--- 250 unchanged lines hidden (view full) ---

578 if (!ref) {
579 pr_warning("Structure on a register is not "
580 "supported yet.\n");
581 return -ENOTSUP;
582 }
583 }
584
585 if (die_find_member(&type, field->name, die_mem) == NULL) {
566 pr_warning("%s(tyep:%s) has no member %s.\n", varname,
586 pr_warning("%s(type:%s) has no member %s.\n", varname,
567 dwarf_diename(&type), field->name);
568 return -EINVAL;
569 }
570
571 /* Get the offset of the field */
572 if (tag == DW_TAG_union_type) {
573 offs = 0;
574 } else {

--- 20 unchanged lines hidden (view full) ---

595{
596 Dwarf_Die die_mem;
597 int ret;
598
599 pr_debug("Converting variable %s into trace event.\n",
600 dwarf_diename(vr_die));
601
602 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
587 dwarf_diename(&type), field->name);
588 return -EINVAL;
589 }
590
591 /* Get the offset of the field */
592 if (tag == DW_TAG_union_type) {
593 offs = 0;
594 } else {

--- 20 unchanged lines hidden (view full) ---

615{
616 Dwarf_Die die_mem;
617 int ret;
618
619 pr_debug("Converting variable %s into trace event.\n",
620 dwarf_diename(vr_die));
621
622 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
603 pf->tvar);
623 &pf->sp_die, pf->tvar);
604 if (ret == -ENOENT)
605 pr_err("Failed to find the location of %s at this address.\n"
606 " Perhaps, it has been optimized out.\n", pf->pvar->var);
607 else if (ret == -ENOTSUP)
608 pr_err("Sorry, we don't support this variable location yet.\n");
609 else if (pf->pvar->field) {
610 ret = convert_variable_fields(vr_die, pf->pvar->var,
611 pf->pvar->field, &pf->tvar->ref,

--- 519 unchanged lines hidden (view full) ---

1131 }
1132
1133found:
1134 line_list__free(&pf->lcache);
1135
1136 return ret;
1137}
1138
624 if (ret == -ENOENT)
625 pr_err("Failed to find the location of %s at this address.\n"
626 " Perhaps, it has been optimized out.\n", pf->pvar->var);
627 else if (ret == -ENOTSUP)
628 pr_err("Sorry, we don't support this variable location yet.\n");
629 else if (pf->pvar->field) {
630 ret = convert_variable_fields(vr_die, pf->pvar->var,
631 pf->pvar->field, &pf->tvar->ref,

--- 519 unchanged lines hidden (view full) ---

1151 }
1152
1153found:
1154 line_list__free(&pf->lcache);
1155
1156 return ret;
1157}
1158
1159struct local_vars_finder {
1160 struct probe_finder *pf;
1161 struct perf_probe_arg *args;
1162 int max_args;
1163 int nargs;
1164 int ret;
1165};
1166
1167/* Collect available variables in this scope */
1168static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
1169{
1170 struct local_vars_finder *vf = data;
1171 struct probe_finder *pf = vf->pf;
1172 int tag;
1173
1174 tag = dwarf_tag(die_mem);
1175 if (tag == DW_TAG_formal_parameter ||
1176 tag == DW_TAG_variable) {
1177 if (convert_variable_location(die_mem, vf->pf->addr,
1178 vf->pf->fb_ops, &pf->sp_die,
1179 NULL) == 0) {
1180 vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
1181 if (vf->args[vf->nargs].var == NULL) {
1182 vf->ret = -ENOMEM;
1183 return DIE_FIND_CB_END;
1184 }
1185 pr_debug(" %s", vf->args[vf->nargs].var);
1186 vf->nargs++;
1187 }
1188 }
1189
1190 if (dwarf_haspc(die_mem, vf->pf->addr))
1191 return DIE_FIND_CB_CONTINUE;
1192 else
1193 return DIE_FIND_CB_SIBLING;
1194}
1195
1196static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf,
1197 struct perf_probe_arg *args)
1198{
1199 Dwarf_Die die_mem;
1200 int i;
1201 int n = 0;
1202 struct local_vars_finder vf = {.pf = pf, .args = args,
1203 .max_args = MAX_PROBE_ARGS, .ret = 0};
1204
1205 for (i = 0; i < pf->pev->nargs; i++) {
1206 /* var never be NULL */
1207 if (strcmp(pf->pev->args[i].var, "$vars") == 0) {
1208 pr_debug("Expanding $vars into:");
1209 vf.nargs = n;
1210 /* Special local variables */
1211 die_find_child(sc_die, copy_variables_cb, (void *)&vf,
1212 &die_mem);
1213 pr_debug(" (%d)\n", vf.nargs - n);
1214 if (vf.ret < 0)
1215 return vf.ret;
1216 n = vf.nargs;
1217 } else {
1218 /* Copy normal argument */
1219 args[n] = pf->pev->args[i];
1220 n++;
1221 }
1222 }
1223 return n;
1224}
1225
1139/* Add a found probe point into trace event list */
1140static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1141{
1142 struct trace_event_finder *tf =
1143 container_of(pf, struct trace_event_finder, pf);
1144 struct probe_trace_event *tev;
1226/* Add a found probe point into trace event list */
1227static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1228{
1229 struct trace_event_finder *tf =
1230 container_of(pf, struct trace_event_finder, pf);
1231 struct probe_trace_event *tev;
1232 struct perf_probe_arg *args;
1145 int ret, i;
1146
1147 /* Check number of tevs */
1148 if (tf->ntevs == tf->max_tevs) {
1149 pr_warning("Too many( > %d) probe point found.\n",
1150 tf->max_tevs);
1151 return -ERANGE;
1152 }
1153 tev = &tf->tevs[tf->ntevs++];
1154
1155 /* Trace point should be converted from subprogram DIE */
1156 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
1157 pf->pev->point.retprobe, &tev->point);
1158 if (ret < 0)
1159 return ret;
1160
1161 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1162 tev->point.offset);
1163
1233 int ret, i;
1234
1235 /* Check number of tevs */
1236 if (tf->ntevs == tf->max_tevs) {
1237 pr_warning("Too many( > %d) probe point found.\n",
1238 tf->max_tevs);
1239 return -ERANGE;
1240 }
1241 tev = &tf->tevs[tf->ntevs++];
1242
1243 /* Trace point should be converted from subprogram DIE */
1244 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
1245 pf->pev->point.retprobe, &tev->point);
1246 if (ret < 0)
1247 return ret;
1248
1249 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1250 tev->point.offset);
1251
1164 /* Find each argument */
1165 tev->nargs = pf->pev->nargs;
1166 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1167 if (tev->args == NULL)
1252 /* Expand special probe argument if exist */
1253 args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
1254 if (args == NULL)
1168 return -ENOMEM;
1255 return -ENOMEM;
1169 for (i = 0; i < pf->pev->nargs; i++) {
1170 pf->pvar = &pf->pev->args[i];
1256
1257 ret = expand_probe_args(sc_die, pf, args);
1258 if (ret < 0)
1259 goto end;
1260
1261 tev->nargs = ret;
1262 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1263 if (tev->args == NULL) {
1264 ret = -ENOMEM;
1265 goto end;
1266 }
1267
1268 /* Find each argument */
1269 for (i = 0; i < tev->nargs; i++) {
1270 pf->pvar = &args[i];
1171 pf->tvar = &tev->args[i];
1172 /* Variable should be found from scope DIE */
1173 ret = find_variable(sc_die, pf);
1174 if (ret != 0)
1271 pf->tvar = &tev->args[i];
1272 /* Variable should be found from scope DIE */
1273 ret = find_variable(sc_die, pf);
1274 if (ret != 0)
1175 return ret;
1275 break;
1176 }
1177
1276 }
1277
1178 return 0;
1278end:
1279 free(args);
1280 return ret;
1179}
1180
1181/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1182int debuginfo__find_trace_events(struct debuginfo *self,
1183 struct perf_probe_event *pev,
1184 struct probe_trace_event **tevs, int max_tevs)
1185{
1186 struct trace_event_finder tf = {

--- 30 unchanged lines hidden (view full) ---

1217 int tag, ret;
1218
1219 vl = &af->vls[af->nvls - 1];
1220
1221 tag = dwarf_tag(die_mem);
1222 if (tag == DW_TAG_formal_parameter ||
1223 tag == DW_TAG_variable) {
1224 ret = convert_variable_location(die_mem, af->pf.addr,
1281}
1282
1283/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1284int debuginfo__find_trace_events(struct debuginfo *self,
1285 struct perf_probe_event *pev,
1286 struct probe_trace_event **tevs, int max_tevs)
1287{
1288 struct trace_event_finder tf = {

--- 30 unchanged lines hidden (view full) ---

1319 int tag, ret;
1320
1321 vl = &af->vls[af->nvls - 1];
1322
1323 tag = dwarf_tag(die_mem);
1324 if (tag == DW_TAG_formal_parameter ||
1325 tag == DW_TAG_variable) {
1326 ret = convert_variable_location(die_mem, af->pf.addr,
1225 af->pf.fb_ops, NULL);
1327 af->pf.fb_ops, &af->pf.sp_die,
1328 NULL);
1226 if (ret == 0) {
1227 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
1228 pr_debug2("Add new var: %s\n", buf);
1229 if (ret > 0)
1230 strlist__add(vl->vars, buf);
1231 }
1232 }
1233

--- 375 unchanged lines hidden ---
1329 if (ret == 0) {
1330 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
1331 pr_debug2("Add new var: %s\n", buf);
1332 if (ret > 0)
1333 strlist__add(vl->vars, buf);
1334 }
1335 }
1336

--- 375 unchanged lines hidden ---