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 --- |