probe-finder.c (7c7145f6acc68100dbdc5d3c5c64fe3af1c99c89) | probe-finder.c (48481938b02471d505296d7557ed296eb093d496) |
---|---|
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 --- 111 unchanged lines hidden (view full) --- 120 goto found; 121 } else if (ln->line == line) /* Already exist */ 122 return ; 123 } 124 /* List is empty, or the smallest entry */ 125 p = head; 126found: 127 pr_debug("line list: add a line %u\n", line); | 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 --- 111 unchanged lines hidden (view full) --- 120 goto found; 121 } else if (ln->line == line) /* Already exist */ 122 return ; 123 } 124 /* List is empty, or the smallest entry */ 125 p = head; 126found: 127 pr_debug("line list: add a line %u\n", line); |
128 ln = zalloc(sizeof(struct line_node)); 129 DIE_IF(ln == NULL); | 128 ln = xzalloc(sizeof(struct line_node)); |
130 ln->line = line; 131 INIT_LIST_HEAD(&ln->list); 132 list_add(&ln->list, p); 133} 134 135/* Check if the line in line number list */ 136static int line_list__has_line(struct list_head *head, unsigned int line) 137{ --- 41 unchanged lines hidden (view full) --- 179 if (ret != 0) 180 return NULL; 181 182 for (i = 0; i < nfiles; i++) { 183 src = dwarf_filesrc(files, i, NULL, NULL); 184 if (strtailcmp(src, fname) == 0) 185 break; 186 } | 129 ln->line = line; 130 INIT_LIST_HEAD(&ln->list); 131 list_add(&ln->list, p); 132} 133 134/* Check if the line in line number list */ 135static int line_list__has_line(struct list_head *head, unsigned int line) 136{ --- 41 unchanged lines hidden (view full) --- 178 if (ret != 0) 179 return NULL; 180 181 for (i = 0; i < nfiles; i++) { 182 src = dwarf_filesrc(files, i, NULL, NULL); 183 if (strtailcmp(src, fname) == 0) 184 break; 185 } |
186 if (i == nfiles) 187 return NULL; |
|
187 return src; 188} 189 | 188 return src; 189} 190 |
191/* Compare diename and tname */ 192static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 193{ 194 const char *name; 195 name = dwarf_diename(dw_die); 196 DIE_IF(name == NULL); 197 return strcmp(tname, name); 198} 199 200/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 201static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) 202{ 203 Dwarf_Addr epc; 204 int ret; 205 206 ret = dwarf_entrypc(dw_die, &epc); 207 DIE_IF(ret == -1); 208 return epc; 209} 210 211/* Get type die, but skip qualifiers and typedef */ 212static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 213{ 214 Dwarf_Attribute attr; 215 int tag; 216 217 do { 218 if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL || 219 dwarf_formref_die(&attr, die_mem) == NULL) 220 return NULL; 221 222 tag = dwarf_tag(die_mem); 223 vr_die = die_mem; 224 } while (tag == DW_TAG_const_type || 225 tag == DW_TAG_restrict_type || 226 tag == DW_TAG_volatile_type || 227 tag == DW_TAG_shared_type || 228 tag == DW_TAG_typedef); 229 230 return die_mem; 231} 232 233/* Return values for die_find callbacks */ 234enum { 235 DIE_FIND_CB_FOUND = 0, /* End of Search */ 236 DIE_FIND_CB_CHILD = 1, /* Search only children */ 237 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */ 238 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */ 239}; 240 241/* Search a child die */ 242static Dwarf_Die *die_find_child(Dwarf_Die *rt_die, 243 int (*callback)(Dwarf_Die *, void *), 244 void *data, Dwarf_Die *die_mem) 245{ 246 Dwarf_Die child_die; 247 int ret; 248 249 ret = dwarf_child(rt_die, die_mem); 250 if (ret != 0) 251 return NULL; 252 253 do { 254 ret = callback(die_mem, data); 255 if (ret == DIE_FIND_CB_FOUND) 256 return die_mem; 257 258 if ((ret & DIE_FIND_CB_CHILD) && 259 die_find_child(die_mem, callback, data, &child_die)) { 260 memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); 261 return die_mem; 262 } 263 } while ((ret & DIE_FIND_CB_SIBLING) && 264 dwarf_siblingof(die_mem, die_mem) == 0); 265 266 return NULL; 267} 268 |
|
190struct __addr_die_search_param { 191 Dwarf_Addr addr; 192 Dwarf_Die *die_mem; 193}; 194 195static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) 196{ 197 struct __addr_die_search_param *ad = data; 198 199 if (dwarf_tag(fn_die) == DW_TAG_subprogram && 200 dwarf_haspc(fn_die, ad->addr)) { 201 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); 202 return DWARF_CB_ABORT; 203 } 204 return DWARF_CB_OK; 205} 206 207/* Search a real subprogram including this line, */ | 269struct __addr_die_search_param { 270 Dwarf_Addr addr; 271 Dwarf_Die *die_mem; 272}; 273 274static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) 275{ 276 struct __addr_die_search_param *ad = data; 277 278 if (dwarf_tag(fn_die) == DW_TAG_subprogram && 279 dwarf_haspc(fn_die, ad->addr)) { 280 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); 281 return DWARF_CB_ABORT; 282 } 283 return DWARF_CB_OK; 284} 285 286/* Search a real subprogram including this line, */ |
208static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, 209 Dwarf_Die *die_mem) | 287static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, 288 Dwarf_Die *die_mem) |
210{ 211 struct __addr_die_search_param ad; 212 ad.addr = addr; 213 ad.die_mem = die_mem; 214 /* dwarf_getscopes can't find subprogram. */ 215 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) 216 return NULL; 217 else 218 return die_mem; 219} 220 | 289{ 290 struct __addr_die_search_param ad; 291 ad.addr = addr; 292 ad.die_mem = die_mem; 293 /* dwarf_getscopes can't find subprogram. */ 294 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) 295 return NULL; 296 else 297 return die_mem; 298} 299 |
221/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ 222static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 223 Dwarf_Die *die_mem) | 300/* die_find callback for inline function search */ 301static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) |
224{ | 302{ |
225 Dwarf_Die child_die; 226 int ret; | 303 Dwarf_Addr *addr = data; |
227 | 304 |
228 ret = dwarf_child(sp_die, die_mem); 229 if (ret != 0) 230 return NULL; | 305 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && 306 dwarf_haspc(die_mem, *addr)) 307 return DIE_FIND_CB_FOUND; |
231 | 308 |
232 do { 233 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && 234 dwarf_haspc(die_mem, addr)) 235 return die_mem; 236 237 if (die_get_inlinefunc(die_mem, addr, &child_die)) { 238 memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); 239 return die_mem; 240 } 241 } while (dwarf_siblingof(die_mem, die_mem) == 0); 242 243 return NULL; | 309 return DIE_FIND_CB_CONTINUE; |
244} 245 | 310} 311 |
246/* Compare diename and tname */ 247static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | 312/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ 313static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 314 Dwarf_Die *die_mem) |
248{ | 315{ |
249 const char *name; 250 name = dwarf_diename(dw_die); 251 DIE_IF(name == NULL); 252 return strcmp(tname, name); | 316 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); |
253} 254 | 317} 318 |
255/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 256static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) | 319static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) |
257{ | 320{ |
258 Dwarf_Addr epc; 259 int ret; | 321 const char *name = data; 322 int tag; |
260 | 323 |
261 ret = dwarf_entrypc(dw_die, &epc); 262 DIE_IF(ret == -1); 263 return epc; | 324 tag = dwarf_tag(die_mem); 325 if ((tag == DW_TAG_formal_parameter || 326 tag == DW_TAG_variable) && 327 (die_compare_name(die_mem, name) == 0)) 328 return DIE_FIND_CB_FOUND; 329 330 return DIE_FIND_CB_CONTINUE; |
264} 265 | 331} 332 |
266/* Get a variable die */ | 333/* Find a variable called 'name' */ |
267static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, 268 Dwarf_Die *die_mem) 269{ | 334static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, 335 Dwarf_Die *die_mem) 336{ |
270 Dwarf_Die child_die; 271 int tag; 272 int ret; | 337 return die_find_child(sp_die, __die_find_variable_cb, (void *)name, 338 die_mem); 339} |
273 | 340 |
274 ret = dwarf_child(sp_die, die_mem); 275 if (ret != 0) 276 return NULL; | 341static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) 342{ 343 const char *name = data; |
277 | 344 |
278 do { 279 tag = dwarf_tag(die_mem); 280 if ((tag == DW_TAG_formal_parameter || 281 tag == DW_TAG_variable) && 282 (die_compare_name(die_mem, name) == 0)) 283 return die_mem; | 345 if ((dwarf_tag(die_mem) == DW_TAG_member) && 346 (die_compare_name(die_mem, name) == 0)) 347 return DIE_FIND_CB_FOUND; |
284 | 348 |
285 if (die_find_variable(die_mem, name, &child_die)) { 286 memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); 287 return die_mem; 288 } 289 } while (dwarf_siblingof(die_mem, die_mem) == 0); | 349 return DIE_FIND_CB_SIBLING; 350} |
290 | 351 |
291 return NULL; | 352/* Find a member called 'name' */ 353static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, 354 Dwarf_Die *die_mem) 355{ 356 return die_find_child(st_die, __die_find_member_cb, (void *)name, 357 die_mem); |
292} 293 294/* 295 * Probe finder related functions 296 */ 297 298/* Show a location */ | 358} 359 360/* 361 * Probe finder related functions 362 */ 363 364/* Show a location */ |
299static void show_location(Dwarf_Op *op, struct probe_finder *pf) | 365static void convert_location(Dwarf_Op *op, struct probe_finder *pf) |
300{ 301 unsigned int regn; 302 Dwarf_Word offs = 0; | 366{ 367 unsigned int regn; 368 Dwarf_Word offs = 0; |
303 int deref = 0, ret; | 369 bool ref = false; |
304 const char *regs; | 370 const char *regs; |
371 struct kprobe_trace_arg *tvar = pf->tvar; |
|
305 306 /* TODO: support CFA */ 307 /* If this is based on frame buffer, set the offset */ 308 if (op->atom == DW_OP_fbreg) { 309 if (pf->fb_ops == NULL) 310 die("The attribute of frame base is not supported.\n"); | 372 373 /* TODO: support CFA */ 374 /* If this is based on frame buffer, set the offset */ 375 if (op->atom == DW_OP_fbreg) { 376 if (pf->fb_ops == NULL) 377 die("The attribute of frame base is not supported.\n"); |
311 deref = 1; | 378 ref = true; |
312 offs = op->number; 313 op = &pf->fb_ops[0]; 314 } 315 316 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 317 regn = op->atom - DW_OP_breg0; 318 offs += op->number; | 379 offs = op->number; 380 op = &pf->fb_ops[0]; 381 } 382 383 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 384 regn = op->atom - DW_OP_breg0; 385 offs += op->number; |
319 deref = 1; | 386 ref = true; |
320 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 321 regn = op->atom - DW_OP_reg0; 322 } else if (op->atom == DW_OP_bregx) { 323 regn = op->number; 324 offs += op->number2; | 387 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 388 regn = op->atom - DW_OP_reg0; 389 } else if (op->atom == DW_OP_bregx) { 390 regn = op->number; 391 offs += op->number2; |
325 deref = 1; | 392 ref = true; |
326 } else if (op->atom == DW_OP_regx) { 327 regn = op->number; 328 } else 329 die("DW_OP %d is not supported.", op->atom); 330 331 regs = get_arch_regstr(regn); 332 if (!regs) 333 die("%u exceeds max register number.", regn); 334 | 393 } else if (op->atom == DW_OP_regx) { 394 regn = op->number; 395 } else 396 die("DW_OP %d is not supported.", op->atom); 397 398 regs = get_arch_regstr(regn); 399 if (!regs) 400 die("%u exceeds max register number.", regn); 401 |
335 if (deref) 336 ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)", 337 pf->var, (intmax_t)offs, regs); 338 else 339 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 340 DIE_IF(ret < 0); 341 DIE_IF(ret >= pf->len); | 402 tvar->value = xstrdup(regs); 403 if (ref) { 404 tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref)); 405 tvar->ref->offset = (long)offs; 406 } |
342} 343 | 407} 408 |
409static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 410 struct perf_probe_arg_field *field, 411 struct kprobe_trace_arg_ref **ref_ptr) 412{ 413 struct kprobe_trace_arg_ref *ref = *ref_ptr; 414 Dwarf_Attribute attr; 415 Dwarf_Die member; 416 Dwarf_Die type; 417 Dwarf_Word offs; 418 419 pr_debug("converting %s in %s\n", field->name, varname); 420 if (die_get_real_type(vr_die, &type) == NULL) 421 die("Failed to get a type information of %s.", varname); 422 423 /* Check the pointer and dereference */ 424 if (dwarf_tag(&type) == DW_TAG_pointer_type) { 425 if (!field->ref) 426 die("Semantic error: %s must be referred by '->'", 427 field->name); 428 /* Get the type pointed by this pointer */ 429 if (die_get_real_type(&type, &type) == NULL) 430 die("Failed to get a type information of %s.", varname); 431 432 /* Verify it is a data structure */ 433 if (dwarf_tag(&type) != DW_TAG_structure_type) 434 die("%s is not a data structure.", varname); 435 436 ref = xzalloc(sizeof(struct kprobe_trace_arg_ref)); 437 if (*ref_ptr) 438 (*ref_ptr)->next = ref; 439 else 440 *ref_ptr = ref; 441 } else { 442 /* Verify it is a data structure */ 443 if (dwarf_tag(&type) != DW_TAG_structure_type) 444 die("%s is not a data structure.", varname); 445 446 if (field->ref) 447 die("Semantic error: %s must be referred by '.'", 448 field->name); 449 if (!ref) 450 die("Structure on a register is not supported yet."); 451 } 452 453 if (die_find_member(&type, field->name, &member) == NULL) 454 die("%s(tyep:%s) has no member %s.", varname, 455 dwarf_diename(&type), field->name); 456 457 /* Get the offset of the field */ 458 if (dwarf_attr(&member, DW_AT_data_member_location, &attr) == NULL || 459 dwarf_formudata(&attr, &offs) != 0) 460 die("Failed to get the offset of %s.", field->name); 461 ref->offset += (long)offs; 462 463 /* Converting next field */ 464 if (field->next) 465 convert_variable_fields(&member, field->name, field->next, 466 &ref); 467} 468 |
|
344/* Show a variables in kprobe event format */ | 469/* Show a variables in kprobe event format */ |
345static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | 470static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) |
346{ 347 Dwarf_Attribute attr; 348 Dwarf_Op *expr; 349 size_t nexpr; 350 int ret; 351 352 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 353 goto error; 354 /* TODO: handle more than 1 exprs */ 355 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1); 356 if (ret <= 0 || nexpr == 0) 357 goto error; 358 | 471{ 472 Dwarf_Attribute attr; 473 Dwarf_Op *expr; 474 size_t nexpr; 475 int ret; 476 477 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 478 goto error; 479 /* TODO: handle more than 1 exprs */ 480 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1); 481 if (ret <= 0 || nexpr == 0) 482 goto error; 483 |
359 show_location(expr, pf); | 484 convert_location(expr, pf); 485 486 if (pf->pvar->field) 487 convert_variable_fields(vr_die, pf->pvar->var, 488 pf->pvar->field, &pf->tvar->ref); |
360 /* *expr will be cached in libdw. Don't free it. */ 361 return ; 362error: 363 /* TODO: Support const_value */ 364 die("Failed to find the location of %s at this address.\n" | 489 /* *expr will be cached in libdw. Don't free it. */ 490 return ; 491error: 492 /* TODO: Support const_value */ 493 die("Failed to find the location of %s at this address.\n" |
365 " Perhaps, it has been optimized out.", pf->var); | 494 " Perhaps, it has been optimized out.", pf->pvar->var); |
366} 367 368/* Find a variable in a subprogram die */ 369static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 370{ | 495} 496 497/* Find a variable in a subprogram die */ 498static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 499{ |
371 int ret; | |
372 Dwarf_Die vr_die; | 500 Dwarf_Die vr_die; |
501 char buf[32]; |
|
373 | 502 |
374 /* TODO: Support struct members and arrays */ 375 if (!is_c_varname(pf->var)) { 376 /* Output raw parameters */ 377 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 378 DIE_IF(ret < 0); 379 DIE_IF(ret >= pf->len); 380 return ; | 503 /* TODO: Support arrays */ 504 if (pf->pvar->name) 505 pf->tvar->name = xstrdup(pf->pvar->name); 506 else { 507 synthesize_perf_probe_arg(pf->pvar, buf, 32); 508 pf->tvar->name = xstrdup(buf); |
381 } 382 | 509 } 510 |
383 pr_debug("Searching '%s' variable in context.\n", pf->var); 384 /* Search child die for local variables and parameters. */ 385 if (!die_find_variable(sp_die, pf->var, &vr_die)) 386 die("Failed to find '%s' in this function.", pf->var); 387 388 show_variable(&vr_die, pf); | 511 if (!is_c_varname(pf->pvar->var)) { 512 /* Copy raw parameters */ 513 pf->tvar->value = xstrdup(pf->pvar->var); 514 } else { 515 pr_debug("Searching '%s' variable in context.\n", 516 pf->pvar->var); 517 /* Search child die for local variables and parameters. */ 518 if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) 519 die("Failed to find '%s' in this function.", 520 pf->pvar->var); 521 convert_variable(&vr_die, pf); 522 } |
389} 390 391/* Show a probe point to output buffer */ | 523} 524 525/* Show a probe point to output buffer */ |
392static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | 526static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) |
393{ | 527{ |
394 struct probe_point *pp = pf->pp; | 528 struct kprobe_trace_event *tev; |
395 Dwarf_Addr eaddr; 396 Dwarf_Die die_mem; 397 const char *name; | 529 Dwarf_Addr eaddr; 530 Dwarf_Die die_mem; 531 const char *name; |
398 char tmp[MAX_PROBE_BUFFER]; 399 int ret, i, len; | 532 int ret, i; |
400 Dwarf_Attribute fb_attr; 401 size_t nops; 402 | 533 Dwarf_Attribute fb_attr; 534 size_t nops; 535 |
536 if (pf->ntevs == MAX_PROBES) 537 die("Too many( > %d) probe point found.\n", MAX_PROBES); 538 tev = &pf->tevs[pf->ntevs++]; 539 |
|
403 /* If no real subprogram, find a real one */ 404 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 540 /* If no real subprogram, find a real one */ 541 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { |
405 sp_die = die_get_real_subprogram(&pf->cu_die, | 542 sp_die = die_find_real_subprogram(&pf->cu_die, |
406 pf->addr, &die_mem); 407 if (!sp_die) 408 die("Probe point is not found in subprograms."); 409 } 410 | 543 pf->addr, &die_mem); 544 if (!sp_die) 545 die("Probe point is not found in subprograms."); 546 } 547 |
411 /* Output name of probe point */ | 548 /* Copy the name of probe point */ |
412 name = dwarf_diename(sp_die); 413 if (name) { 414 dwarf_entrypc(sp_die, &eaddr); | 549 name = dwarf_diename(sp_die); 550 if (name) { 551 dwarf_entrypc(sp_die, &eaddr); |
415 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name, 416 (unsigned long)(pf->addr - eaddr)); 417 /* Copy the function name if possible */ 418 if (!pp->function) { 419 pp->function = strdup(name); 420 pp->offset = (size_t)(pf->addr - eaddr); 421 } 422 } else { | 552 tev->point.symbol = xstrdup(name); 553 tev->point.offset = (unsigned long)(pf->addr - eaddr); 554 } else |
423 /* This function has no name. */ | 555 /* This function has no name. */ |
424 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx", 425 (uintmax_t)pf->addr); 426 if (!pp->function) { 427 /* TODO: Use _stext */ 428 pp->function = strdup(""); 429 pp->offset = (size_t)pf->addr; 430 } 431 } 432 DIE_IF(ret < 0); 433 DIE_IF(ret >= MAX_PROBE_BUFFER); 434 len = ret; 435 pr_debug("Probe point found: %s\n", tmp); | 556 tev->point.offset = (unsigned long)pf->addr; |
436 | 557 |
558 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 559 tev->point.offset); 560 |
|
437 /* Get the frame base attribute/ops */ 438 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 439 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 440 if (ret <= 0 || nops == 0) 441 pf->fb_ops = NULL; 442 443 /* Find each argument */ 444 /* TODO: use dwarf_cfi_addrframe */ | 561 /* Get the frame base attribute/ops */ 562 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 563 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 564 if (ret <= 0 || nops == 0) 565 pf->fb_ops = NULL; 566 567 /* Find each argument */ 568 /* TODO: use dwarf_cfi_addrframe */ |
445 for (i = 0; i < pp->nr_args; i++) { 446 pf->var = pp->args[i]; 447 pf->buf = &tmp[len]; 448 pf->len = MAX_PROBE_BUFFER - len; | 569 tev->nargs = pf->pev->nargs; 570 tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); 571 for (i = 0; i < pf->pev->nargs; i++) { 572 pf->pvar = &pf->pev->args[i]; 573 pf->tvar = &tev->args[i]; |
449 find_variable(sp_die, pf); | 574 find_variable(sp_die, pf); |
450 len += strlen(pf->buf); | |
451 } 452 453 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 454 pf->fb_ops = NULL; | 575 } 576 577 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 578 pf->fb_ops = NULL; |
455 456 if (pp->found == MAX_PROBES) 457 die("Too many( > %d) probe point found.\n", MAX_PROBES); 458 459 pp->probes[pp->found] = strdup(tmp); 460 pp->found++; | |
461} 462 463/* Find probe point from its line number */ 464static void find_probe_point_by_line(struct probe_finder *pf) 465{ 466 Dwarf_Lines *lines; 467 Dwarf_Line *line; 468 size_t nlines, i; --- 15 unchanged lines hidden (view full) --- 484 continue; 485 486 ret = dwarf_lineaddr(line, &addr); 487 DIE_IF(ret != 0); 488 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", 489 (int)i, lineno, (uintmax_t)addr); 490 pf->addr = addr; 491 | 579} 580 581/* Find probe point from its line number */ 582static void find_probe_point_by_line(struct probe_finder *pf) 583{ 584 Dwarf_Lines *lines; 585 Dwarf_Line *line; 586 size_t nlines, i; --- 15 unchanged lines hidden (view full) --- 602 continue; 603 604 ret = dwarf_lineaddr(line, &addr); 605 DIE_IF(ret != 0); 606 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", 607 (int)i, lineno, (uintmax_t)addr); 608 pf->addr = addr; 609 |
492 show_probe_point(NULL, pf); | 610 convert_probe_point(NULL, pf); |
493 /* Continuing, because target line might be inlined. */ 494 } 495} 496 497/* Find lines which match lazy pattern */ 498static int find_lazy_match_lines(struct list_head *head, 499 const char *fname, const char *pat) 500{ 501 char *fbuf, *p1, *p2; 502 int fd, line, nlines = 0; 503 struct stat st; 504 505 fd = open(fname, O_RDONLY); 506 if (fd < 0) 507 die("failed to open %s", fname); 508 DIE_IF(fstat(fd, &st) < 0); | 611 /* Continuing, because target line might be inlined. */ 612 } 613} 614 615/* Find lines which match lazy pattern */ 616static int find_lazy_match_lines(struct list_head *head, 617 const char *fname, const char *pat) 618{ 619 char *fbuf, *p1, *p2; 620 int fd, line, nlines = 0; 621 struct stat st; 622 623 fd = open(fname, O_RDONLY); 624 if (fd < 0) 625 die("failed to open %s", fname); 626 DIE_IF(fstat(fd, &st) < 0); |
509 fbuf = malloc(st.st_size + 2); 510 DIE_IF(fbuf == NULL); | 627 fbuf = xmalloc(st.st_size + 2); |
511 DIE_IF(read(fd, fbuf, st.st_size) < 0); 512 close(fd); 513 fbuf[st.st_size] = '\n'; /* Dummy line */ 514 fbuf[st.st_size + 1] = '\0'; 515 p1 = fbuf; 516 line = 1; 517 while ((p2 = strchr(p1, '\n')) != NULL) { 518 *p2 = '\0'; --- 17 unchanged lines hidden (view full) --- 536 Dwarf_Addr addr; 537 Dwarf_Die die_mem; 538 int lineno; 539 int ret; 540 541 if (list_empty(&pf->lcache)) { 542 /* Matching lazy line pattern */ 543 ret = find_lazy_match_lines(&pf->lcache, pf->fname, | 628 DIE_IF(read(fd, fbuf, st.st_size) < 0); 629 close(fd); 630 fbuf[st.st_size] = '\n'; /* Dummy line */ 631 fbuf[st.st_size + 1] = '\0'; 632 p1 = fbuf; 633 line = 1; 634 while ((p2 = strchr(p1, '\n')) != NULL) { 635 *p2 = '\0'; --- 17 unchanged lines hidden (view full) --- 653 Dwarf_Addr addr; 654 Dwarf_Die die_mem; 655 int lineno; 656 int ret; 657 658 if (list_empty(&pf->lcache)) { 659 /* Matching lazy line pattern */ 660 ret = find_lazy_match_lines(&pf->lcache, pf->fname, |
544 pf->pp->lazy_line); | 661 pf->pev->point.lazy_line); |
545 if (ret <= 0) 546 die("No matched lines found in %s.", pf->fname); 547 } 548 549 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); 550 DIE_IF(ret != 0); 551 for (i = 0; i < nlines; i++) { 552 line = dwarf_onesrcline(lines, i); --- 8 unchanged lines hidden (view full) --- 561 562 ret = dwarf_lineaddr(line, &addr); 563 DIE_IF(ret != 0); 564 if (sp_die) { 565 /* Address filtering 1: does sp_die include addr? */ 566 if (!dwarf_haspc(sp_die, addr)) 567 continue; 568 /* Address filtering 2: No child include addr? */ | 662 if (ret <= 0) 663 die("No matched lines found in %s.", pf->fname); 664 } 665 666 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); 667 DIE_IF(ret != 0); 668 for (i = 0; i < nlines; i++) { 669 line = dwarf_onesrcline(lines, i); --- 8 unchanged lines hidden (view full) --- 678 679 ret = dwarf_lineaddr(line, &addr); 680 DIE_IF(ret != 0); 681 if (sp_die) { 682 /* Address filtering 1: does sp_die include addr? */ 683 if (!dwarf_haspc(sp_die, addr)) 684 continue; 685 /* Address filtering 2: No child include addr? */ |
569 if (die_get_inlinefunc(sp_die, addr, &die_mem)) | 686 if (die_find_inlinefunc(sp_die, addr, &die_mem)) |
570 continue; 571 } 572 573 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n", 574 (int)i, lineno, (unsigned long long)addr); 575 pf->addr = addr; 576 | 687 continue; 688 } 689 690 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n", 691 (int)i, lineno, (unsigned long long)addr); 692 pf->addr = addr; 693 |
577 show_probe_point(sp_die, pf); | 694 convert_probe_point(sp_die, pf); |
578 /* Continuing, because target line might be inlined. */ 579 } 580 /* TODO: deallocate lines, but how? */ 581} 582 583static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 584{ 585 struct probe_finder *pf = (struct probe_finder *)data; | 695 /* Continuing, because target line might be inlined. */ 696 } 697 /* TODO: deallocate lines, but how? */ 698} 699 700static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 701{ 702 struct probe_finder *pf = (struct probe_finder *)data; |
586 struct probe_point *pp = pf->pp; | 703 struct perf_probe_point *pp = &pf->pev->point; |
587 588 if (pp->lazy_line) 589 find_probe_point_lazy(in_die, pf); 590 else { 591 /* Get probe address */ 592 pf->addr = die_get_entrypc(in_die); 593 pf->addr += pp->offset; 594 pr_debug("found inline addr: 0x%jx\n", 595 (uintmax_t)pf->addr); 596 | 704 705 if (pp->lazy_line) 706 find_probe_point_lazy(in_die, pf); 707 else { 708 /* Get probe address */ 709 pf->addr = die_get_entrypc(in_die); 710 pf->addr += pp->offset; 711 pr_debug("found inline addr: 0x%jx\n", 712 (uintmax_t)pf->addr); 713 |
597 show_probe_point(in_die, pf); | 714 convert_probe_point(in_die, pf); |
598 } 599 600 return DWARF_CB_OK; 601} 602 603/* Search function from function name */ 604static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 605{ 606 struct probe_finder *pf = (struct probe_finder *)data; | 715 } 716 717 return DWARF_CB_OK; 718} 719 720/* Search function from function name */ 721static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 722{ 723 struct probe_finder *pf = (struct probe_finder *)data; |
607 struct probe_point *pp = pf->pp; | 724 struct perf_probe_point *pp = &pf->pev->point; |
608 609 /* Check tag and diename */ 610 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 611 die_compare_name(sp_die, pp->function) != 0) 612 return 0; 613 614 pf->fname = dwarf_decl_file(sp_die); 615 if (pp->line) { /* Function relative line */ 616 dwarf_decl_line(sp_die, &pf->lno); 617 pf->lno += pp->line; 618 find_probe_point_by_line(pf); 619 } else if (!dwarf_func_inline(sp_die)) { 620 /* Real function */ 621 if (pp->lazy_line) 622 find_probe_point_lazy(sp_die, pf); 623 else { 624 pf->addr = die_get_entrypc(sp_die); 625 pf->addr += pp->offset; 626 /* TODO: Check the address in this function */ | 725 726 /* Check tag and diename */ 727 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 728 die_compare_name(sp_die, pp->function) != 0) 729 return 0; 730 731 pf->fname = dwarf_decl_file(sp_die); 732 if (pp->line) { /* Function relative line */ 733 dwarf_decl_line(sp_die, &pf->lno); 734 pf->lno += pp->line; 735 find_probe_point_by_line(pf); 736 } else if (!dwarf_func_inline(sp_die)) { 737 /* Real function */ 738 if (pp->lazy_line) 739 find_probe_point_lazy(sp_die, pf); 740 else { 741 pf->addr = die_get_entrypc(sp_die); 742 pf->addr += pp->offset; 743 /* TODO: Check the address in this function */ |
627 show_probe_point(sp_die, pf); | 744 convert_probe_point(sp_die, pf); |
628 } 629 } else 630 /* Inlined function: search instances */ 631 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf); 632 633 return 1; /* Exit; no same symbol in this CU. */ 634} 635 636static void find_probe_point_by_func(struct probe_finder *pf) 637{ 638 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0); 639} 640 | 745 } 746 } else 747 /* Inlined function: search instances */ 748 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf); 749 750 return 1; /* Exit; no same symbol in this CU. */ 751} 752 753static void find_probe_point_by_func(struct probe_finder *pf) 754{ 755 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0); 756} 757 |
641/* Find a probe point */ 642int find_probe_point(int fd, struct probe_point *pp) | 758/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ 759int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, 760 struct kprobe_trace_event **tevs) |
643{ | 761{ |
644 struct probe_finder pf = {.pp = pp}; | 762 struct probe_finder pf = {.pev = pev}; 763 struct perf_probe_point *pp = &pev->point; |
645 Dwarf_Off off, noff; 646 size_t cuhl; 647 Dwarf_Die *diep; 648 Dwarf *dbg; 649 | 764 Dwarf_Off off, noff; 765 size_t cuhl; 766 Dwarf_Die *diep; 767 Dwarf *dbg; 768 |
769 pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES); 770 *tevs = pf.tevs; 771 pf.ntevs = 0; 772 |
|
650 dbg = dwarf_begin(fd, DWARF_C_READ); 651 if (!dbg) 652 return -ENOENT; 653 | 773 dbg = dwarf_begin(fd, DWARF_C_READ); 774 if (!dbg) 775 return -ENOENT; 776 |
654 pp->found = 0; | |
655 off = 0; 656 line_list__init(&pf.lcache); 657 /* Loop on CUs (Compilation Unit) */ 658 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 659 /* Get the DIE(Debugging Information Entry) of this CU */ 660 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); 661 if (!diep) 662 continue; --- 14 unchanged lines hidden (view full) --- 677 find_probe_point_by_line(&pf); 678 } 679 } 680 off = noff; 681 } 682 line_list__free(&pf.lcache); 683 dwarf_end(dbg); 684 | 777 off = 0; 778 line_list__init(&pf.lcache); 779 /* Loop on CUs (Compilation Unit) */ 780 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 781 /* Get the DIE(Debugging Information Entry) of this CU */ 782 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); 783 if (!diep) 784 continue; --- 14 unchanged lines hidden (view full) --- 799 find_probe_point_by_line(&pf); 800 } 801 } 802 off = noff; 803 } 804 line_list__free(&pf.lcache); 805 dwarf_end(dbg); 806 |
685 return pp->found; | 807 return pf.ntevs; |
686} 687 | 808} 809 |
810/* Reverse search */ 811int find_perf_probe_point(int fd, unsigned long addr, 812 struct perf_probe_point *ppt) 813{ 814 Dwarf_Die cudie, spdie, indie; 815 Dwarf *dbg; 816 Dwarf_Line *line; 817 Dwarf_Addr laddr, eaddr; 818 const char *tmp; 819 int lineno, ret = 0; 820 821 dbg = dwarf_begin(fd, DWARF_C_READ); 822 if (!dbg) 823 return -ENOENT; 824 825 /* Find cu die */ 826 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { 827 ret = -EINVAL; 828 goto end; 829 } 830 831 /* Find a corresponding line */ 832 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); 833 if (line) { 834 dwarf_lineaddr(line, &laddr); 835 if ((Dwarf_Addr)addr == laddr) { 836 dwarf_lineno(line, &lineno); 837 ppt->line = lineno; 838 839 tmp = dwarf_linesrc(line, NULL, NULL); 840 DIE_IF(!tmp); 841 ppt->file = xstrdup(tmp); 842 ret = 1; 843 } 844 } 845 846 /* Find a corresponding function */ 847 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { 848 tmp = dwarf_diename(&spdie); 849 if (!tmp) 850 goto end; 851 852 dwarf_entrypc(&spdie, &eaddr); 853 if (!lineno) { 854 /* We don't have a line number, let's use offset */ 855 ppt->function = xstrdup(tmp); 856 ppt->offset = addr - (unsigned long)eaddr; 857 ret = 1; 858 goto end; 859 } 860 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) { 861 /* addr in an inline function */ 862 tmp = dwarf_diename(&indie); 863 if (!tmp) 864 goto end; 865 dwarf_decl_line(&indie, &lineno); 866 } else { 867 if (eaddr == addr) /* No offset: function entry */ 868 lineno = ppt->line; 869 else 870 dwarf_decl_line(&spdie, &lineno); 871 } 872 ppt->function = xstrdup(tmp); 873 ppt->line -= lineno; /* Make a relative line number */ 874 } 875 876end: 877 dwarf_end(dbg); 878 return ret; 879} 880 881 |
|
688/* Find line range from its line number */ 689static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 690{ 691 Dwarf_Lines *lines; 692 Dwarf_Line *line; 693 size_t nlines, i; 694 Dwarf_Addr addr; 695 int lineno; --- 15 unchanged lines hidden (view full) --- 711 if (sp_die) { 712 /* Address filtering 1: does sp_die include addr? */ 713 ret = dwarf_lineaddr(line, &addr); 714 DIE_IF(ret != 0); 715 if (!dwarf_haspc(sp_die, addr)) 716 continue; 717 718 /* Address filtering 2: No child include addr? */ | 882/* Find line range from its line number */ 883static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 884{ 885 Dwarf_Lines *lines; 886 Dwarf_Line *line; 887 size_t nlines, i; 888 Dwarf_Addr addr; 889 int lineno; --- 15 unchanged lines hidden (view full) --- 905 if (sp_die) { 906 /* Address filtering 1: does sp_die include addr? */ 907 ret = dwarf_lineaddr(line, &addr); 908 DIE_IF(ret != 0); 909 if (!dwarf_haspc(sp_die, addr)) 910 continue; 911 912 /* Address filtering 2: No child include addr? */ |
719 if (die_get_inlinefunc(sp_die, addr, &die_mem)) | 913 if (die_find_inlinefunc(sp_die, addr, &die_mem)) |
720 continue; 721 } 722 723 /* TODO: Get fileno from line, but how? */ 724 src = dwarf_linesrc(line, NULL, NULL); 725 if (strtailcmp(src, lf->fname) != 0) 726 continue; 727 728 /* Copy real path */ 729 if (!lf->lr->path) | 914 continue; 915 } 916 917 /* TODO: Get fileno from line, but how? */ 918 src = dwarf_linesrc(line, NULL, NULL); 919 if (strtailcmp(src, lf->fname) != 0) 920 continue; 921 922 /* Copy real path */ 923 if (!lf->lr->path) |
730 lf->lr->path = strdup(src); | 924 lf->lr->path = xstrdup(src); |
731 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno); 732 } 733 /* Update status */ 734 if (!list_empty(&lf->lr->line_list)) 735 lf->found = 1; 736 else { 737 free(lf->lr->path); 738 lf->lr->path = NULL; --- 91 unchanged lines hidden --- | 925 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno); 926 } 927 /* Update status */ 928 if (!list_empty(&lf->lr->line_list)) 929 lf->found = 1; 930 else { 931 free(lf->lr->path); 932 lf->lr->path = NULL; --- 91 unchanged lines hidden --- |