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 "event.h" 36 #include "debug.h" 37 #include "util.h" 38 #include "probe-finder.h" 39 40 41 /* Dwarf_Die Linkage to parent Die */ 42 struct die_link { 43 struct die_link *parent; /* Parent die */ 44 Dwarf_Die die; /* Current die */ 45 }; 46 47 static Dwarf_Debug __dw_debug; 48 static Dwarf_Error __dw_error; 49 50 /* 51 * Generic dwarf analysis helpers 52 */ 53 54 #define X86_32_MAX_REGS 8 55 const char *x86_32_regs_table[X86_32_MAX_REGS] = { 56 "%ax", 57 "%cx", 58 "%dx", 59 "%bx", 60 "$stack", /* Stack address instead of %sp */ 61 "%bp", 62 "%si", 63 "%di", 64 }; 65 66 #define X86_64_MAX_REGS 16 67 const char *x86_64_regs_table[X86_64_MAX_REGS] = { 68 "%ax", 69 "%dx", 70 "%cx", 71 "%bx", 72 "%si", 73 "%di", 74 "%bp", 75 "%sp", 76 "%r8", 77 "%r9", 78 "%r10", 79 "%r11", 80 "%r12", 81 "%r13", 82 "%r14", 83 "%r15", 84 }; 85 86 /* TODO: switching by dwarf address size */ 87 #ifdef __x86_64__ 88 #define ARCH_MAX_REGS X86_64_MAX_REGS 89 #define arch_regs_table x86_64_regs_table 90 #else 91 #define ARCH_MAX_REGS X86_32_MAX_REGS 92 #define arch_regs_table x86_32_regs_table 93 #endif 94 95 /* Return architecture dependent register string (for kprobe-tracer) */ 96 static const char *get_arch_regstr(unsigned int n) 97 { 98 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL; 99 } 100 101 /* 102 * Compare the tail of two strings. 103 * Return 0 if whole of either string is same as another's tail part. 104 */ 105 static int strtailcmp(const char *s1, const char *s2) 106 { 107 int i1 = strlen(s1); 108 int i2 = strlen(s2); 109 while (--i1 >= 0 && --i2 >= 0) { 110 if (s1[i1] != s2[i2]) 111 return s1[i1] - s2[i2]; 112 } 113 return 0; 114 } 115 116 /* Find the fileno of the target file. */ 117 static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname) 118 { 119 Dwarf_Signed cnt, i; 120 Dwarf_Unsigned found = 0; 121 char **srcs; 122 int ret; 123 124 if (!fname) 125 return 0; 126 127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 128 if (ret == DW_DLV_OK) { 129 for (i = 0; i < cnt && !found; i++) { 130 if (strtailcmp(srcs[i], fname) == 0) 131 found = i + 1; 132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 133 } 134 for (; i < cnt; i++) 135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST); 137 } 138 if (found) 139 pr_debug("found fno: %d\n", (int)found); 140 return found; 141 } 142 143 static int cu_get_filename(Dwarf_Die cu_die, Dwarf_Unsigned fno, char **buf) 144 { 145 Dwarf_Signed cnt, i; 146 char **srcs; 147 int ret = 0; 148 149 if (!buf || !fno) 150 return -EINVAL; 151 152 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 153 if (ret == DW_DLV_OK) { 154 if ((Dwarf_Unsigned)cnt > fno - 1) { 155 *buf = strdup(srcs[fno - 1]); 156 ret = 0; 157 pr_debug("found filename: %s\n", *buf); 158 } else 159 ret = -ENOENT; 160 for (i = 0; i < cnt; i++) 161 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 162 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST); 163 } else 164 ret = -EINVAL; 165 return ret; 166 } 167 168 /* Compare diename and tname */ 169 static int die_compare_name(Dwarf_Die dw_die, const char *tname) 170 { 171 char *name; 172 int ret; 173 ret = dwarf_diename(dw_die, &name, &__dw_error); 174 DIE_IF(ret == DW_DLV_ERROR); 175 if (ret == DW_DLV_OK) { 176 ret = strcmp(tname, name); 177 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING); 178 } else 179 ret = -1; 180 return ret; 181 } 182 183 /* Check the address is in the subprogram(function). */ 184 static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, 185 Dwarf_Signed *offs) 186 { 187 Dwarf_Addr lopc, hipc; 188 int ret; 189 190 /* TODO: check ranges */ 191 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error); 192 DIE_IF(ret == DW_DLV_ERROR); 193 if (ret == DW_DLV_NO_ENTRY) 194 return 0; 195 ret = dwarf_highpc(sp_die, &hipc, &__dw_error); 196 DIE_IF(ret != DW_DLV_OK); 197 if (lopc <= addr && addr < hipc) { 198 *offs = addr - lopc; 199 return 1; 200 } else 201 return 0; 202 } 203 204 /* Check the die is inlined function */ 205 static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die) 206 { 207 /* TODO: check strictly */ 208 Dwarf_Bool inl; 209 int ret; 210 211 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error); 212 DIE_IF(ret == DW_DLV_ERROR); 213 return inl; 214 } 215 216 /* Get the offset of abstruct_origin */ 217 static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die) 218 { 219 Dwarf_Attribute attr; 220 Dwarf_Off cu_offs; 221 int ret; 222 223 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error); 224 DIE_IF(ret != DW_DLV_OK); 225 ret = dwarf_formref(attr, &cu_offs, &__dw_error); 226 DIE_IF(ret != DW_DLV_OK); 227 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 228 return cu_offs; 229 } 230 231 /* Get entry pc(or low pc, 1st entry of ranges) of the die */ 232 static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die) 233 { 234 Dwarf_Attribute attr; 235 Dwarf_Addr addr; 236 Dwarf_Off offs; 237 Dwarf_Ranges *ranges; 238 Dwarf_Signed cnt; 239 int ret; 240 241 /* Try to get entry pc */ 242 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error); 243 DIE_IF(ret == DW_DLV_ERROR); 244 if (ret == DW_DLV_OK) { 245 ret = dwarf_formaddr(attr, &addr, &__dw_error); 246 DIE_IF(ret != DW_DLV_OK); 247 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 248 return addr; 249 } 250 251 /* Try to get low pc */ 252 ret = dwarf_lowpc(dw_die, &addr, &__dw_error); 253 DIE_IF(ret == DW_DLV_ERROR); 254 if (ret == DW_DLV_OK) 255 return addr; 256 257 /* Try to get ranges */ 258 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error); 259 DIE_IF(ret != DW_DLV_OK); 260 ret = dwarf_formref(attr, &offs, &__dw_error); 261 DIE_IF(ret != DW_DLV_OK); 262 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL, 263 &__dw_error); 264 DIE_IF(ret != DW_DLV_OK); 265 addr = ranges[0].dwr_addr1; 266 dwarf_ranges_dealloc(__dw_debug, ranges, cnt); 267 return addr; 268 } 269 270 /* 271 * Search a Die from Die tree. 272 * Note: cur_link->die should be deallocated in this function. 273 */ 274 static int __search_die_tree(struct die_link *cur_link, 275 int (*die_cb)(struct die_link *, void *), 276 void *data) 277 { 278 Dwarf_Die new_die; 279 struct die_link new_link; 280 int ret; 281 282 if (!die_cb) 283 return 0; 284 285 /* Check current die */ 286 while (!(ret = die_cb(cur_link, data))) { 287 /* Check child die */ 288 ret = dwarf_child(cur_link->die, &new_die, &__dw_error); 289 DIE_IF(ret == DW_DLV_ERROR); 290 if (ret == DW_DLV_OK) { 291 new_link.parent = cur_link; 292 new_link.die = new_die; 293 ret = __search_die_tree(&new_link, die_cb, data); 294 if (ret) 295 break; 296 } 297 298 /* Move to next sibling */ 299 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die, 300 &__dw_error); 301 DIE_IF(ret == DW_DLV_ERROR); 302 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE); 303 cur_link->die = new_die; 304 if (ret == DW_DLV_NO_ENTRY) 305 return 0; 306 } 307 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE); 308 return ret; 309 } 310 311 /* Search a die in its children's die tree */ 312 static int search_die_from_children(Dwarf_Die parent_die, 313 int (*die_cb)(struct die_link *, void *), 314 void *data) 315 { 316 struct die_link new_link; 317 int ret; 318 319 new_link.parent = NULL; 320 ret = dwarf_child(parent_die, &new_link.die, &__dw_error); 321 DIE_IF(ret == DW_DLV_ERROR); 322 if (ret == DW_DLV_OK) 323 return __search_die_tree(&new_link, die_cb, data); 324 else 325 return 0; 326 } 327 328 /* Find a locdesc corresponding to the address */ 329 static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc, 330 Dwarf_Addr addr) 331 { 332 Dwarf_Signed lcnt; 333 Dwarf_Locdesc **llbuf; 334 int ret, i; 335 336 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error); 337 DIE_IF(ret != DW_DLV_OK); 338 ret = DW_DLV_NO_ENTRY; 339 for (i = 0; i < lcnt; ++i) { 340 if (llbuf[i]->ld_lopc <= addr && 341 llbuf[i]->ld_hipc > addr) { 342 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc)); 343 desc->ld_s = 344 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents); 345 DIE_IF(desc->ld_s == NULL); 346 memcpy(desc->ld_s, llbuf[i]->ld_s, 347 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents); 348 ret = DW_DLV_OK; 349 break; 350 } 351 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK); 352 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC); 353 } 354 /* Releasing loop */ 355 for (; i < lcnt; ++i) { 356 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK); 357 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC); 358 } 359 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST); 360 return ret; 361 } 362 363 /* Get decl_file attribute value (file number) */ 364 static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die) 365 { 366 Dwarf_Attribute attr; 367 Dwarf_Unsigned fno; 368 int ret; 369 370 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error); 371 DIE_IF(ret != DW_DLV_OK); 372 dwarf_formudata(attr, &fno, &__dw_error); 373 DIE_IF(ret != DW_DLV_OK); 374 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 375 return fno; 376 } 377 378 /* Get decl_line attribute value (line number) */ 379 static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die) 380 { 381 Dwarf_Attribute attr; 382 Dwarf_Unsigned lno; 383 int ret; 384 385 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error); 386 DIE_IF(ret != DW_DLV_OK); 387 dwarf_formudata(attr, &lno, &__dw_error); 388 DIE_IF(ret != DW_DLV_OK); 389 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 390 return lno; 391 } 392 393 /* 394 * Probe finder related functions 395 */ 396 397 /* Show a location */ 398 static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) 399 { 400 Dwarf_Small op; 401 Dwarf_Unsigned regn; 402 Dwarf_Signed offs; 403 int deref = 0, ret; 404 const char *regs; 405 406 op = loc->lr_atom; 407 408 /* If this is based on frame buffer, set the offset */ 409 if (op == DW_OP_fbreg) { 410 deref = 1; 411 offs = (Dwarf_Signed)loc->lr_number; 412 op = pf->fbloc.ld_s[0].lr_atom; 413 loc = &pf->fbloc.ld_s[0]; 414 } else 415 offs = 0; 416 417 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { 418 regn = op - DW_OP_breg0; 419 offs += (Dwarf_Signed)loc->lr_number; 420 deref = 1; 421 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { 422 regn = op - DW_OP_reg0; 423 } else if (op == DW_OP_bregx) { 424 regn = loc->lr_number; 425 offs += (Dwarf_Signed)loc->lr_number2; 426 deref = 1; 427 } else if (op == DW_OP_regx) { 428 regn = loc->lr_number; 429 } else 430 die("Dwarf_OP %d is not supported.", op); 431 432 regs = get_arch_regstr(regn); 433 if (!regs) 434 die("%lld exceeds max register number.", regn); 435 436 if (deref) 437 ret = snprintf(pf->buf, pf->len, 438 " %s=%+lld(%s)", pf->var, offs, regs); 439 else 440 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 441 DIE_IF(ret < 0); 442 DIE_IF(ret >= pf->len); 443 } 444 445 /* Show a variables in kprobe event format */ 446 static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) 447 { 448 Dwarf_Attribute attr; 449 Dwarf_Locdesc ld; 450 int ret; 451 452 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error); 453 if (ret != DW_DLV_OK) 454 goto error; 455 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base)); 456 if (ret != DW_DLV_OK) 457 goto error; 458 /* TODO? */ 459 DIE_IF(ld.ld_cents != 1); 460 show_location(&ld.ld_s[0], pf); 461 free(ld.ld_s); 462 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 463 return ; 464 error: 465 die("Failed to find the location of %s at this address.\n" 466 " Perhaps, it has been optimized out.", pf->var); 467 } 468 469 static int variable_callback(struct die_link *dlink, void *data) 470 { 471 struct probe_finder *pf = (struct probe_finder *)data; 472 Dwarf_Half tag; 473 int ret; 474 475 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 476 DIE_IF(ret == DW_DLV_ERROR); 477 if ((tag == DW_TAG_formal_parameter || 478 tag == DW_TAG_variable) && 479 (die_compare_name(dlink->die, pf->var) == 0)) { 480 show_variable(dlink->die, pf); 481 return 1; 482 } 483 /* TODO: Support struct members and arrays */ 484 return 0; 485 } 486 487 /* Find a variable in a subprogram die */ 488 static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) 489 { 490 int ret; 491 492 if (!is_c_varname(pf->var)) { 493 /* Output raw parameters */ 494 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 495 DIE_IF(ret < 0); 496 DIE_IF(ret >= pf->len); 497 return ; 498 } 499 500 pr_debug("Searching '%s' variable in context.\n", pf->var); 501 /* Search child die for local variables and parameters. */ 502 ret = search_die_from_children(sp_die, variable_callback, pf); 503 if (!ret) 504 die("Failed to find '%s' in this function.", pf->var); 505 } 506 507 /* Get a frame base on the address */ 508 static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf) 509 { 510 Dwarf_Attribute attr; 511 int ret; 512 513 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error); 514 DIE_IF(ret != DW_DLV_OK); 515 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base)); 516 DIE_IF(ret != DW_DLV_OK); 517 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 518 } 519 520 static void free_current_frame_base(struct probe_finder *pf) 521 { 522 free(pf->fbloc.ld_s); 523 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc)); 524 } 525 526 /* Show a probe point to output buffer */ 527 static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs, 528 struct probe_finder *pf) 529 { 530 struct probe_point *pp = pf->pp; 531 char *name; 532 char tmp[MAX_PROBE_BUFFER]; 533 int ret, i, len; 534 535 /* Output name of probe point */ 536 ret = dwarf_diename(sp_die, &name, &__dw_error); 537 DIE_IF(ret == DW_DLV_ERROR); 538 if (ret == DW_DLV_OK) { 539 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, 540 (unsigned int)offs); 541 /* Copy the function name if possible */ 542 if (!pp->function) { 543 pp->function = strdup(name); 544 pp->offset = offs; 545 } 546 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING); 547 } else { 548 /* This function has no name. */ 549 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr); 550 if (!pp->function) { 551 /* TODO: Use _stext */ 552 pp->function = strdup(""); 553 pp->offset = (int)pf->addr; 554 } 555 } 556 DIE_IF(ret < 0); 557 DIE_IF(ret >= MAX_PROBE_BUFFER); 558 len = ret; 559 pr_debug("Probe point found: %s\n", tmp); 560 561 /* Find each argument */ 562 get_current_frame_base(sp_die, pf); 563 for (i = 0; i < pp->nr_args; i++) { 564 pf->var = pp->args[i]; 565 pf->buf = &tmp[len]; 566 pf->len = MAX_PROBE_BUFFER - len; 567 find_variable(sp_die, pf); 568 len += strlen(pf->buf); 569 } 570 free_current_frame_base(pf); 571 572 pp->probes[pp->found] = strdup(tmp); 573 pp->found++; 574 } 575 576 static int probeaddr_callback(struct die_link *dlink, void *data) 577 { 578 struct probe_finder *pf = (struct probe_finder *)data; 579 Dwarf_Half tag; 580 Dwarf_Signed offs; 581 int ret; 582 583 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 584 DIE_IF(ret == DW_DLV_ERROR); 585 /* Check the address is in this subprogram */ 586 if (tag == DW_TAG_subprogram && 587 die_within_subprogram(dlink->die, pf->addr, &offs)) { 588 show_probepoint(dlink->die, offs, pf); 589 return 1; 590 } 591 return 0; 592 } 593 594 /* Find probe point from its line number */ 595 static void find_probe_point_by_line(struct probe_finder *pf) 596 { 597 Dwarf_Signed cnt, i, clm; 598 Dwarf_Line *lines; 599 Dwarf_Unsigned lineno = 0; 600 Dwarf_Addr addr; 601 Dwarf_Unsigned fno; 602 int ret; 603 604 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error); 605 DIE_IF(ret != DW_DLV_OK); 606 607 for (i = 0; i < cnt; i++) { 608 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 609 DIE_IF(ret != DW_DLV_OK); 610 if (fno != pf->fno) 611 continue; 612 613 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 614 DIE_IF(ret != DW_DLV_OK); 615 if (lineno != pf->lno) 616 continue; 617 618 ret = dwarf_lineoff(lines[i], &clm, &__dw_error); 619 DIE_IF(ret != DW_DLV_OK); 620 621 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 622 DIE_IF(ret != DW_DLV_OK); 623 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n", 624 (int)i, (unsigned)lineno, (int)clm, addr); 625 pf->addr = addr; 626 /* Search a real subprogram including this line, */ 627 ret = search_die_from_children(pf->cu_die, 628 probeaddr_callback, pf); 629 if (ret == 0) 630 die("Probe point is not found in subprograms."); 631 /* Continuing, because target line might be inlined. */ 632 } 633 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 634 } 635 636 /* Search function from function name */ 637 static int probefunc_callback(struct die_link *dlink, void *data) 638 { 639 struct probe_finder *pf = (struct probe_finder *)data; 640 struct probe_point *pp = pf->pp; 641 struct die_link *lk; 642 Dwarf_Signed offs; 643 Dwarf_Half tag; 644 int ret; 645 646 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 647 DIE_IF(ret == DW_DLV_ERROR); 648 if (tag == DW_TAG_subprogram) { 649 if (die_compare_name(dlink->die, pp->function) == 0) { 650 if (pp->line) { /* Function relative line */ 651 pf->fno = die_get_decl_file(dlink->die); 652 pf->lno = die_get_decl_line(dlink->die) 653 + pp->line; 654 find_probe_point_by_line(pf); 655 return 1; 656 } 657 if (die_inlined_subprogram(dlink->die)) { 658 /* Inlined function, save it. */ 659 ret = dwarf_die_CU_offset(dlink->die, 660 &pf->inl_offs, 661 &__dw_error); 662 DIE_IF(ret != DW_DLV_OK); 663 pr_debug("inline definition offset %lld\n", 664 pf->inl_offs); 665 return 0; /* Continue to search */ 666 } 667 /* Get probe address */ 668 pf->addr = die_get_entrypc(dlink->die); 669 pf->addr += pp->offset; 670 /* TODO: Check the address in this function */ 671 show_probepoint(dlink->die, pp->offset, pf); 672 return 1; /* Exit; no same symbol in this CU. */ 673 } 674 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) { 675 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) { 676 /* Get probe address */ 677 pf->addr = die_get_entrypc(dlink->die); 678 pf->addr += pp->offset; 679 pr_debug("found inline addr: 0x%llx\n", pf->addr); 680 /* Inlined function. Get a real subprogram */ 681 for (lk = dlink->parent; lk != NULL; lk = lk->parent) { 682 tag = 0; 683 dwarf_tag(lk->die, &tag, &__dw_error); 684 DIE_IF(ret == DW_DLV_ERROR); 685 if (tag == DW_TAG_subprogram && 686 !die_inlined_subprogram(lk->die)) 687 goto found; 688 } 689 die("Failed to find real subprogram."); 690 found: 691 /* Get offset from subprogram */ 692 ret = die_within_subprogram(lk->die, pf->addr, &offs); 693 DIE_IF(!ret); 694 show_probepoint(lk->die, offs, pf); 695 /* Continue to search */ 696 } 697 } 698 return 0; 699 } 700 701 static void find_probe_point_by_func(struct probe_finder *pf) 702 { 703 search_die_from_children(pf->cu_die, probefunc_callback, pf); 704 } 705 706 /* Find a probe point */ 707 int find_probepoint(int fd, struct probe_point *pp) 708 { 709 Dwarf_Half addr_size = 0; 710 Dwarf_Unsigned next_cuh = 0; 711 int cu_number = 0, ret; 712 struct probe_finder pf = {.pp = pp}; 713 714 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 715 if (ret != DW_DLV_OK) 716 return -ENOENT; 717 718 pp->found = 0; 719 while (++cu_number) { 720 /* Search CU (Compilation Unit) */ 721 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 722 &addr_size, &next_cuh, &__dw_error); 723 DIE_IF(ret == DW_DLV_ERROR); 724 if (ret == DW_DLV_NO_ENTRY) 725 break; 726 727 /* Get the DIE(Debugging Information Entry) of this CU */ 728 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error); 729 DIE_IF(ret != DW_DLV_OK); 730 731 /* Check if target file is included. */ 732 if (pp->file) 733 pf.fno = cu_find_fileno(pf.cu_die, pp->file); 734 735 if (!pp->file || pf.fno) { 736 /* Save CU base address (for frame_base) */ 737 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error); 738 DIE_IF(ret == DW_DLV_ERROR); 739 if (ret == DW_DLV_NO_ENTRY) 740 pf.cu_base = 0; 741 if (pp->function) 742 find_probe_point_by_func(&pf); 743 else { 744 pf.lno = pp->line; 745 find_probe_point_by_line(&pf); 746 } 747 } 748 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 749 } 750 ret = dwarf_finish(__dw_debug, &__dw_error); 751 DIE_IF(ret != DW_DLV_OK); 752 753 return pp->found; 754 } 755 756 757 static void line_range_add_line(struct line_range *lr, unsigned int line) 758 { 759 struct line_node *ln; 760 struct list_head *p; 761 762 /* Reverse search, because new line will be the last one */ 763 list_for_each_entry_reverse(ln, &lr->line_list, list) { 764 if (ln->line < line) { 765 p = &ln->list; 766 goto found; 767 } else if (ln->line == line) /* Already exist */ 768 return ; 769 } 770 /* List is empty, or the smallest entry */ 771 p = &lr->line_list; 772 found: 773 pr_debug("Debug: add a line %u\n", line); 774 ln = zalloc(sizeof(struct line_node)); 775 DIE_IF(ln == NULL); 776 ln->line = line; 777 INIT_LIST_HEAD(&ln->list); 778 list_add(&ln->list, p); 779 } 780 781 /* Find line range from its line number */ 782 static void find_line_range_by_line(struct line_finder *lf) 783 { 784 Dwarf_Signed cnt, i; 785 Dwarf_Line *lines; 786 Dwarf_Unsigned lineno = 0; 787 Dwarf_Unsigned fno; 788 Dwarf_Addr addr; 789 int ret; 790 791 ret = dwarf_srclines(lf->cu_die, &lines, &cnt, &__dw_error); 792 DIE_IF(ret != DW_DLV_OK); 793 794 for (i = 0; i < cnt; i++) { 795 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 796 DIE_IF(ret != DW_DLV_OK); 797 if (fno != lf->fno) 798 continue; 799 800 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 801 DIE_IF(ret != DW_DLV_OK); 802 if (lf->lno_s > lineno || lf->lno_e < lineno) 803 continue; 804 805 /* Filter line in the function address range */ 806 if (lf->addr_s && lf->addr_e) { 807 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 808 DIE_IF(ret != DW_DLV_OK); 809 if (lf->addr_s > addr || lf->addr_e <= addr) 810 continue; 811 } 812 line_range_add_line(lf->lr, (unsigned int)lineno); 813 } 814 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 815 if (!list_empty(&lf->lr->line_list)) 816 lf->found = 1; 817 } 818 819 /* Search function from function name */ 820 static int linefunc_callback(struct die_link *dlink, void *data) 821 { 822 struct line_finder *lf = (struct line_finder *)data; 823 struct line_range *lr = lf->lr; 824 Dwarf_Half tag; 825 int ret; 826 827 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 828 DIE_IF(ret == DW_DLV_ERROR); 829 if (tag == DW_TAG_subprogram && 830 die_compare_name(dlink->die, lr->function) == 0) { 831 /* Get the address range of this function */ 832 ret = dwarf_highpc(dlink->die, &lf->addr_e, &__dw_error); 833 if (ret == DW_DLV_OK) 834 ret = dwarf_lowpc(dlink->die, &lf->addr_s, &__dw_error); 835 DIE_IF(ret == DW_DLV_ERROR); 836 if (ret == DW_DLV_NO_ENTRY) { 837 lf->addr_s = 0; 838 lf->addr_e = 0; 839 } 840 841 lf->fno = die_get_decl_file(dlink->die); 842 lr->offset = die_get_decl_line(dlink->die);; 843 lf->lno_s = lr->offset + lr->start; 844 if (!lr->end) 845 lf->lno_e = (Dwarf_Unsigned)-1; 846 else 847 lf->lno_e = lr->offset + lr->end; 848 lr->start = lf->lno_s; 849 lr->end = lf->lno_e; 850 find_line_range_by_line(lf); 851 /* If we find a target function, this should be end. */ 852 lf->found = 1; 853 return 1; 854 } 855 return 0; 856 } 857 858 static void find_line_range_by_func(struct line_finder *lf) 859 { 860 search_die_from_children(lf->cu_die, linefunc_callback, lf); 861 } 862 863 int find_line_range(int fd, struct line_range *lr) 864 { 865 Dwarf_Half addr_size = 0; 866 Dwarf_Unsigned next_cuh = 0; 867 int ret; 868 struct line_finder lf = {.lr = lr}; 869 870 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 871 if (ret != DW_DLV_OK) 872 return -ENOENT; 873 874 while (!lf.found) { 875 /* Search CU (Compilation Unit) */ 876 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 877 &addr_size, &next_cuh, &__dw_error); 878 DIE_IF(ret == DW_DLV_ERROR); 879 if (ret == DW_DLV_NO_ENTRY) 880 break; 881 882 /* Get the DIE(Debugging Information Entry) of this CU */ 883 ret = dwarf_siblingof(__dw_debug, 0, &lf.cu_die, &__dw_error); 884 DIE_IF(ret != DW_DLV_OK); 885 886 /* Check if target file is included. */ 887 if (lr->file) 888 lf.fno = cu_find_fileno(lf.cu_die, lr->file); 889 890 if (!lr->file || lf.fno) { 891 if (lr->function) 892 find_line_range_by_func(&lf); 893 else { 894 lf.lno_s = lr->start; 895 if (!lr->end) 896 lf.lno_e = (Dwarf_Unsigned)-1; 897 else 898 lf.lno_e = lr->end; 899 find_line_range_by_line(&lf); 900 } 901 /* Get the real file path */ 902 if (lf.found) 903 cu_get_filename(lf.cu_die, lf.fno, &lr->path); 904 } 905 dwarf_dealloc(__dw_debug, lf.cu_die, DW_DLA_DIE); 906 } 907 ret = dwarf_finish(__dw_debug, &__dw_error); 908 DIE_IF(ret != DW_DLV_OK); 909 return lf.found; 910 } 911 912