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 __maybe_unused) 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 tag = dwarf_tag(&type); 529 if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 530 pr_warning("%s is not a data structure nor an union.\n", 531 varname); 532 return -EINVAL; 533 } 534 535 ref = zalloc(sizeof(struct probe_trace_arg_ref)); 536 if (ref == NULL) 537 return -ENOMEM; 538 if (*ref_ptr) 539 (*ref_ptr)->next = ref; 540 else 541 *ref_ptr = ref; 542 } else { 543 /* Verify it is a data structure */ 544 if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 545 pr_warning("%s is not a data structure nor an union.\n", 546 varname); 547 return -EINVAL; 548 } 549 if (field->name[0] == '[') { 550 pr_err("Semantic error: %s is not a pointor" 551 " nor array.\n", varname); 552 return -EINVAL; 553 } 554 if (field->ref) { 555 pr_err("Semantic error: %s must be referred by '.'\n", 556 field->name); 557 return -EINVAL; 558 } 559 if (!ref) { 560 pr_warning("Structure on a register is not " 561 "supported yet.\n"); 562 return -ENOTSUP; 563 } 564 } 565 566 if (die_find_member(&type, field->name, die_mem) == NULL) { 567 pr_warning("%s(tyep:%s) has no member %s.\n", varname, 568 dwarf_diename(&type), field->name); 569 return -EINVAL; 570 } 571 572 /* Get the offset of the field */ 573 if (tag == DW_TAG_union_type) { 574 offs = 0; 575 } else { 576 ret = die_get_data_member_location(die_mem, &offs); 577 if (ret < 0) { 578 pr_warning("Failed to get the offset of %s.\n", 579 field->name); 580 return ret; 581 } 582 } 583 ref->offset += (long)offs; 584 585 next: 586 /* Converting next field */ 587 if (field->next) 588 return convert_variable_fields(die_mem, field->name, 589 field->next, &ref, die_mem); 590 else 591 return 0; 592 } 593 594 /* Show a variables in kprobe event format */ 595 static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 596 { 597 Dwarf_Die die_mem; 598 int ret; 599 600 pr_debug("Converting variable %s into trace event.\n", 601 dwarf_diename(vr_die)); 602 603 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 604 pf->tvar); 605 if (ret == -ENOENT) 606 pr_err("Failed to find the location of %s at this address.\n" 607 " Perhaps, it has been optimized out.\n", pf->pvar->var); 608 else if (ret == -ENOTSUP) 609 pr_err("Sorry, we don't support this variable location yet.\n"); 610 else if (pf->pvar->field) { 611 ret = convert_variable_fields(vr_die, pf->pvar->var, 612 pf->pvar->field, &pf->tvar->ref, 613 &die_mem); 614 vr_die = &die_mem; 615 } 616 if (ret == 0) 617 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); 618 /* *expr will be cached in libdw. Don't free it. */ 619 return ret; 620 } 621 622 /* Find a variable in a scope DIE */ 623 static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) 624 { 625 Dwarf_Die vr_die; 626 char buf[32], *ptr; 627 int ret = 0; 628 629 if (!is_c_varname(pf->pvar->var)) { 630 /* Copy raw parameters */ 631 pf->tvar->value = strdup(pf->pvar->var); 632 if (pf->tvar->value == NULL) 633 return -ENOMEM; 634 if (pf->pvar->type) { 635 pf->tvar->type = strdup(pf->pvar->type); 636 if (pf->tvar->type == NULL) 637 return -ENOMEM; 638 } 639 if (pf->pvar->name) { 640 pf->tvar->name = strdup(pf->pvar->name); 641 if (pf->tvar->name == NULL) 642 return -ENOMEM; 643 } else 644 pf->tvar->name = NULL; 645 return 0; 646 } 647 648 if (pf->pvar->name) 649 pf->tvar->name = strdup(pf->pvar->name); 650 else { 651 ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); 652 if (ret < 0) 653 return ret; 654 ptr = strchr(buf, ':'); /* Change type separator to _ */ 655 if (ptr) 656 *ptr = '_'; 657 pf->tvar->name = strdup(buf); 658 } 659 if (pf->tvar->name == NULL) 660 return -ENOMEM; 661 662 pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); 663 /* Search child die for local variables and parameters. */ 664 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 665 /* Search again in global variables */ 666 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 667 ret = -ENOENT; 668 } 669 if (ret >= 0) 670 ret = convert_variable(&vr_die, pf); 671 672 if (ret < 0) 673 pr_warning("Failed to find '%s' in this function.\n", 674 pf->pvar->var); 675 return ret; 676 } 677 678 /* Convert subprogram DIE to trace point */ 679 static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, 680 bool retprobe, struct probe_trace_point *tp) 681 { 682 Dwarf_Addr eaddr, highaddr; 683 const char *name; 684 685 /* Copy the name of probe point */ 686 name = dwarf_diename(sp_die); 687 if (name) { 688 if (dwarf_entrypc(sp_die, &eaddr) != 0) { 689 pr_warning("Failed to get entry address of %s\n", 690 dwarf_diename(sp_die)); 691 return -ENOENT; 692 } 693 if (dwarf_highpc(sp_die, &highaddr) != 0) { 694 pr_warning("Failed to get end address of %s\n", 695 dwarf_diename(sp_die)); 696 return -ENOENT; 697 } 698 if (paddr > highaddr) { 699 pr_warning("Offset specified is greater than size of %s\n", 700 dwarf_diename(sp_die)); 701 return -EINVAL; 702 } 703 tp->symbol = strdup(name); 704 if (tp->symbol == NULL) 705 return -ENOMEM; 706 tp->offset = (unsigned long)(paddr - eaddr); 707 } else 708 /* This function has no name. */ 709 tp->offset = (unsigned long)paddr; 710 711 /* Return probe must be on the head of a subprogram */ 712 if (retprobe) { 713 if (eaddr != paddr) { 714 pr_warning("Return probe must be on the head of" 715 " a real function.\n"); 716 return -EINVAL; 717 } 718 tp->retprobe = true; 719 } 720 721 return 0; 722 } 723 724 /* Call probe_finder callback with scope DIE */ 725 static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 726 { 727 Dwarf_Attribute fb_attr; 728 size_t nops; 729 int ret; 730 731 if (!sc_die) { 732 pr_err("Caller must pass a scope DIE. Program error.\n"); 733 return -EINVAL; 734 } 735 736 /* If not a real subprogram, find a real one */ 737 if (dwarf_tag(sc_die) != DW_TAG_subprogram) { 738 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 739 pr_warning("Failed to find probe point in any " 740 "functions.\n"); 741 return -ENOENT; 742 } 743 } else 744 memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); 745 746 /* Get the frame base attribute/ops from subprogram */ 747 dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); 748 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 749 if (ret <= 0 || nops == 0) { 750 pf->fb_ops = NULL; 751 #if _ELFUTILS_PREREQ(0, 142) 752 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 753 pf->cfi != NULL) { 754 Dwarf_Frame *frame; 755 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 756 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 757 pr_warning("Failed to get call frame on 0x%jx\n", 758 (uintmax_t)pf->addr); 759 return -ENOENT; 760 } 761 #endif 762 } 763 764 /* Call finder's callback handler */ 765 ret = pf->callback(sc_die, pf); 766 767 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 768 pf->fb_ops = NULL; 769 770 return ret; 771 } 772 773 struct find_scope_param { 774 const char *function; 775 const char *file; 776 int line; 777 int diff; 778 Dwarf_Die *die_mem; 779 bool found; 780 }; 781 782 static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) 783 { 784 struct find_scope_param *fsp = data; 785 const char *file; 786 int lno; 787 788 /* Skip if declared file name does not match */ 789 if (fsp->file) { 790 file = dwarf_decl_file(fn_die); 791 if (!file || strcmp(fsp->file, file) != 0) 792 return 0; 793 } 794 /* If the function name is given, that's what user expects */ 795 if (fsp->function) { 796 if (die_compare_name(fn_die, fsp->function)) { 797 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 798 fsp->found = true; 799 return 1; 800 } 801 } else { 802 /* With the line number, find the nearest declared DIE */ 803 dwarf_decl_line(fn_die, &lno); 804 if (lno < fsp->line && fsp->diff > fsp->line - lno) { 805 /* Keep a candidate and continue */ 806 fsp->diff = fsp->line - lno; 807 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); 808 fsp->found = true; 809 } 810 } 811 return 0; 812 } 813 814 /* Find an appropriate scope fits to given conditions */ 815 static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) 816 { 817 struct find_scope_param fsp = { 818 .function = pf->pev->point.function, 819 .file = pf->fname, 820 .line = pf->lno, 821 .diff = INT_MAX, 822 .die_mem = die_mem, 823 .found = false, 824 }; 825 826 cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); 827 828 return fsp.found ? die_mem : NULL; 829 } 830 831 static int probe_point_line_walker(const char *fname, int lineno, 832 Dwarf_Addr addr, void *data) 833 { 834 struct probe_finder *pf = data; 835 Dwarf_Die *sc_die, die_mem; 836 int ret; 837 838 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 839 return 0; 840 841 pf->addr = addr; 842 sc_die = find_best_scope(pf, &die_mem); 843 if (!sc_die) { 844 pr_warning("Failed to find scope of probe point.\n"); 845 return -ENOENT; 846 } 847 848 ret = call_probe_finder(sc_die, pf); 849 850 /* Continue if no error, because the line will be in inline function */ 851 return ret < 0 ? ret : 0; 852 } 853 854 /* Find probe point from its line number */ 855 static int find_probe_point_by_line(struct probe_finder *pf) 856 { 857 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); 858 } 859 860 /* Find lines which match lazy pattern */ 861 static int find_lazy_match_lines(struct list_head *head, 862 const char *fname, const char *pat) 863 { 864 FILE *fp; 865 char *line = NULL; 866 size_t line_len; 867 ssize_t len; 868 int count = 0, linenum = 1; 869 870 fp = fopen(fname, "r"); 871 if (!fp) { 872 pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); 873 return -errno; 874 } 875 876 while ((len = getline(&line, &line_len, fp)) > 0) { 877 878 if (line[len - 1] == '\n') 879 line[len - 1] = '\0'; 880 881 if (strlazymatch(line, pat)) { 882 line_list__add_line(head, linenum); 883 count++; 884 } 885 linenum++; 886 } 887 888 if (ferror(fp)) 889 count = -errno; 890 free(line); 891 fclose(fp); 892 893 if (count == 0) 894 pr_debug("No matched lines found in %s.\n", fname); 895 return count; 896 } 897 898 static int probe_point_lazy_walker(const char *fname, int lineno, 899 Dwarf_Addr addr, void *data) 900 { 901 struct probe_finder *pf = data; 902 Dwarf_Die *sc_die, die_mem; 903 int ret; 904 905 if (!line_list__has_line(&pf->lcache, lineno) || 906 strtailcmp(fname, pf->fname) != 0) 907 return 0; 908 909 pr_debug("Probe line found: line:%d addr:0x%llx\n", 910 lineno, (unsigned long long)addr); 911 pf->addr = addr; 912 pf->lno = lineno; 913 sc_die = find_best_scope(pf, &die_mem); 914 if (!sc_die) { 915 pr_warning("Failed to find scope of probe point.\n"); 916 return -ENOENT; 917 } 918 919 ret = call_probe_finder(sc_die, pf); 920 921 /* 922 * Continue if no error, because the lazy pattern will match 923 * to other lines 924 */ 925 return ret < 0 ? ret : 0; 926 } 927 928 /* Find probe points from lazy pattern */ 929 static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 930 { 931 int ret = 0; 932 933 if (list_empty(&pf->lcache)) { 934 /* Matching lazy line pattern */ 935 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 936 pf->pev->point.lazy_line); 937 if (ret <= 0) 938 return ret; 939 } 940 941 return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 942 } 943 944 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 945 { 946 struct probe_finder *pf = data; 947 struct perf_probe_point *pp = &pf->pev->point; 948 Dwarf_Addr addr; 949 int ret; 950 951 if (pp->lazy_line) 952 ret = find_probe_point_lazy(in_die, pf); 953 else { 954 /* Get probe address */ 955 if (dwarf_entrypc(in_die, &addr) != 0) { 956 pr_warning("Failed to get entry address of %s.\n", 957 dwarf_diename(in_die)); 958 return -ENOENT; 959 } 960 pf->addr = addr; 961 pf->addr += pp->offset; 962 pr_debug("found inline addr: 0x%jx\n", 963 (uintmax_t)pf->addr); 964 965 ret = call_probe_finder(in_die, pf); 966 } 967 968 return ret; 969 } 970 971 /* Callback parameter with return value for libdw */ 972 struct dwarf_callback_param { 973 void *data; 974 int retval; 975 }; 976 977 /* Search function from function name */ 978 static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 979 { 980 struct dwarf_callback_param *param = data; 981 struct probe_finder *pf = param->data; 982 struct perf_probe_point *pp = &pf->pev->point; 983 Dwarf_Attribute attr; 984 985 /* Check tag and diename */ 986 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 987 !die_compare_name(sp_die, pp->function) || 988 dwarf_attr(sp_die, DW_AT_declaration, &attr)) 989 return DWARF_CB_OK; 990 991 /* Check declared file */ 992 if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) 993 return DWARF_CB_OK; 994 995 pf->fname = dwarf_decl_file(sp_die); 996 if (pp->line) { /* Function relative line */ 997 dwarf_decl_line(sp_die, &pf->lno); 998 pf->lno += pp->line; 999 param->retval = find_probe_point_by_line(pf); 1000 } else if (!dwarf_func_inline(sp_die)) { 1001 /* Real function */ 1002 if (pp->lazy_line) 1003 param->retval = find_probe_point_lazy(sp_die, pf); 1004 else { 1005 if (dwarf_entrypc(sp_die, &pf->addr) != 0) { 1006 pr_warning("Failed to get entry address of " 1007 "%s.\n", dwarf_diename(sp_die)); 1008 param->retval = -ENOENT; 1009 return DWARF_CB_ABORT; 1010 } 1011 pf->addr += pp->offset; 1012 /* TODO: Check the address in this function */ 1013 param->retval = call_probe_finder(sp_die, pf); 1014 } 1015 } else 1016 /* Inlined function: search instances */ 1017 param->retval = die_walk_instances(sp_die, 1018 probe_point_inline_cb, (void *)pf); 1019 1020 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ 1021 } 1022 1023 static int find_probe_point_by_func(struct probe_finder *pf) 1024 { 1025 struct dwarf_callback_param _param = {.data = (void *)pf, 1026 .retval = 0}; 1027 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); 1028 return _param.retval; 1029 } 1030 1031 struct pubname_callback_param { 1032 char *function; 1033 char *file; 1034 Dwarf_Die *cu_die; 1035 Dwarf_Die *sp_die; 1036 int found; 1037 }; 1038 1039 static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) 1040 { 1041 struct pubname_callback_param *param = data; 1042 1043 if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { 1044 if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) 1045 return DWARF_CB_OK; 1046 1047 if (die_compare_name(param->sp_die, param->function)) { 1048 if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) 1049 return DWARF_CB_OK; 1050 1051 if (param->file && 1052 strtailcmp(param->file, dwarf_decl_file(param->sp_die))) 1053 return DWARF_CB_OK; 1054 1055 param->found = 1; 1056 return DWARF_CB_ABORT; 1057 } 1058 } 1059 1060 return DWARF_CB_OK; 1061 } 1062 1063 /* Find probe points from debuginfo */ 1064 static int debuginfo__find_probes(struct debuginfo *self, 1065 struct probe_finder *pf) 1066 { 1067 struct perf_probe_point *pp = &pf->pev->point; 1068 Dwarf_Off off, noff; 1069 size_t cuhl; 1070 Dwarf_Die *diep; 1071 int ret = 0; 1072 1073 #if _ELFUTILS_PREREQ(0, 142) 1074 /* Get the call frame information from this dwarf */ 1075 pf->cfi = dwarf_getcfi(self->dbg); 1076 #endif 1077 1078 off = 0; 1079 line_list__init(&pf->lcache); 1080 1081 /* Fastpath: lookup by function name from .debug_pubnames section */ 1082 if (pp->function) { 1083 struct pubname_callback_param pubname_param = { 1084 .function = pp->function, 1085 .file = pp->file, 1086 .cu_die = &pf->cu_die, 1087 .sp_die = &pf->sp_die, 1088 .found = 0, 1089 }; 1090 struct dwarf_callback_param probe_param = { 1091 .data = pf, 1092 }; 1093 1094 dwarf_getpubnames(self->dbg, pubname_search_cb, 1095 &pubname_param, 0); 1096 if (pubname_param.found) { 1097 ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1098 if (ret) 1099 goto found; 1100 } 1101 } 1102 1103 /* Loop on CUs (Compilation Unit) */ 1104 while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 1105 /* Get the DIE(Debugging Information Entry) of this CU */ 1106 diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); 1107 if (!diep) 1108 continue; 1109 1110 /* Check if target file is included. */ 1111 if (pp->file) 1112 pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1113 else 1114 pf->fname = NULL; 1115 1116 if (!pp->file || pf->fname) { 1117 if (pp->function) 1118 ret = find_probe_point_by_func(pf); 1119 else if (pp->lazy_line) 1120 ret = find_probe_point_lazy(NULL, pf); 1121 else { 1122 pf->lno = pp->line; 1123 ret = find_probe_point_by_line(pf); 1124 } 1125 if (ret < 0) 1126 break; 1127 } 1128 off = noff; 1129 } 1130 1131 found: 1132 line_list__free(&pf->lcache); 1133 1134 return ret; 1135 } 1136 1137 /* Add a found probe point into trace event list */ 1138 static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1139 { 1140 struct trace_event_finder *tf = 1141 container_of(pf, struct trace_event_finder, pf); 1142 struct probe_trace_event *tev; 1143 int ret, i; 1144 1145 /* Check number of tevs */ 1146 if (tf->ntevs == tf->max_tevs) { 1147 pr_warning("Too many( > %d) probe point found.\n", 1148 tf->max_tevs); 1149 return -ERANGE; 1150 } 1151 tev = &tf->tevs[tf->ntevs++]; 1152 1153 /* Trace point should be converted from subprogram DIE */ 1154 ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1155 pf->pev->point.retprobe, &tev->point); 1156 if (ret < 0) 1157 return ret; 1158 1159 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1160 tev->point.offset); 1161 1162 /* Find each argument */ 1163 tev->nargs = pf->pev->nargs; 1164 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1165 if (tev->args == NULL) 1166 return -ENOMEM; 1167 for (i = 0; i < pf->pev->nargs; i++) { 1168 pf->pvar = &pf->pev->args[i]; 1169 pf->tvar = &tev->args[i]; 1170 /* Variable should be found from scope DIE */ 1171 ret = find_variable(sc_die, pf); 1172 if (ret != 0) 1173 return ret; 1174 } 1175 1176 return 0; 1177 } 1178 1179 /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1180 int debuginfo__find_trace_events(struct debuginfo *self, 1181 struct perf_probe_event *pev, 1182 struct probe_trace_event **tevs, int max_tevs) 1183 { 1184 struct trace_event_finder tf = { 1185 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1186 .max_tevs = max_tevs}; 1187 int ret; 1188 1189 /* Allocate result tevs array */ 1190 *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); 1191 if (*tevs == NULL) 1192 return -ENOMEM; 1193 1194 tf.tevs = *tevs; 1195 tf.ntevs = 0; 1196 1197 ret = debuginfo__find_probes(self, &tf.pf); 1198 if (ret < 0) { 1199 free(*tevs); 1200 *tevs = NULL; 1201 return ret; 1202 } 1203 1204 return (ret < 0) ? ret : tf.ntevs; 1205 } 1206 1207 #define MAX_VAR_LEN 64 1208 1209 /* Collect available variables in this scope */ 1210 static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1211 { 1212 struct available_var_finder *af = data; 1213 struct variable_list *vl; 1214 char buf[MAX_VAR_LEN]; 1215 int tag, ret; 1216 1217 vl = &af->vls[af->nvls - 1]; 1218 1219 tag = dwarf_tag(die_mem); 1220 if (tag == DW_TAG_formal_parameter || 1221 tag == DW_TAG_variable) { 1222 ret = convert_variable_location(die_mem, af->pf.addr, 1223 af->pf.fb_ops, NULL); 1224 if (ret == 0) { 1225 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); 1226 pr_debug2("Add new var: %s\n", buf); 1227 if (ret > 0) 1228 strlist__add(vl->vars, buf); 1229 } 1230 } 1231 1232 if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1233 return DIE_FIND_CB_CONTINUE; 1234 else 1235 return DIE_FIND_CB_SIBLING; 1236 } 1237 1238 /* Add a found vars into available variables list */ 1239 static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) 1240 { 1241 struct available_var_finder *af = 1242 container_of(pf, struct available_var_finder, pf); 1243 struct variable_list *vl; 1244 Dwarf_Die die_mem; 1245 int ret; 1246 1247 /* Check number of tevs */ 1248 if (af->nvls == af->max_vls) { 1249 pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1250 return -ERANGE; 1251 } 1252 vl = &af->vls[af->nvls++]; 1253 1254 /* Trace point should be converted from subprogram DIE */ 1255 ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1256 pf->pev->point.retprobe, &vl->point); 1257 if (ret < 0) 1258 return ret; 1259 1260 pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1261 vl->point.offset); 1262 1263 /* Find local variables */ 1264 vl->vars = strlist__new(true, NULL); 1265 if (vl->vars == NULL) 1266 return -ENOMEM; 1267 af->child = true; 1268 die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); 1269 1270 /* Find external variables */ 1271 if (!af->externs) 1272 goto out; 1273 /* Don't need to search child DIE for externs. */ 1274 af->child = false; 1275 die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); 1276 1277 out: 1278 if (strlist__empty(vl->vars)) { 1279 strlist__delete(vl->vars); 1280 vl->vars = NULL; 1281 } 1282 1283 return ret; 1284 } 1285 1286 /* Find available variables at given probe point */ 1287 int debuginfo__find_available_vars_at(struct debuginfo *self, 1288 struct perf_probe_event *pev, 1289 struct variable_list **vls, 1290 int max_vls, bool externs) 1291 { 1292 struct available_var_finder af = { 1293 .pf = {.pev = pev, .callback = add_available_vars}, 1294 .max_vls = max_vls, .externs = externs}; 1295 int ret; 1296 1297 /* Allocate result vls array */ 1298 *vls = zalloc(sizeof(struct variable_list) * max_vls); 1299 if (*vls == NULL) 1300 return -ENOMEM; 1301 1302 af.vls = *vls; 1303 af.nvls = 0; 1304 1305 ret = debuginfo__find_probes(self, &af.pf); 1306 if (ret < 0) { 1307 /* Free vlist for error */ 1308 while (af.nvls--) { 1309 if (af.vls[af.nvls].point.symbol) 1310 free(af.vls[af.nvls].point.symbol); 1311 if (af.vls[af.nvls].vars) 1312 strlist__delete(af.vls[af.nvls].vars); 1313 } 1314 free(af.vls); 1315 *vls = NULL; 1316 return ret; 1317 } 1318 1319 return (ret < 0) ? ret : af.nvls; 1320 } 1321 1322 /* Reverse search */ 1323 int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, 1324 struct perf_probe_point *ppt) 1325 { 1326 Dwarf_Die cudie, spdie, indie; 1327 Dwarf_Addr _addr, baseaddr; 1328 const char *fname = NULL, *func = NULL, *tmp; 1329 int baseline = 0, lineno = 0, ret = 0; 1330 1331 /* Adjust address with bias */ 1332 addr += self->bias; 1333 1334 /* Find cu die */ 1335 if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { 1336 pr_warning("Failed to find debug information for address %lx\n", 1337 addr); 1338 ret = -EINVAL; 1339 goto end; 1340 } 1341 1342 /* Find a corresponding line (filename and lineno) */ 1343 cu_find_lineinfo(&cudie, addr, &fname, &lineno); 1344 /* Don't care whether it failed or not */ 1345 1346 /* Find a corresponding function (name, baseline and baseaddr) */ 1347 if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 1348 /* Get function entry information */ 1349 tmp = dwarf_diename(&spdie); 1350 if (!tmp || 1351 dwarf_entrypc(&spdie, &baseaddr) != 0 || 1352 dwarf_decl_line(&spdie, &baseline) != 0) 1353 goto post; 1354 func = tmp; 1355 1356 if (addr == (unsigned long)baseaddr) 1357 /* Function entry - Relative line number is 0 */ 1358 lineno = baseline; 1359 else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, 1360 &indie)) { 1361 if (dwarf_entrypc(&indie, &_addr) == 0 && 1362 _addr == addr) 1363 /* 1364 * addr is at an inline function entry. 1365 * In this case, lineno should be the call-site 1366 * line number. 1367 */ 1368 lineno = die_get_call_lineno(&indie); 1369 else { 1370 /* 1371 * addr is in an inline function body. 1372 * Since lineno points one of the lines 1373 * of the inline function, baseline should 1374 * be the entry line of the inline function. 1375 */ 1376 tmp = dwarf_diename(&indie); 1377 if (tmp && 1378 dwarf_decl_line(&spdie, &baseline) == 0) 1379 func = tmp; 1380 } 1381 } 1382 } 1383 1384 post: 1385 /* Make a relative line number or an offset */ 1386 if (lineno) 1387 ppt->line = lineno - baseline; 1388 else if (func) 1389 ppt->offset = addr - (unsigned long)baseaddr; 1390 1391 /* Duplicate strings */ 1392 if (func) { 1393 ppt->function = strdup(func); 1394 if (ppt->function == NULL) { 1395 ret = -ENOMEM; 1396 goto end; 1397 } 1398 } 1399 if (fname) { 1400 ppt->file = strdup(fname); 1401 if (ppt->file == NULL) { 1402 if (ppt->function) { 1403 free(ppt->function); 1404 ppt->function = NULL; 1405 } 1406 ret = -ENOMEM; 1407 goto end; 1408 } 1409 } 1410 end: 1411 if (ret == 0 && (fname || func)) 1412 ret = 1; /* Found a point */ 1413 return ret; 1414 } 1415 1416 /* Add a line and store the src path */ 1417 static int line_range_add_line(const char *src, unsigned int lineno, 1418 struct line_range *lr) 1419 { 1420 /* Copy source path */ 1421 if (!lr->path) { 1422 lr->path = strdup(src); 1423 if (lr->path == NULL) 1424 return -ENOMEM; 1425 } 1426 return line_list__add_line(&lr->line_list, lineno); 1427 } 1428 1429 static int line_range_walk_cb(const char *fname, int lineno, 1430 Dwarf_Addr addr __maybe_unused, 1431 void *data) 1432 { 1433 struct line_finder *lf = data; 1434 1435 if ((strtailcmp(fname, lf->fname) != 0) || 1436 (lf->lno_s > lineno || lf->lno_e < lineno)) 1437 return 0; 1438 1439 if (line_range_add_line(fname, lineno, lf->lr) < 0) 1440 return -EINVAL; 1441 1442 return 0; 1443 } 1444 1445 /* Find line range from its line number */ 1446 static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1447 { 1448 int ret; 1449 1450 ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); 1451 1452 /* Update status */ 1453 if (ret >= 0) 1454 if (!list_empty(&lf->lr->line_list)) 1455 ret = lf->found = 1; 1456 else 1457 ret = 0; /* Lines are not found */ 1458 else { 1459 free(lf->lr->path); 1460 lf->lr->path = NULL; 1461 } 1462 return ret; 1463 } 1464 1465 static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1466 { 1467 find_line_range_by_line(in_die, data); 1468 1469 /* 1470 * We have to check all instances of inlined function, because 1471 * some execution paths can be optimized out depends on the 1472 * function argument of instances 1473 */ 1474 return 0; 1475 } 1476 1477 /* Search function from function name */ 1478 static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1479 { 1480 struct dwarf_callback_param *param = data; 1481 struct line_finder *lf = param->data; 1482 struct line_range *lr = lf->lr; 1483 1484 /* Check declared file */ 1485 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 1486 return DWARF_CB_OK; 1487 1488 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1489 die_compare_name(sp_die, lr->function)) { 1490 lf->fname = dwarf_decl_file(sp_die); 1491 dwarf_decl_line(sp_die, &lr->offset); 1492 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1493 lf->lno_s = lr->offset + lr->start; 1494 if (lf->lno_s < 0) /* Overflow */ 1495 lf->lno_s = INT_MAX; 1496 lf->lno_e = lr->offset + lr->end; 1497 if (lf->lno_e < 0) /* Overflow */ 1498 lf->lno_e = INT_MAX; 1499 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); 1500 lr->start = lf->lno_s; 1501 lr->end = lf->lno_e; 1502 if (dwarf_func_inline(sp_die)) 1503 param->retval = die_walk_instances(sp_die, 1504 line_range_inline_cb, lf); 1505 else 1506 param->retval = find_line_range_by_line(sp_die, lf); 1507 return DWARF_CB_ABORT; 1508 } 1509 return DWARF_CB_OK; 1510 } 1511 1512 static int find_line_range_by_func(struct line_finder *lf) 1513 { 1514 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; 1515 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); 1516 return param.retval; 1517 } 1518 1519 int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) 1520 { 1521 struct line_finder lf = {.lr = lr, .found = 0}; 1522 int ret = 0; 1523 Dwarf_Off off = 0, noff; 1524 size_t cuhl; 1525 Dwarf_Die *diep; 1526 const char *comp_dir; 1527 1528 /* Fastpath: lookup by function name from .debug_pubnames section */ 1529 if (lr->function) { 1530 struct pubname_callback_param pubname_param = { 1531 .function = lr->function, .file = lr->file, 1532 .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; 1533 struct dwarf_callback_param line_range_param = { 1534 .data = (void *)&lf, .retval = 0}; 1535 1536 dwarf_getpubnames(self->dbg, pubname_search_cb, 1537 &pubname_param, 0); 1538 if (pubname_param.found) { 1539 line_range_search_cb(&lf.sp_die, &line_range_param); 1540 if (lf.found) 1541 goto found; 1542 } 1543 } 1544 1545 /* Loop on CUs (Compilation Unit) */ 1546 while (!lf.found && ret >= 0) { 1547 if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, 1548 NULL, NULL, NULL) != 0) 1549 break; 1550 1551 /* Get the DIE(Debugging Information Entry) of this CU */ 1552 diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); 1553 if (!diep) 1554 continue; 1555 1556 /* Check if target file is included. */ 1557 if (lr->file) 1558 lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 1559 else 1560 lf.fname = 0; 1561 1562 if (!lr->file || lf.fname) { 1563 if (lr->function) 1564 ret = find_line_range_by_func(&lf); 1565 else { 1566 lf.lno_s = lr->start; 1567 lf.lno_e = lr->end; 1568 ret = find_line_range_by_line(NULL, &lf); 1569 } 1570 } 1571 off = noff; 1572 } 1573 1574 found: 1575 /* Store comp_dir */ 1576 if (lf.found) { 1577 comp_dir = cu_get_comp_dir(&lf.cu_die); 1578 if (comp_dir) { 1579 lr->comp_dir = strdup(comp_dir); 1580 if (!lr->comp_dir) 1581 ret = -ENOMEM; 1582 } 1583 } 1584 1585 pr_debug("path: %s\n", lr->path); 1586 return (ret < 0) ? ret : lf.found; 1587 } 1588 1589