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 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 * 20 */ 21 22 #include <sys/utsname.h> 23 #include <sys/types.h> 24 #include <sys/stat.h> 25 #include <fcntl.h> 26 #include <errno.h> 27 #include <stdio.h> 28 #include <unistd.h> 29 #include <getopt.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <stdarg.h> 33 #include <dwarf-regs.h> 34 35 #include <linux/bitops.h> 36 #include "event.h" 37 #include "debug.h" 38 #include "util.h" 39 #include "symbol.h" 40 #include "probe-finder.h" 41 42 /* Kprobe tracer basic type is up to u64 */ 43 #define MAX_BASIC_TYPE_BITS 64 44 45 /* Line number list operations */ 46 47 /* Add a line to line number list */ 48 static int line_list__add_line(struct list_head *head, int line) 49 { 50 struct line_node *ln; 51 struct list_head *p; 52 53 /* Reverse search, because new line will be the last one */ 54 list_for_each_entry_reverse(ln, head, list) { 55 if (ln->line < line) { 56 p = &ln->list; 57 goto found; 58 } else if (ln->line == line) /* Already exist */ 59 return 1; 60 } 61 /* List is empty, or the smallest entry */ 62 p = head; 63 found: 64 pr_debug("line list: add a line %u\n", line); 65 ln = zalloc(sizeof(struct line_node)); 66 if (ln == NULL) 67 return -ENOMEM; 68 ln->line = line; 69 INIT_LIST_HEAD(&ln->list); 70 list_add(&ln->list, p); 71 return 0; 72 } 73 74 /* Check if the line in line number list */ 75 static int line_list__has_line(struct list_head *head, int line) 76 { 77 struct line_node *ln; 78 79 /* Reverse search, because new line will be the last one */ 80 list_for_each_entry(ln, head, list) 81 if (ln->line == line) 82 return 1; 83 84 return 0; 85 } 86 87 /* Init line number list */ 88 static void line_list__init(struct list_head *head) 89 { 90 INIT_LIST_HEAD(head); 91 } 92 93 /* Free line number list */ 94 static void line_list__free(struct list_head *head) 95 { 96 struct line_node *ln; 97 while (!list_empty(head)) { 98 ln = list_first_entry(head, struct line_node, list); 99 list_del(&ln->list); 100 free(ln); 101 } 102 } 103 104 /* Dwarf FL wrappers */ 105 static char *debuginfo_path; /* Currently dummy */ 106 107 static const Dwfl_Callbacks offline_callbacks = { 108 .find_debuginfo = dwfl_standard_find_debuginfo, 109 .debuginfo_path = &debuginfo_path, 110 111 .section_address = dwfl_offline_section_address, 112 113 /* We use this table for core files too. */ 114 .find_elf = dwfl_build_id_find_elf, 115 }; 116 117 /* Get a Dwarf from offline image */ 118 static int debuginfo__init_offline_dwarf(struct debuginfo *self, 119 const char *path) 120 { 121 Dwfl_Module *mod; 122 int fd; 123 124 fd = open(path, O_RDONLY); 125 if (fd < 0) 126 return fd; 127 128 self->dwfl = dwfl_begin(&offline_callbacks); 129 if (!self->dwfl) 130 goto error; 131 132 mod = dwfl_report_offline(self->dwfl, "", "", fd); 133 if (!mod) 134 goto error; 135 136 self->dbg = dwfl_module_getdwarf(mod, &self->bias); 137 if (!self->dbg) 138 goto error; 139 140 return 0; 141 error: 142 if (self->dwfl) 143 dwfl_end(self->dwfl); 144 else 145 close(fd); 146 memset(self, 0, sizeof(*self)); 147 148 return -ENOENT; 149 } 150 151 #if _ELFUTILS_PREREQ(0, 148) 152 /* This method is buggy if elfutils is older than 0.148 */ 153 static int __linux_kernel_find_elf(Dwfl_Module *mod, 154 void **userdata, 155 const char *module_name, 156 Dwarf_Addr base, 157 char **file_name, Elf **elfp) 158 { 159 int fd; 160 const char *path = kernel_get_module_path(module_name); 161 162 pr_debug2("Use file %s for %s\n", path, module_name); 163 if (path) { 164 fd = open(path, O_RDONLY); 165 if (fd >= 0) { 166 *file_name = strdup(path); 167 return fd; 168 } 169 } 170 /* If failed, try to call standard method */ 171 return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base, 172 file_name, elfp); 173 } 174 175 static const Dwfl_Callbacks kernel_callbacks = { 176 .find_debuginfo = dwfl_standard_find_debuginfo, 177 .debuginfo_path = &debuginfo_path, 178 179 .find_elf = __linux_kernel_find_elf, 180 .section_address = dwfl_linux_kernel_module_section_address, 181 }; 182 183 /* Get a Dwarf from live kernel image */ 184 static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 185 Dwarf_Addr addr) 186 { 187 self->dwfl = dwfl_begin(&kernel_callbacks); 188 if (!self->dwfl) 189 return -EINVAL; 190 191 /* Load the kernel dwarves: Don't care the result here */ 192 dwfl_linux_kernel_report_kernel(self->dwfl); 193 dwfl_linux_kernel_report_modules(self->dwfl); 194 195 self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); 196 /* Here, check whether we could get a real dwarf */ 197 if (!self->dbg) { 198 pr_debug("Failed to find kernel dwarf at %lx\n", 199 (unsigned long)addr); 200 dwfl_end(self->dwfl); 201 memset(self, 0, sizeof(*self)); 202 return -ENOENT; 203 } 204 205 return 0; 206 } 207 #else 208 /* With older elfutils, this just support kernel module... */ 209 static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 210 Dwarf_Addr addr __used) 211 { 212 const char *path = kernel_get_module_path("kernel"); 213 214 if (!path) { 215 pr_err("Failed to find vmlinux path\n"); 216 return -ENOENT; 217 } 218 219 pr_debug2("Use file %s for debuginfo\n", path); 220 return debuginfo__init_offline_dwarf(self, path); 221 } 222 #endif 223 224 struct debuginfo *debuginfo__new(const char *path) 225 { 226 struct debuginfo *self = zalloc(sizeof(struct debuginfo)); 227 if (!self) 228 return NULL; 229 230 if (debuginfo__init_offline_dwarf(self, path) < 0) { 231 free(self); 232 self = NULL; 233 } 234 235 return self; 236 } 237 238 struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) 239 { 240 struct debuginfo *self = zalloc(sizeof(struct debuginfo)); 241 if (!self) 242 return NULL; 243 244 if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) { 245 free(self); 246 self = NULL; 247 } 248 249 return self; 250 } 251 252 void debuginfo__delete(struct debuginfo *self) 253 { 254 if (self) { 255 if (self->dwfl) 256 dwfl_end(self->dwfl); 257 free(self); 258 } 259 } 260 261 /* 262 * Probe finder related functions 263 */ 264 265 static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) 266 { 267 struct probe_trace_arg_ref *ref; 268 ref = zalloc(sizeof(struct probe_trace_arg_ref)); 269 if (ref != NULL) 270 ref->offset = offs; 271 return ref; 272 } 273 274 /* 275 * Convert a location into trace_arg. 276 * If tvar == NULL, this just checks variable can be converted. 277 */ 278 static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 279 Dwarf_Op *fb_ops, 280 struct probe_trace_arg *tvar) 281 { 282 Dwarf_Attribute attr; 283 Dwarf_Op *op; 284 size_t nops; 285 unsigned int regn; 286 Dwarf_Word offs = 0; 287 bool ref = false; 288 const char *regs; 289 int ret; 290 291 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 292 goto static_var; 293 294 /* TODO: handle more than 1 exprs */ 295 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || 296 dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || 297 nops == 0) { 298 /* TODO: Support const_value */ 299 return -ENOENT; 300 } 301 302 if (op->atom == DW_OP_addr) { 303 static_var: 304 if (!tvar) 305 return 0; 306 /* Static variables on memory (not stack), make @varname */ 307 ret = strlen(dwarf_diename(vr_die)); 308 tvar->value = zalloc(ret + 2); 309 if (tvar->value == NULL) 310 return -ENOMEM; 311 snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); 312 tvar->ref = alloc_trace_arg_ref((long)offs); 313 if (tvar->ref == NULL) 314 return -ENOMEM; 315 return 0; 316 } 317 318 /* If this is based on frame buffer, set the offset */ 319 if (op->atom == DW_OP_fbreg) { 320 if (fb_ops == NULL) 321 return -ENOTSUP; 322 ref = true; 323 offs = op->number; 324 op = &fb_ops[0]; 325 } 326 327 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 328 regn = op->atom - DW_OP_breg0; 329 offs += op->number; 330 ref = true; 331 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 332 regn = op->atom - DW_OP_reg0; 333 } else if (op->atom == DW_OP_bregx) { 334 regn = op->number; 335 offs += op->number2; 336 ref = true; 337 } else if (op->atom == DW_OP_regx) { 338 regn = op->number; 339 } else { 340 pr_debug("DW_OP %x is not supported.\n", op->atom); 341 return -ENOTSUP; 342 } 343 344 if (!tvar) 345 return 0; 346 347 regs = get_arch_regstr(regn); 348 if (!regs) { 349 /* This should be a bug in DWARF or this tool */ 350 pr_warning("Mapping for the register number %u " 351 "missing on this architecture.\n", regn); 352 return -ERANGE; 353 } 354 355 tvar->value = strdup(regs); 356 if (tvar->value == NULL) 357 return -ENOMEM; 358 359 if (ref) { 360 tvar->ref = alloc_trace_arg_ref((long)offs); 361 if (tvar->ref == NULL) 362 return -ENOMEM; 363 } 364 return 0; 365 } 366 367 #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) 368 369 static int convert_variable_type(Dwarf_Die *vr_die, 370 struct probe_trace_arg *tvar, 371 const char *cast) 372 { 373 struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 374 Dwarf_Die type; 375 char buf[16]; 376 int bsize, boffs, total; 377 int ret; 378 379 /* TODO: check all types */ 380 if (cast && strcmp(cast, "string") != 0) { 381 /* Non string type is OK */ 382 tvar->type = strdup(cast); 383 return (tvar->type == NULL) ? -ENOMEM : 0; 384 } 385 386 bsize = dwarf_bitsize(vr_die); 387 if (bsize > 0) { 388 /* This is a bitfield */ 389 boffs = dwarf_bitoffset(vr_die); 390 total = dwarf_bytesize(vr_die); 391 if (boffs < 0 || total < 0) 392 return -ENOENT; 393 ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, 394 BYTES_TO_BITS(total)); 395 goto formatted; 396 } 397 398 if (die_get_real_type(vr_die, &type) == NULL) { 399 pr_warning("Failed to get a type information of %s.\n", 400 dwarf_diename(vr_die)); 401 return -ENOENT; 402 } 403 404 pr_debug("%s type is %s.\n", 405 dwarf_diename(vr_die), dwarf_diename(&type)); 406 407 if (cast && strcmp(cast, "string") == 0) { /* String type */ 408 ret = dwarf_tag(&type); 409 if (ret != DW_TAG_pointer_type && 410 ret != DW_TAG_array_type) { 411 pr_warning("Failed to cast into string: " 412 "%s(%s) is not a pointer nor array.\n", 413 dwarf_diename(vr_die), dwarf_diename(&type)); 414 return -EINVAL; 415 } 416 if (ret == DW_TAG_pointer_type) { 417 if (die_get_real_type(&type, &type) == NULL) { 418 pr_warning("Failed to get a type" 419 " information.\n"); 420 return -ENOENT; 421 } 422 while (*ref_ptr) 423 ref_ptr = &(*ref_ptr)->next; 424 /* Add new reference with offset +0 */ 425 *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); 426 if (*ref_ptr == NULL) { 427 pr_warning("Out of memory error\n"); 428 return -ENOMEM; 429 } 430 } 431 if (!die_compare_name(&type, "char") && 432 !die_compare_name(&type, "unsigned char")) { 433 pr_warning("Failed to cast into string: " 434 "%s is not (unsigned) char *.\n", 435 dwarf_diename(vr_die)); 436 return -EINVAL; 437 } 438 tvar->type = strdup(cast); 439 return (tvar->type == NULL) ? -ENOMEM : 0; 440 } 441 442 ret = dwarf_bytesize(&type); 443 if (ret <= 0) 444 /* No size ... try to use default type */ 445 return 0; 446 ret = BYTES_TO_BITS(ret); 447 448 /* Check the bitwidth */ 449 if (ret > MAX_BASIC_TYPE_BITS) { 450 pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", 451 dwarf_diename(&type), MAX_BASIC_TYPE_BITS); 452 ret = MAX_BASIC_TYPE_BITS; 453 } 454 ret = snprintf(buf, 16, "%c%d", 455 die_is_signed_type(&type) ? 's' : 'u', ret); 456 457 formatted: 458 if (ret < 0 || ret >= 16) { 459 if (ret >= 16) 460 ret = -E2BIG; 461 pr_warning("Failed to convert variable type: %s\n", 462 strerror(-ret)); 463 return ret; 464 } 465 tvar->type = strdup(buf); 466 if (tvar->type == NULL) 467 return -ENOMEM; 468 return 0; 469 } 470 471 static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 472 struct perf_probe_arg_field *field, 473 struct probe_trace_arg_ref **ref_ptr, 474 Dwarf_Die *die_mem) 475 { 476 struct probe_trace_arg_ref *ref = *ref_ptr; 477 Dwarf_Die type; 478 Dwarf_Word offs; 479 int ret, tag; 480 481 pr_debug("converting %s in %s\n", field->name, varname); 482 if (die_get_real_type(vr_die, &type) == NULL) { 483 pr_warning("Failed to get the type of %s.\n", varname); 484 return -ENOENT; 485 } 486 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); 487 tag = dwarf_tag(&type); 488 489 if (field->name[0] == '[' && 490 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { 491 if (field->next) 492 /* Save original type for next field */ 493 memcpy(die_mem, &type, sizeof(*die_mem)); 494 /* Get the type of this array */ 495 if (die_get_real_type(&type, &type) == NULL) { 496 pr_warning("Failed to get the type of %s.\n", varname); 497 return -ENOENT; 498 } 499 pr_debug2("Array real type: (%x)\n", 500 (unsigned)dwarf_dieoffset(&type)); 501 if (tag == DW_TAG_pointer_type) { 502 ref = zalloc(sizeof(struct probe_trace_arg_ref)); 503 if (ref == NULL) 504 return -ENOMEM; 505 if (*ref_ptr) 506 (*ref_ptr)->next = ref; 507 else 508 *ref_ptr = ref; 509 } 510 ref->offset += dwarf_bytesize(&type) * field->index; 511 if (!field->next) 512 /* Save vr_die for converting types */ 513 memcpy(die_mem, vr_die, sizeof(*die_mem)); 514 goto next; 515 } else if (tag == DW_TAG_pointer_type) { 516 /* Check the pointer and dereference */ 517 if (!field->ref) { 518 pr_err("Semantic error: %s must be referred by '->'\n", 519 field->name); 520 return -EINVAL; 521 } 522 /* Get the type pointed by this pointer */ 523 if (die_get_real_type(&type, &type) == NULL) { 524 pr_warning("Failed to get the type of %s.\n", varname); 525 return -ENOENT; 526 } 527 /* Verify it is a data structure */ 528 if (dwarf_tag(&type) != DW_TAG_structure_type) { 529 pr_warning("%s is not a data structure.\n", varname); 530 return -EINVAL; 531 } 532 533 ref = zalloc(sizeof(struct probe_trace_arg_ref)); 534 if (ref == NULL) 535 return -ENOMEM; 536 if (*ref_ptr) 537 (*ref_ptr)->next = ref; 538 else 539 *ref_ptr = ref; 540 } else { 541 /* Verify it is a data structure */ 542 if (tag != DW_TAG_structure_type) { 543 pr_warning("%s is not a data structure.\n", varname); 544 return -EINVAL; 545 } 546 if (field->name[0] == '[') { 547 pr_err("Semantic error: %s is not a pointor" 548 " nor array.\n", varname); 549 return -EINVAL; 550 } 551 if (field->ref) { 552 pr_err("Semantic error: %s must be referred by '.'\n", 553 field->name); 554 return -EINVAL; 555 } 556 if (!ref) { 557 pr_warning("Structure on a register is not " 558 "supported yet.\n"); 559 return -ENOTSUP; 560 } 561 } 562 563 if (die_find_member(&type, field->name, die_mem) == NULL) { 564 pr_warning("%s(tyep:%s) has no member %s.\n", varname, 565 dwarf_diename(&type), field->name); 566 return -EINVAL; 567 } 568 569 /* Get the offset of the field */ 570 ret = die_get_data_member_location(die_mem, &offs); 571 if (ret < 0) { 572 pr_warning("Failed to get the offset of %s.\n", field->name); 573 return ret; 574 } 575 ref->offset += (long)offs; 576 577 next: 578 /* Converting next field */ 579 if (field->next) 580 return convert_variable_fields(die_mem, field->name, 581 field->next, &ref, die_mem); 582 else 583 return 0; 584 } 585 586 /* Show a variables in kprobe event format */ 587 static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 588 { 589 Dwarf_Die die_mem; 590 int ret; 591 592 pr_debug("Converting variable %s into trace event.\n", 593 dwarf_diename(vr_die)); 594 595 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 596 pf->tvar); 597 if (ret == -ENOENT) 598 pr_err("Failed to find the location of %s at this address.\n" 599 " Perhaps, it has been optimized out.\n", pf->pvar->var); 600 else if (ret == -ENOTSUP) 601 pr_err("Sorry, we don't support this variable location yet.\n"); 602 else if (pf->pvar->field) { 603 ret = convert_variable_fields(vr_die, pf->pvar->var, 604 pf->pvar->field, &pf->tvar->ref, 605 &die_mem); 606 vr_die = &die_mem; 607 } 608 if (ret == 0) 609 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); 610 /* *expr will be cached in libdw. Don't free it. */ 611 return ret; 612 } 613 614 /* Find a variable in a scope DIE */ 615 static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) 616 { 617 Dwarf_Die vr_die; 618 char buf[32], *ptr; 619 int ret = 0; 620 621 if (!is_c_varname(pf->pvar->var)) { 622 /* Copy raw parameters */ 623 pf->tvar->value = strdup(pf->pvar->var); 624 if (pf->tvar->value == NULL) 625 return -ENOMEM; 626 if (pf->pvar->type) { 627 pf->tvar->type = strdup(pf->pvar->type); 628 if (pf->tvar->type == NULL) 629 return -ENOMEM; 630 } 631 if (pf->pvar->name) { 632 pf->tvar->name = strdup(pf->pvar->name); 633 if (pf->tvar->name == NULL) 634 return -ENOMEM; 635 } else 636 pf->tvar->name = NULL; 637 return 0; 638 } 639 640 if (pf->pvar->name) 641 pf->tvar->name = strdup(pf->pvar->name); 642 else { 643 ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); 644 if (ret < 0) 645 return ret; 646 ptr = strchr(buf, ':'); /* Change type separator to _ */ 647 if (ptr) 648 *ptr = '_'; 649 pf->tvar->name = strdup(buf); 650 } 651 if (pf->tvar->name == NULL) 652 return -ENOMEM; 653 654 pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); 655 /* Search child die for local variables and parameters. */ 656 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 657 /* Search again in global variables */ 658 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 659 ret = -ENOENT; 660 } 661 if (ret >= 0) 662 ret = convert_variable(&vr_die, pf); 663 664 if (ret < 0) 665 pr_warning("Failed to find '%s' in this function.\n", 666 pf->pvar->var); 667 return ret; 668 } 669 670 /* Convert subprogram DIE to trace point */ 671 static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, 672 bool retprobe, struct probe_trace_point *tp) 673 { 674 Dwarf_Addr eaddr, highaddr; 675 const char *name; 676 677 /* Copy the name of probe point */ 678 name = dwarf_diename(sp_die); 679 if (name) { 680 if (dwarf_entrypc(sp_die, &eaddr) != 0) { 681 pr_warning("Failed to get entry address of %s\n", 682 dwarf_diename(sp_die)); 683 return -ENOENT; 684 } 685 if (dwarf_highpc(sp_die, &highaddr) != 0) { 686 pr_warning("Failed to get end address of %s\n", 687 dwarf_diename(sp_die)); 688 return -ENOENT; 689 } 690 if (paddr > highaddr) { 691 pr_warning("Offset specified is greater than size of %s\n", 692 dwarf_diename(sp_die)); 693 return -EINVAL; 694 } 695 tp->symbol = strdup(name); 696 if (tp->symbol == NULL) 697 return -ENOMEM; 698 tp->offset = (unsigned long)(paddr - eaddr); 699 } else 700 /* This function has no name. */ 701 tp->offset = (unsigned long)paddr; 702 703 /* Return probe must be on the head of a subprogram */ 704 if (retprobe) { 705 if (eaddr != paddr) { 706 pr_warning("Return probe must be on the head of" 707 " a real function.\n"); 708 return -EINVAL; 709 } 710 tp->retprobe = true; 711 } 712 713 return 0; 714 } 715 716 /* Call probe_finder callback with scope DIE */ 717 static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 718 { 719 Dwarf_Attribute fb_attr; 720 size_t nops; 721 int ret; 722 723 if (!sc_die) { 724 pr_err("Caller must pass a scope DIE. Program error.\n"); 725 return -EINVAL; 726 } 727 728 /* If not a real subprogram, find a real one */ 729 if (dwarf_tag(sc_die) != DW_TAG_subprogram) { 730 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 731 pr_warning("Failed to find probe point in any " 732 "functions.\n"); 733 return -ENOENT; 734 } 735 } else 736 memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); 737 738 /* Get the frame base attribute/ops from subprogram */ 739 dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); 740 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 741 if (ret <= 0 || nops == 0) { 742 pf->fb_ops = NULL; 743 #if _ELFUTILS_PREREQ(0, 142) 744 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 745 pf->cfi != NULL) { 746 Dwarf_Frame *frame; 747 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 748 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 749 pr_warning("Failed to get call frame on 0x%jx\n", 750 (uintmax_t)pf->addr); 751 return -ENOENT; 752 } 753 #endif 754 } 755 756 /* Call finder's callback handler */ 757 ret = pf->callback(sc_die, pf); 758 759 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 760 pf->fb_ops = NULL; 761 762 return ret; 763 } 764 765 struct find_scope_param { 766 const char *function; 767 const char *file; 768 int line; 769 int diff; 770 Dwarf_Die *die_mem; 771 bool found; 772 }; 773 774 static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) 775 { 776 struct find_scope_param *fsp = data; 777 const char *file; 778 int lno; 779 780 /* Skip if declared file name does not match */ 781 if (fsp->file) { 782 file = dwarf_decl_file(fn_die); 783 if (!file || strcmp(fsp->file, file) != 0) 784 return 0; 785 } 786 /* If the function name is given, that's what user expects */ 787 if (fsp->function) { 788 if (die_compare_name(fn_die, fsp->function)) { 789 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 790 fsp->found = true; 791 return 1; 792 } 793 } else { 794 /* With the line number, find the nearest declared DIE */ 795 dwarf_decl_line(fn_die, &lno); 796 if (lno < fsp->line && fsp->diff > fsp->line - lno) { 797 /* Keep a candidate and continue */ 798 fsp->diff = fsp->line - lno; 799 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 800 fsp->found = true; 801 } 802 } 803 return 0; 804 } 805 806 /* Find an appropriate scope fits to given conditions */ 807 static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) 808 { 809 struct find_scope_param fsp = { 810 .function = pf->pev->point.function, 811 .file = pf->fname, 812 .line = pf->lno, 813 .diff = INT_MAX, 814 .die_mem = die_mem, 815 .found = false, 816 }; 817 818 cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); 819 820 return fsp.found ? die_mem : NULL; 821 } 822 823 static int probe_point_line_walker(const char *fname, int lineno, 824 Dwarf_Addr addr, void *data) 825 { 826 struct probe_finder *pf = data; 827 Dwarf_Die *sc_die, die_mem; 828 int ret; 829 830 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 831 return 0; 832 833 pf->addr = addr; 834 sc_die = find_best_scope(pf, &die_mem); 835 if (!sc_die) { 836 pr_warning("Failed to find scope of probe point.\n"); 837 return -ENOENT; 838 } 839 840 ret = call_probe_finder(sc_die, pf); 841 842 /* Continue if no error, because the line will be in inline function */ 843 return ret < 0 ? ret : 0; 844 } 845 846 /* Find probe point from its line number */ 847 static int find_probe_point_by_line(struct probe_finder *pf) 848 { 849 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 850 } 851 852 /* Find lines which match lazy pattern */ 853 static int find_lazy_match_lines(struct list_head *head, 854 const char *fname, const char *pat) 855 { 856 FILE *fp; 857 char *line = NULL; 858 size_t line_len; 859 ssize_t len; 860 int count = 0, linenum = 1; 861 862 fp = fopen(fname, "r"); 863 if (!fp) { 864 pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); 865 return -errno; 866 } 867 868 while ((len = getline(&line, &line_len, fp)) > 0) { 869 870 if (line[len - 1] == '\n') 871 line[len - 1] = '\0'; 872 873 if (strlazymatch(line, pat)) { 874 line_list__add_line(head, linenum); 875 count++; 876 } 877 linenum++; 878 } 879 880 if (ferror(fp)) 881 count = -errno; 882 free(line); 883 fclose(fp); 884 885 if (count == 0) 886 pr_debug("No matched lines found in %s.\n", fname); 887 return count; 888 } 889 890 static int probe_point_lazy_walker(const char *fname, int lineno, 891 Dwarf_Addr addr, void *data) 892 { 893 struct probe_finder *pf = data; 894 Dwarf_Die *sc_die, die_mem; 895 int ret; 896 897 if (!line_list__has_line(&pf->lcache, lineno) || 898 strtailcmp(fname, pf->fname) != 0) 899 return 0; 900 901 pr_debug("Probe line found: line:%d addr:0x%llx\n", 902 lineno, (unsigned long long)addr); 903 pf->addr = addr; 904 pf->lno = lineno; 905 sc_die = find_best_scope(pf, &die_mem); 906 if (!sc_die) { 907 pr_warning("Failed to find scope of probe point.\n"); 908 return -ENOENT; 909 } 910 911 ret = call_probe_finder(sc_die, pf); 912 913 /* 914 * Continue if no error, because the lazy pattern will match 915 * to other lines 916 */ 917 return ret < 0 ? ret : 0; 918 } 919 920 /* Find probe points from lazy pattern */ 921 static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 922 { 923 int ret = 0; 924 925 if (list_empty(&pf->lcache)) { 926 /* Matching lazy line pattern */ 927 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 928 pf->pev->point.lazy_line); 929 if (ret <= 0) 930 return ret; 931 } 932 933 return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 934 } 935 936 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 937 { 938 struct probe_finder *pf = data; 939 struct perf_probe_point *pp = &pf->pev->point; 940 Dwarf_Addr addr; 941 int ret; 942 943 if (pp->lazy_line) 944 ret = find_probe_point_lazy(in_die, pf); 945 else { 946 /* Get probe address */ 947 if (dwarf_entrypc(in_die, &addr) != 0) { 948 pr_warning("Failed to get entry address of %s.\n", 949 dwarf_diename(in_die)); 950 return -ENOENT; 951 } 952 pf->addr = addr; 953 pf->addr += pp->offset; 954 pr_debug("found inline addr: 0x%jx\n", 955 (uintmax_t)pf->addr); 956 957 ret = call_probe_finder(in_die, pf); 958 } 959 960 return ret; 961 } 962 963 /* Callback parameter with return value for libdw */ 964 struct dwarf_callback_param { 965 void *data; 966 int retval; 967 }; 968 969 /* Search function from function name */ 970 static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 971 { 972 struct dwarf_callback_param *param = data; 973 struct probe_finder *pf = param->data; 974 struct perf_probe_point *pp = &pf->pev->point; 975 976 /* Check tag and diename */ 977 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 978 !die_compare_name(sp_die, pp->function)) 979 return DWARF_CB_OK; 980 981 /* Check declared file */ 982 if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) 983 return DWARF_CB_OK; 984 985 pf->fname = dwarf_decl_file(sp_die); 986 if (pp->line) { /* Function relative line */ 987 dwarf_decl_line(sp_die, &pf->lno); 988 pf->lno += pp->line; 989 param->retval = find_probe_point_by_line(pf); 990 } else if (!dwarf_func_inline(sp_die)) { 991 /* Real function */ 992 if (pp->lazy_line) 993 param->retval = find_probe_point_lazy(sp_die, pf); 994 else { 995 if (dwarf_entrypc(sp_die, &pf->addr) != 0) { 996 pr_warning("Failed to get entry address of " 997 "%s.\n", dwarf_diename(sp_die)); 998 param->retval = -ENOENT; 999 return DWARF_CB_ABORT; 1000 } 1001 pf->addr += pp->offset; 1002 /* TODO: Check the address in this function */ 1003 param->retval = call_probe_finder(sp_die, pf); 1004 } 1005 } else 1006 /* Inlined function: search instances */ 1007 param->retval = die_walk_instances(sp_die, 1008 probe_point_inline_cb, (void *)pf); 1009 1010 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 1011 } 1012 1013 static int find_probe_point_by_func(struct probe_finder *pf) 1014 { 1015 struct dwarf_callback_param _param = {.data = (void *)pf, 1016 .retval = 0}; 1017 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 1018 return _param.retval; 1019 } 1020 1021 struct pubname_callback_param { 1022 char *function; 1023 char *file; 1024 Dwarf_Die *cu_die; 1025 Dwarf_Die *sp_die; 1026 int found; 1027 }; 1028 1029 static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) 1030 { 1031 struct pubname_callback_param *param = data; 1032 1033 if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { 1034 if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) 1035 return DWARF_CB_OK; 1036 1037 if (die_compare_name(param->sp_die, param->function)) { 1038 if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) 1039 return DWARF_CB_OK; 1040 1041 if (param->file && 1042 strtailcmp(param->file, dwarf_decl_file(param->sp_die))) 1043 return DWARF_CB_OK; 1044 1045 param->found = 1; 1046 return DWARF_CB_ABORT; 1047 } 1048 } 1049 1050 return DWARF_CB_OK; 1051 } 1052 1053 /* Find probe points from debuginfo */ 1054 static int debuginfo__find_probes(struct debuginfo *self, 1055 struct probe_finder *pf) 1056 { 1057 struct perf_probe_point *pp = &pf->pev->point; 1058 Dwarf_Off off, noff; 1059 size_t cuhl; 1060 Dwarf_Die *diep; 1061 int ret = 0; 1062 1063 #if _ELFUTILS_PREREQ(0, 142) 1064 /* Get the call frame information from this dwarf */ 1065 pf->cfi = dwarf_getcfi(self->dbg); 1066 #endif 1067 1068 off = 0; 1069 line_list__init(&pf->lcache); 1070 1071 /* Fastpath: lookup by function name from .debug_pubnames section */ 1072 if (pp->function) { 1073 struct pubname_callback_param pubname_param = { 1074 .function = pp->function, 1075 .file = pp->file, 1076 .cu_die = &pf->cu_die, 1077 .sp_die = &pf->sp_die, 1078 .found = 0, 1079 }; 1080 struct dwarf_callback_param probe_param = { 1081 .data = pf, 1082 }; 1083 1084 dwarf_getpubnames(self->dbg, pubname_search_cb, 1085 &pubname_param, 0); 1086 if (pubname_param.found) { 1087 ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1088 if (ret) 1089 goto found; 1090 } 1091 } 1092 1093 /* Loop on CUs (Compilation Unit) */ 1094 while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 1095 /* Get the DIE(Debugging Information Entry) of this CU */ 1096 diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); 1097 if (!diep) 1098 continue; 1099 1100 /* Check if target file is included. */ 1101 if (pp->file) 1102 pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1103 else 1104 pf->fname = NULL; 1105 1106 if (!pp->file || pf->fname) { 1107 if (pp->function) 1108 ret = find_probe_point_by_func(pf); 1109 else if (pp->lazy_line) 1110 ret = find_probe_point_lazy(NULL, pf); 1111 else { 1112 pf->lno = pp->line; 1113 ret = find_probe_point_by_line(pf); 1114 } 1115 if (ret < 0) 1116 break; 1117 } 1118 off = noff; 1119 } 1120 1121 found: 1122 line_list__free(&pf->lcache); 1123 1124 return ret; 1125 } 1126 1127 /* Add a found probe point into trace event list */ 1128 static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1129 { 1130 struct trace_event_finder *tf = 1131 container_of(pf, struct trace_event_finder, pf); 1132 struct probe_trace_event *tev; 1133 int ret, i; 1134 1135 /* Check number of tevs */ 1136 if (tf->ntevs == tf->max_tevs) { 1137 pr_warning("Too many( > %d) probe point found.\n", 1138 tf->max_tevs); 1139 return -ERANGE; 1140 } 1141 tev = &tf->tevs[tf->ntevs++]; 1142 1143 /* Trace point should be converted from subprogram DIE */ 1144 ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1145 pf->pev->point.retprobe, &tev->point); 1146 if (ret < 0) 1147 return ret; 1148 1149 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1150 tev->point.offset); 1151 1152 /* Find each argument */ 1153 tev->nargs = pf->pev->nargs; 1154 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1155 if (tev->args == NULL) 1156 return -ENOMEM; 1157 for (i = 0; i < pf->pev->nargs; i++) { 1158 pf->pvar = &pf->pev->args[i]; 1159 pf->tvar = &tev->args[i]; 1160 /* Variable should be found from scope DIE */ 1161 ret = find_variable(sc_die, pf); 1162 if (ret != 0) 1163 return ret; 1164 } 1165 1166 return 0; 1167 } 1168 1169 /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1170 int debuginfo__find_trace_events(struct debuginfo *self, 1171 struct perf_probe_event *pev, 1172 struct probe_trace_event **tevs, int max_tevs) 1173 { 1174 struct trace_event_finder tf = { 1175 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1176 .max_tevs = max_tevs}; 1177 int ret; 1178 1179 /* Allocate result tevs array */ 1180 *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); 1181 if (*tevs == NULL) 1182 return -ENOMEM; 1183 1184 tf.tevs = *tevs; 1185 tf.ntevs = 0; 1186 1187 ret = debuginfo__find_probes(self, &tf.pf); 1188 if (ret < 0) { 1189 free(*tevs); 1190 *tevs = NULL; 1191 return ret; 1192 } 1193 1194 return (ret < 0) ? ret : tf.ntevs; 1195 } 1196 1197 #define MAX_VAR_LEN 64 1198 1199 /* Collect available variables in this scope */ 1200 static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1201 { 1202 struct available_var_finder *af = data; 1203 struct variable_list *vl; 1204 char buf[MAX_VAR_LEN]; 1205 int tag, ret; 1206 1207 vl = &af->vls[af->nvls - 1]; 1208 1209 tag = dwarf_tag(die_mem); 1210 if (tag == DW_TAG_formal_parameter || 1211 tag == DW_TAG_variable) { 1212 ret = convert_variable_location(die_mem, af->pf.addr, 1213 af->pf.fb_ops, NULL); 1214 if (ret == 0) { 1215 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); 1216 pr_debug2("Add new var: %s\n", buf); 1217 if (ret > 0) 1218 strlist__add(vl->vars, buf); 1219 } 1220 } 1221 1222 if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1223 return DIE_FIND_CB_CONTINUE; 1224 else 1225 return DIE_FIND_CB_SIBLING; 1226 } 1227 1228 /* Add a found vars into available variables list */ 1229 static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) 1230 { 1231 struct available_var_finder *af = 1232 container_of(pf, struct available_var_finder, pf); 1233 struct variable_list *vl; 1234 Dwarf_Die die_mem; 1235 int ret; 1236 1237 /* Check number of tevs */ 1238 if (af->nvls == af->max_vls) { 1239 pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1240 return -ERANGE; 1241 } 1242 vl = &af->vls[af->nvls++]; 1243 1244 /* Trace point should be converted from subprogram DIE */ 1245 ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1246 pf->pev->point.retprobe, &vl->point); 1247 if (ret < 0) 1248 return ret; 1249 1250 pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1251 vl->point.offset); 1252 1253 /* Find local variables */ 1254 vl->vars = strlist__new(true, NULL); 1255 if (vl->vars == NULL) 1256 return -ENOMEM; 1257 af->child = true; 1258 die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); 1259 1260 /* Find external variables */ 1261 if (!af->externs) 1262 goto out; 1263 /* Don't need to search child DIE for externs. */ 1264 af->child = false; 1265 die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); 1266 1267 out: 1268 if (strlist__empty(vl->vars)) { 1269 strlist__delete(vl->vars); 1270 vl->vars = NULL; 1271 } 1272 1273 return ret; 1274 } 1275 1276 /* Find available variables at given probe point */ 1277 int debuginfo__find_available_vars_at(struct debuginfo *self, 1278 struct perf_probe_event *pev, 1279 struct variable_list **vls, 1280 int max_vls, bool externs) 1281 { 1282 struct available_var_finder af = { 1283 .pf = {.pev = pev, .callback = add_available_vars}, 1284 .max_vls = max_vls, .externs = externs}; 1285 int ret; 1286 1287 /* Allocate result vls array */ 1288 *vls = zalloc(sizeof(struct variable_list) * max_vls); 1289 if (*vls == NULL) 1290 return -ENOMEM; 1291 1292 af.vls = *vls; 1293 af.nvls = 0; 1294 1295 ret = debuginfo__find_probes(self, &af.pf); 1296 if (ret < 0) { 1297 /* Free vlist for error */ 1298 while (af.nvls--) { 1299 if (af.vls[af.nvls].point.symbol) 1300 free(af.vls[af.nvls].point.symbol); 1301 if (af.vls[af.nvls].vars) 1302 strlist__delete(af.vls[af.nvls].vars); 1303 } 1304 free(af.vls); 1305 *vls = NULL; 1306 return ret; 1307 } 1308 1309 return (ret < 0) ? ret : af.nvls; 1310 } 1311 1312 /* Reverse search */ 1313 int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, 1314 struct perf_probe_point *ppt) 1315 { 1316 Dwarf_Die cudie, spdie, indie; 1317 Dwarf_Addr _addr, baseaddr; 1318 const char *fname = NULL, *func = NULL, *tmp; 1319 int baseline = 0, lineno = 0, ret = 0; 1320 1321 /* Adjust address with bias */ 1322 addr += self->bias; 1323 1324 /* Find cu die */ 1325 if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { 1326 pr_warning("Failed to find debug information for address %lx\n", 1327 addr); 1328 ret = -EINVAL; 1329 goto end; 1330 } 1331 1332 /* Find a corresponding line (filename and lineno) */ 1333 cu_find_lineinfo(&cudie, addr, &fname, &lineno); 1334 /* Don't care whether it failed or not */ 1335 1336 /* Find a corresponding function (name, baseline and baseaddr) */ 1337 if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 1338 /* Get function entry information */ 1339 tmp = dwarf_diename(&spdie); 1340 if (!tmp || 1341 dwarf_entrypc(&spdie, &baseaddr) != 0 || 1342 dwarf_decl_line(&spdie, &baseline) != 0) 1343 goto post; 1344 func = tmp; 1345 1346 if (addr == (unsigned long)baseaddr) 1347 /* Function entry - Relative line number is 0 */ 1348 lineno = baseline; 1349 else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, 1350 &indie)) { 1351 if (dwarf_entrypc(&indie, &_addr) == 0 && 1352 _addr == addr) 1353 /* 1354 * addr is at an inline function entry. 1355 * In this case, lineno should be the call-site 1356 * line number. 1357 */ 1358 lineno = die_get_call_lineno(&indie); 1359 else { 1360 /* 1361 * addr is in an inline function body. 1362 * Since lineno points one of the lines 1363 * of the inline function, baseline should 1364 * be the entry line of the inline function. 1365 */ 1366 tmp = dwarf_diename(&indie); 1367 if (tmp && 1368 dwarf_decl_line(&spdie, &baseline) == 0) 1369 func = tmp; 1370 } 1371 } 1372 } 1373 1374 post: 1375 /* Make a relative line number or an offset */ 1376 if (lineno) 1377 ppt->line = lineno - baseline; 1378 else if (func) 1379 ppt->offset = addr - (unsigned long)baseaddr; 1380 1381 /* Duplicate strings */ 1382 if (func) { 1383 ppt->function = strdup(func); 1384 if (ppt->function == NULL) { 1385 ret = -ENOMEM; 1386 goto end; 1387 } 1388 } 1389 if (fname) { 1390 ppt->file = strdup(fname); 1391 if (ppt->file == NULL) { 1392 if (ppt->function) { 1393 free(ppt->function); 1394 ppt->function = NULL; 1395 } 1396 ret = -ENOMEM; 1397 goto end; 1398 } 1399 } 1400 end: 1401 if (ret == 0 && (fname || func)) 1402 ret = 1; /* Found a point */ 1403 return ret; 1404 } 1405 1406 /* Add a line and store the src path */ 1407 static int line_range_add_line(const char *src, unsigned int lineno, 1408 struct line_range *lr) 1409 { 1410 /* Copy source path */ 1411 if (!lr->path) { 1412 lr->path = strdup(src); 1413 if (lr->path == NULL) 1414 return -ENOMEM; 1415 } 1416 return line_list__add_line(&lr->line_list, lineno); 1417 } 1418 1419 static int line_range_walk_cb(const char *fname, int lineno, 1420 Dwarf_Addr addr __used, 1421 void *data) 1422 { 1423 struct line_finder *lf = data; 1424 1425 if ((strtailcmp(fname, lf->fname) != 0) || 1426 (lf->lno_s > lineno || lf->lno_e < lineno)) 1427 return 0; 1428 1429 if (line_range_add_line(fname, lineno, lf->lr) < 0) 1430 return -EINVAL; 1431 1432 return 0; 1433 } 1434 1435 /* Find line range from its line number */ 1436 static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1437 { 1438 int ret; 1439 1440 ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 1441 1442 /* Update status */ 1443 if (ret >= 0) 1444 if (!list_empty(&lf->lr->line_list)) 1445 ret = lf->found = 1; 1446 else 1447 ret = 0; /* Lines are not found */ 1448 else { 1449 free(lf->lr->path); 1450 lf->lr->path = NULL; 1451 } 1452 return ret; 1453 } 1454 1455 static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1456 { 1457 find_line_range_by_line(in_die, data); 1458 1459 /* 1460 * We have to check all instances of inlined function, because 1461 * some execution paths can be optimized out depends on the 1462 * function argument of instances 1463 */ 1464 return 0; 1465 } 1466 1467 /* Search function from function name */ 1468 static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1469 { 1470 struct dwarf_callback_param *param = data; 1471 struct line_finder *lf = param->data; 1472 struct line_range *lr = lf->lr; 1473 1474 /* Check declared file */ 1475 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 1476 return DWARF_CB_OK; 1477 1478 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1479 die_compare_name(sp_die, lr->function)) { 1480 lf->fname = dwarf_decl_file(sp_die); 1481 dwarf_decl_line(sp_die, &lr->offset); 1482 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1483 lf->lno_s = lr->offset + lr->start; 1484 if (lf->lno_s < 0) /* Overflow */ 1485 lf->lno_s = INT_MAX; 1486 lf->lno_e = lr->offset + lr->end; 1487 if (lf->lno_e < 0) /* Overflow */ 1488 lf->lno_e = INT_MAX; 1489 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1490 lr->start = lf->lno_s; 1491 lr->end = lf->lno_e; 1492 if (dwarf_func_inline(sp_die)) 1493 param->retval = die_walk_instances(sp_die, 1494 line_range_inline_cb, lf); 1495 else 1496 param->retval = find_line_range_by_line(sp_die, lf); 1497 return DWARF_CB_ABORT; 1498 } 1499 return DWARF_CB_OK; 1500 } 1501 1502 static int find_line_range_by_func(struct line_finder *lf) 1503 { 1504 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 1505 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 1506 return param.retval; 1507 } 1508 1509 int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) 1510 { 1511 struct line_finder lf = {.lr = lr, .found = 0}; 1512 int ret = 0; 1513 Dwarf_Off off = 0, noff; 1514 size_t cuhl; 1515 Dwarf_Die *diep; 1516 const char *comp_dir; 1517 1518 /* Fastpath: lookup by function name from .debug_pubnames section */ 1519 if (lr->function) { 1520 struct pubname_callback_param pubname_param = { 1521 .function = lr->function, .file = lr->file, 1522 .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; 1523 struct dwarf_callback_param line_range_param = { 1524 .data = (void *)&lf, .retval = 0}; 1525 1526 dwarf_getpubnames(self->dbg, pubname_search_cb, 1527 &pubname_param, 0); 1528 if (pubname_param.found) { 1529 line_range_search_cb(&lf.sp_die, &line_range_param); 1530 if (lf.found) 1531 goto found; 1532 } 1533 } 1534 1535 /* Loop on CUs (Compilation Unit) */ 1536 while (!lf.found && ret >= 0) { 1537 if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, 1538 NULL, NULL, NULL) != 0) 1539 break; 1540 1541 /* Get the DIE(Debugging Information Entry) of this CU */ 1542 diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); 1543 if (!diep) 1544 continue; 1545 1546 /* Check if target file is included. */ 1547 if (lr->file) 1548 lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 1549 else 1550 lf.fname = 0; 1551 1552 if (!lr->file || lf.fname) { 1553 if (lr->function) 1554 ret = find_line_range_by_func(&lf); 1555 else { 1556 lf.lno_s = lr->start; 1557 lf.lno_e = lr->end; 1558 ret = find_line_range_by_line(NULL, &lf); 1559 } 1560 } 1561 off = noff; 1562 } 1563 1564 found: 1565 /* Store comp_dir */ 1566 if (lf.found) { 1567 comp_dir = cu_get_comp_dir(&lf.cu_die); 1568 if (comp_dir) { 1569 lr->comp_dir = strdup(comp_dir); 1570 if (!lr->comp_dir) 1571 ret = -ENOMEM; 1572 } 1573 } 1574 1575 pr_debug("path: %s\n", lr->path); 1576 return (ret < 0) ? ret : lf.found; 1577 } 1578 1579