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 <ctype.h> 34 35 #include "string.h" 36 #include "event.h" 37 #include "debug.h" 38 #include "util.h" 39 #include "probe-finder.h" 40 41 42 /* 43 * Generic dwarf analysis helpers 44 */ 45 46 #define X86_32_MAX_REGS 8 47 const char *x86_32_regs_table[X86_32_MAX_REGS] = { 48 "%ax", 49 "%cx", 50 "%dx", 51 "%bx", 52 "$stack", /* Stack address instead of %sp */ 53 "%bp", 54 "%si", 55 "%di", 56 }; 57 58 #define X86_64_MAX_REGS 16 59 const char *x86_64_regs_table[X86_64_MAX_REGS] = { 60 "%ax", 61 "%dx", 62 "%cx", 63 "%bx", 64 "%si", 65 "%di", 66 "%bp", 67 "%sp", 68 "%r8", 69 "%r9", 70 "%r10", 71 "%r11", 72 "%r12", 73 "%r13", 74 "%r14", 75 "%r15", 76 }; 77 78 /* TODO: switching by dwarf address size */ 79 #ifdef __x86_64__ 80 #define ARCH_MAX_REGS X86_64_MAX_REGS 81 #define arch_regs_table x86_64_regs_table 82 #else 83 #define ARCH_MAX_REGS X86_32_MAX_REGS 84 #define arch_regs_table x86_32_regs_table 85 #endif 86 87 /* Return architecture dependent register string (for kprobe-tracer) */ 88 static const char *get_arch_regstr(unsigned int n) 89 { 90 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL; 91 } 92 93 /* 94 * Compare the tail of two strings. 95 * Return 0 if whole of either string is same as another's tail part. 96 */ 97 static int strtailcmp(const char *s1, const char *s2) 98 { 99 int i1 = strlen(s1); 100 int i2 = strlen(s2); 101 while (--i1 >= 0 && --i2 >= 0) { 102 if (s1[i1] != s2[i2]) 103 return s1[i1] - s2[i2]; 104 } 105 return 0; 106 } 107 108 /* Line number list operations */ 109 110 /* Add a line to line number list */ 111 static void line_list__add_line(struct list_head *head, unsigned int line) 112 { 113 struct line_node *ln; 114 struct list_head *p; 115 116 /* Reverse search, because new line will be the last one */ 117 list_for_each_entry_reverse(ln, head, list) { 118 if (ln->line < line) { 119 p = &ln->list; 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; 126 found: 127 pr_debug("line list: add a line %u\n", line); 128 ln = xzalloc(sizeof(struct line_node)); 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 */ 135 static int line_list__has_line(struct list_head *head, unsigned int line) 136 { 137 struct line_node *ln; 138 139 /* Reverse search, because new line will be the last one */ 140 list_for_each_entry(ln, head, list) 141 if (ln->line == line) 142 return 1; 143 144 return 0; 145 } 146 147 /* Init line number list */ 148 static void line_list__init(struct list_head *head) 149 { 150 INIT_LIST_HEAD(head); 151 } 152 153 /* Free line number list */ 154 static void line_list__free(struct list_head *head) 155 { 156 struct line_node *ln; 157 while (!list_empty(head)) { 158 ln = list_first_entry(head, struct line_node, list); 159 list_del(&ln->list); 160 free(ln); 161 } 162 } 163 164 /* Dwarf wrappers */ 165 166 /* Find the realpath of the target file. */ 167 static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) 168 { 169 Dwarf_Files *files; 170 size_t nfiles, i; 171 const char *src = NULL; 172 int ret; 173 174 if (!fname) 175 return NULL; 176 177 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); 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 return src; 187 } 188 189 struct __addr_die_search_param { 190 Dwarf_Addr addr; 191 Dwarf_Die *die_mem; 192 }; 193 194 static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) 195 { 196 struct __addr_die_search_param *ad = data; 197 198 if (dwarf_tag(fn_die) == DW_TAG_subprogram && 199 dwarf_haspc(fn_die, ad->addr)) { 200 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); 201 return DWARF_CB_ABORT; 202 } 203 return DWARF_CB_OK; 204 } 205 206 /* Search a real subprogram including this line, */ 207 static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, 208 Dwarf_Die *die_mem) 209 { 210 struct __addr_die_search_param ad; 211 ad.addr = addr; 212 ad.die_mem = die_mem; 213 /* dwarf_getscopes can't find subprogram. */ 214 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) 215 return NULL; 216 else 217 return die_mem; 218 } 219 220 /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ 221 static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 222 Dwarf_Die *die_mem) 223 { 224 Dwarf_Die child_die; 225 int ret; 226 227 ret = dwarf_child(sp_die, die_mem); 228 if (ret != 0) 229 return NULL; 230 231 do { 232 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && 233 dwarf_haspc(die_mem, addr)) 234 return die_mem; 235 236 if (die_find_inlinefunc(die_mem, addr, &child_die)) { 237 memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); 238 return die_mem; 239 } 240 } while (dwarf_siblingof(die_mem, die_mem) == 0); 241 242 return NULL; 243 } 244 245 /* Compare diename and tname */ 246 static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 247 { 248 const char *name; 249 name = dwarf_diename(dw_die); 250 DIE_IF(name == NULL); 251 return strcmp(tname, name); 252 } 253 254 /* Get entry pc(or low pc, 1st entry of ranges) of the die */ 255 static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) 256 { 257 Dwarf_Addr epc; 258 int ret; 259 260 ret = dwarf_entrypc(dw_die, &epc); 261 DIE_IF(ret == -1); 262 return epc; 263 } 264 265 /* Get a variable die */ 266 static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, 267 Dwarf_Die *die_mem) 268 { 269 Dwarf_Die child_die; 270 int tag; 271 int ret; 272 273 ret = dwarf_child(sp_die, die_mem); 274 if (ret != 0) 275 return NULL; 276 277 do { 278 tag = dwarf_tag(die_mem); 279 if ((tag == DW_TAG_formal_parameter || 280 tag == DW_TAG_variable) && 281 (die_compare_name(die_mem, name) == 0)) 282 return die_mem; 283 284 if (die_find_variable(die_mem, name, &child_die)) { 285 memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); 286 return die_mem; 287 } 288 } while (dwarf_siblingof(die_mem, die_mem) == 0); 289 290 return NULL; 291 } 292 293 /* 294 * Probe finder related functions 295 */ 296 297 /* Show a location */ 298 static void show_location(Dwarf_Op *op, struct probe_finder *pf) 299 { 300 unsigned int regn; 301 Dwarf_Word offs = 0; 302 int deref = 0, ret; 303 const char *regs; 304 305 /* TODO: support CFA */ 306 /* If this is based on frame buffer, set the offset */ 307 if (op->atom == DW_OP_fbreg) { 308 if (pf->fb_ops == NULL) 309 die("The attribute of frame base is not supported.\n"); 310 deref = 1; 311 offs = op->number; 312 op = &pf->fb_ops[0]; 313 } 314 315 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 316 regn = op->atom - DW_OP_breg0; 317 offs += op->number; 318 deref = 1; 319 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 320 regn = op->atom - DW_OP_reg0; 321 } else if (op->atom == DW_OP_bregx) { 322 regn = op->number; 323 offs += op->number2; 324 deref = 1; 325 } else if (op->atom == DW_OP_regx) { 326 regn = op->number; 327 } else 328 die("DW_OP %d is not supported.", op->atom); 329 330 regs = get_arch_regstr(regn); 331 if (!regs) 332 die("%u exceeds max register number.", regn); 333 334 if (deref) 335 ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)", 336 pf->var, (intmax_t)offs, regs); 337 else 338 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 339 DIE_IF(ret < 0); 340 DIE_IF(ret >= pf->len); 341 } 342 343 /* Show a variables in kprobe event format */ 344 static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 345 { 346 Dwarf_Attribute attr; 347 Dwarf_Op *expr; 348 size_t nexpr; 349 int ret; 350 351 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 352 goto error; 353 /* TODO: handle more than 1 exprs */ 354 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1); 355 if (ret <= 0 || nexpr == 0) 356 goto error; 357 358 show_location(expr, pf); 359 /* *expr will be cached in libdw. Don't free it. */ 360 return ; 361 error: 362 /* TODO: Support const_value */ 363 die("Failed to find the location of %s at this address.\n" 364 " Perhaps, it has been optimized out.", pf->var); 365 } 366 367 /* Find a variable in a subprogram die */ 368 static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 369 { 370 int ret; 371 Dwarf_Die vr_die; 372 373 /* TODO: Support struct members and arrays */ 374 if (!is_c_varname(pf->var)) { 375 /* Output raw parameters */ 376 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 377 DIE_IF(ret < 0); 378 DIE_IF(ret >= pf->len); 379 return ; 380 } 381 382 pr_debug("Searching '%s' variable in context.\n", pf->var); 383 /* Search child die for local variables and parameters. */ 384 if (!die_find_variable(sp_die, pf->var, &vr_die)) 385 die("Failed to find '%s' in this function.", pf->var); 386 387 show_variable(&vr_die, pf); 388 } 389 390 /* Show a probe point to output buffer */ 391 static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) 392 { 393 struct probe_point *pp = pf->pp; 394 Dwarf_Addr eaddr; 395 Dwarf_Die die_mem; 396 const char *name; 397 char tmp[MAX_PROBE_BUFFER]; 398 int ret, i, len; 399 Dwarf_Attribute fb_attr; 400 size_t nops; 401 402 /* If no real subprogram, find a real one */ 403 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 404 sp_die = die_find_real_subprogram(&pf->cu_die, 405 pf->addr, &die_mem); 406 if (!sp_die) 407 die("Probe point is not found in subprograms."); 408 } 409 410 /* Output name of probe point */ 411 name = dwarf_diename(sp_die); 412 if (name) { 413 dwarf_entrypc(sp_die, &eaddr); 414 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name, 415 (unsigned long)(pf->addr - eaddr)); 416 /* Copy the function name if possible */ 417 if (!pp->function) { 418 pp->function = xstrdup(name); 419 pp->offset = (size_t)(pf->addr - eaddr); 420 } 421 } else { 422 /* This function has no name. */ 423 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx", 424 (uintmax_t)pf->addr); 425 if (!pp->function) { 426 /* TODO: Use _stext */ 427 pp->function = xstrdup(""); 428 pp->offset = (size_t)pf->addr; 429 } 430 } 431 DIE_IF(ret < 0); 432 DIE_IF(ret >= MAX_PROBE_BUFFER); 433 len = ret; 434 pr_debug("Probe point found: %s\n", tmp); 435 436 /* Get the frame base attribute/ops */ 437 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 438 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 439 if (ret <= 0 || nops == 0) 440 pf->fb_ops = NULL; 441 442 /* Find each argument */ 443 /* TODO: use dwarf_cfi_addrframe */ 444 for (i = 0; i < pp->nr_args; i++) { 445 pf->var = pp->args[i]; 446 pf->buf = &tmp[len]; 447 pf->len = MAX_PROBE_BUFFER - len; 448 find_variable(sp_die, pf); 449 len += strlen(pf->buf); 450 } 451 452 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 453 pf->fb_ops = NULL; 454 455 if (pp->found == MAX_PROBES) 456 die("Too many( > %d) probe point found.\n", MAX_PROBES); 457 458 pp->probes[pp->found] = xstrdup(tmp); 459 pp->found++; 460 } 461 462 /* Find probe point from its line number */ 463 static void find_probe_point_by_line(struct probe_finder *pf) 464 { 465 Dwarf_Lines *lines; 466 Dwarf_Line *line; 467 size_t nlines, i; 468 Dwarf_Addr addr; 469 int lineno; 470 int ret; 471 472 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); 473 DIE_IF(ret != 0); 474 475 for (i = 0; i < nlines; i++) { 476 line = dwarf_onesrcline(lines, i); 477 dwarf_lineno(line, &lineno); 478 if (lineno != pf->lno) 479 continue; 480 481 /* TODO: Get fileno from line, but how? */ 482 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) 483 continue; 484 485 ret = dwarf_lineaddr(line, &addr); 486 DIE_IF(ret != 0); 487 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", 488 (int)i, lineno, (uintmax_t)addr); 489 pf->addr = addr; 490 491 show_probe_point(NULL, pf); 492 /* Continuing, because target line might be inlined. */ 493 } 494 } 495 496 /* Find lines which match lazy pattern */ 497 static int find_lazy_match_lines(struct list_head *head, 498 const char *fname, const char *pat) 499 { 500 char *fbuf, *p1, *p2; 501 int fd, line, nlines = 0; 502 struct stat st; 503 504 fd = open(fname, O_RDONLY); 505 if (fd < 0) 506 die("failed to open %s", fname); 507 DIE_IF(fstat(fd, &st) < 0); 508 fbuf = xmalloc(st.st_size + 2); 509 DIE_IF(read(fd, fbuf, st.st_size) < 0); 510 close(fd); 511 fbuf[st.st_size] = '\n'; /* Dummy line */ 512 fbuf[st.st_size + 1] = '\0'; 513 p1 = fbuf; 514 line = 1; 515 while ((p2 = strchr(p1, '\n')) != NULL) { 516 *p2 = '\0'; 517 if (strlazymatch(p1, pat)) { 518 line_list__add_line(head, line); 519 nlines++; 520 } 521 line++; 522 p1 = p2 + 1; 523 } 524 free(fbuf); 525 return nlines; 526 } 527 528 /* Find probe points from lazy pattern */ 529 static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 530 { 531 Dwarf_Lines *lines; 532 Dwarf_Line *line; 533 size_t nlines, i; 534 Dwarf_Addr addr; 535 Dwarf_Die die_mem; 536 int lineno; 537 int ret; 538 539 if (list_empty(&pf->lcache)) { 540 /* Matching lazy line pattern */ 541 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 542 pf->pp->lazy_line); 543 if (ret <= 0) 544 die("No matched lines found in %s.", pf->fname); 545 } 546 547 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); 548 DIE_IF(ret != 0); 549 for (i = 0; i < nlines; i++) { 550 line = dwarf_onesrcline(lines, i); 551 552 dwarf_lineno(line, &lineno); 553 if (!line_list__has_line(&pf->lcache, lineno)) 554 continue; 555 556 /* TODO: Get fileno from line, but how? */ 557 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) 558 continue; 559 560 ret = dwarf_lineaddr(line, &addr); 561 DIE_IF(ret != 0); 562 if (sp_die) { 563 /* Address filtering 1: does sp_die include addr? */ 564 if (!dwarf_haspc(sp_die, addr)) 565 continue; 566 /* Address filtering 2: No child include addr? */ 567 if (die_find_inlinefunc(sp_die, addr, &die_mem)) 568 continue; 569 } 570 571 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n", 572 (int)i, lineno, (unsigned long long)addr); 573 pf->addr = addr; 574 575 show_probe_point(sp_die, pf); 576 /* Continuing, because target line might be inlined. */ 577 } 578 /* TODO: deallocate lines, but how? */ 579 } 580 581 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 582 { 583 struct probe_finder *pf = (struct probe_finder *)data; 584 struct probe_point *pp = pf->pp; 585 586 if (pp->lazy_line) 587 find_probe_point_lazy(in_die, pf); 588 else { 589 /* Get probe address */ 590 pf->addr = die_get_entrypc(in_die); 591 pf->addr += pp->offset; 592 pr_debug("found inline addr: 0x%jx\n", 593 (uintmax_t)pf->addr); 594 595 show_probe_point(in_die, pf); 596 } 597 598 return DWARF_CB_OK; 599 } 600 601 /* Search function from function name */ 602 static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 603 { 604 struct probe_finder *pf = (struct probe_finder *)data; 605 struct probe_point *pp = pf->pp; 606 607 /* Check tag and diename */ 608 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 609 die_compare_name(sp_die, pp->function) != 0) 610 return 0; 611 612 pf->fname = dwarf_decl_file(sp_die); 613 if (pp->line) { /* Function relative line */ 614 dwarf_decl_line(sp_die, &pf->lno); 615 pf->lno += pp->line; 616 find_probe_point_by_line(pf); 617 } else if (!dwarf_func_inline(sp_die)) { 618 /* Real function */ 619 if (pp->lazy_line) 620 find_probe_point_lazy(sp_die, pf); 621 else { 622 pf->addr = die_get_entrypc(sp_die); 623 pf->addr += pp->offset; 624 /* TODO: Check the address in this function */ 625 show_probe_point(sp_die, pf); 626 } 627 } else 628 /* Inlined function: search instances */ 629 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf); 630 631 return 1; /* Exit; no same symbol in this CU. */ 632 } 633 634 static void find_probe_point_by_func(struct probe_finder *pf) 635 { 636 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0); 637 } 638 639 /* Find a probe point */ 640 int find_probe_point(int fd, struct probe_point *pp) 641 { 642 struct probe_finder pf = {.pp = pp}; 643 Dwarf_Off off, noff; 644 size_t cuhl; 645 Dwarf_Die *diep; 646 Dwarf *dbg; 647 648 dbg = dwarf_begin(fd, DWARF_C_READ); 649 if (!dbg) 650 return -ENOENT; 651 652 pp->found = 0; 653 off = 0; 654 line_list__init(&pf.lcache); 655 /* Loop on CUs (Compilation Unit) */ 656 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 657 /* Get the DIE(Debugging Information Entry) of this CU */ 658 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); 659 if (!diep) 660 continue; 661 662 /* Check if target file is included. */ 663 if (pp->file) 664 pf.fname = cu_find_realpath(&pf.cu_die, pp->file); 665 else 666 pf.fname = NULL; 667 668 if (!pp->file || pf.fname) { 669 if (pp->function) 670 find_probe_point_by_func(&pf); 671 else if (pp->lazy_line) 672 find_probe_point_lazy(NULL, &pf); 673 else { 674 pf.lno = pp->line; 675 find_probe_point_by_line(&pf); 676 } 677 } 678 off = noff; 679 } 680 line_list__free(&pf.lcache); 681 dwarf_end(dbg); 682 683 return pp->found; 684 } 685 686 /* Find line range from its line number */ 687 static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 688 { 689 Dwarf_Lines *lines; 690 Dwarf_Line *line; 691 size_t nlines, i; 692 Dwarf_Addr addr; 693 int lineno; 694 int ret; 695 const char *src; 696 Dwarf_Die die_mem; 697 698 line_list__init(&lf->lr->line_list); 699 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines); 700 DIE_IF(ret != 0); 701 702 for (i = 0; i < nlines; i++) { 703 line = dwarf_onesrcline(lines, i); 704 ret = dwarf_lineno(line, &lineno); 705 DIE_IF(ret != 0); 706 if (lf->lno_s > lineno || lf->lno_e < lineno) 707 continue; 708 709 if (sp_die) { 710 /* Address filtering 1: does sp_die include addr? */ 711 ret = dwarf_lineaddr(line, &addr); 712 DIE_IF(ret != 0); 713 if (!dwarf_haspc(sp_die, addr)) 714 continue; 715 716 /* Address filtering 2: No child include addr? */ 717 if (die_find_inlinefunc(sp_die, addr, &die_mem)) 718 continue; 719 } 720 721 /* TODO: Get fileno from line, but how? */ 722 src = dwarf_linesrc(line, NULL, NULL); 723 if (strtailcmp(src, lf->fname) != 0) 724 continue; 725 726 /* Copy real path */ 727 if (!lf->lr->path) 728 lf->lr->path = xstrdup(src); 729 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno); 730 } 731 /* Update status */ 732 if (!list_empty(&lf->lr->line_list)) 733 lf->found = 1; 734 else { 735 free(lf->lr->path); 736 lf->lr->path = NULL; 737 } 738 } 739 740 static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 741 { 742 find_line_range_by_line(in_die, (struct line_finder *)data); 743 return DWARF_CB_ABORT; /* No need to find other instances */ 744 } 745 746 /* Search function from function name */ 747 static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 748 { 749 struct line_finder *lf = (struct line_finder *)data; 750 struct line_range *lr = lf->lr; 751 752 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 753 die_compare_name(sp_die, lr->function) == 0) { 754 lf->fname = dwarf_decl_file(sp_die); 755 dwarf_decl_line(sp_die, &lr->offset); 756 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 757 lf->lno_s = lr->offset + lr->start; 758 if (!lr->end) 759 lf->lno_e = INT_MAX; 760 else 761 lf->lno_e = lr->offset + lr->end; 762 lr->start = lf->lno_s; 763 lr->end = lf->lno_e; 764 if (dwarf_func_inline(sp_die)) 765 dwarf_func_inline_instances(sp_die, 766 line_range_inline_cb, lf); 767 else 768 find_line_range_by_line(sp_die, lf); 769 return 1; 770 } 771 return 0; 772 } 773 774 static void find_line_range_by_func(struct line_finder *lf) 775 { 776 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0); 777 } 778 779 int find_line_range(int fd, struct line_range *lr) 780 { 781 struct line_finder lf = {.lr = lr, .found = 0}; 782 int ret; 783 Dwarf_Off off = 0, noff; 784 size_t cuhl; 785 Dwarf_Die *diep; 786 Dwarf *dbg; 787 788 dbg = dwarf_begin(fd, DWARF_C_READ); 789 if (!dbg) 790 return -ENOENT; 791 792 /* Loop on CUs (Compilation Unit) */ 793 while (!lf.found) { 794 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL); 795 if (ret != 0) 796 break; 797 798 /* Get the DIE(Debugging Information Entry) of this CU */ 799 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); 800 if (!diep) 801 continue; 802 803 /* Check if target file is included. */ 804 if (lr->file) 805 lf.fname = cu_find_realpath(&lf.cu_die, lr->file); 806 else 807 lf.fname = 0; 808 809 if (!lr->file || lf.fname) { 810 if (lr->function) 811 find_line_range_by_func(&lf); 812 else { 813 lf.lno_s = lr->start; 814 if (!lr->end) 815 lf.lno_e = INT_MAX; 816 else 817 lf.lno_e = lr->end; 818 find_line_range_by_line(NULL, &lf); 819 } 820 } 821 off = noff; 822 } 823 pr_debug("path: %lx\n", (unsigned long)lr->path); 824 dwarf_end(dbg); 825 return lf.found; 826 } 827 828