blob: 338fdb9e093d096e2d9ac4be44f66b329a40a241 [file] [log] [blame]
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001/*
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>
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -040034
35#include "util.h"
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040036#include "probe-finder.h"
37
38
39/* Dwarf_Die Linkage to parent Die */
40struct die_link {
41 struct die_link *parent; /* Parent die */
42 Dwarf_Die die; /* Current die */
43};
44
45static Dwarf_Debug __dw_debug;
46static Dwarf_Error __dw_error;
47
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040048/*
49 * Generic dwarf analysis helpers
50 */
51
52#define X86_32_MAX_REGS 8
53const char *x86_32_regs_table[X86_32_MAX_REGS] = {
54 "%ax",
55 "%cx",
56 "%dx",
57 "%bx",
58 "$stack", /* Stack address instead of %sp */
59 "%bp",
60 "%si",
61 "%di",
62};
63
64#define X86_64_MAX_REGS 16
65const char *x86_64_regs_table[X86_64_MAX_REGS] = {
66 "%ax",
67 "%dx",
68 "%cx",
69 "%bx",
70 "%si",
71 "%di",
72 "%bp",
73 "%sp",
74 "%r8",
75 "%r9",
76 "%r10",
77 "%r11",
78 "%r12",
79 "%r13",
80 "%r14",
81 "%r15",
82};
83
84/* TODO: switching by dwarf address size */
85#ifdef __x86_64__
86#define ARCH_MAX_REGS X86_64_MAX_REGS
87#define arch_regs_table x86_64_regs_table
88#else
89#define ARCH_MAX_REGS X86_32_MAX_REGS
90#define arch_regs_table x86_32_regs_table
91#endif
92
93/* Return architecture dependent register string (for kprobe-tracer) */
94static const char *get_arch_regstr(unsigned int n)
95{
96 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
97}
98
99/*
100 * Compare the tail of two strings.
101 * Return 0 if whole of either string is same as another's tail part.
102 */
103static int strtailcmp(const char *s1, const char *s2)
104{
105 int i1 = strlen(s1);
106 int i2 = strlen(s2);
107 while (--i1 > 0 && --i2 > 0) {
108 if (s1[i1] != s2[i2])
109 return s1[i1] - s2[i2];
110 }
111 return 0;
112}
113
114/* Find the fileno of the target file. */
115static Dwarf_Unsigned die_get_fileno(Dwarf_Die cu_die, const char *fname)
116{
117 Dwarf_Signed cnt, i;
118 Dwarf_Unsigned found = 0;
119 char **srcs;
120 int ret;
121
122 if (!fname)
123 return 0;
124
125 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
126 if (ret == DW_DLV_OK) {
127 for (i = 0; i < cnt && !found; i++) {
128 if (strtailcmp(srcs[i], fname) == 0)
129 found = i + 1;
130 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
131 }
132 for (; i < cnt; i++)
133 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
134 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
135 }
136 if (found)
137 debug("found fno: %d\n", (int)found);
138 return found;
139}
140
141/* Compare diename and tname */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400142static int die_compare_name(Dwarf_Die dw_die, const char *tname)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400143{
144 char *name;
145 int ret;
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400146 ret = dwarf_diename(dw_die, &name, &__dw_error);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400147 ERR_IF(ret == DW_DLV_ERROR);
148 if (ret == DW_DLV_OK) {
149 ret = strcmp(tname, name);
150 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
151 } else
152 ret = -1;
153 return ret;
154}
155
156/* Check the address is in the subprogram(function). */
157static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr,
158 Dwarf_Signed *offs)
159{
160 Dwarf_Addr lopc, hipc;
161 int ret;
162
163 /* TODO: check ranges */
164 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
165 ERR_IF(ret == DW_DLV_ERROR);
166 if (ret == DW_DLV_NO_ENTRY)
167 return 0;
168 ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
169 ERR_IF(ret != DW_DLV_OK);
170 if (lopc <= addr && addr < hipc) {
171 *offs = addr - lopc;
172 return 1;
173 } else
174 return 0;
175}
176
177/* Check the die is inlined function */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400178static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400179{
180 /* TODO: check strictly */
181 Dwarf_Bool inl;
182 int ret;
183
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400184 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400185 ERR_IF(ret == DW_DLV_ERROR);
186 return inl;
187}
188
189/* Get the offset of abstruct_origin */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400190static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400191{
192 Dwarf_Attribute attr;
193 Dwarf_Off cu_offs;
194 int ret;
195
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400196 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400197 ERR_IF(ret != DW_DLV_OK);
198 ret = dwarf_formref(attr, &cu_offs, &__dw_error);
199 ERR_IF(ret != DW_DLV_OK);
200 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
201 return cu_offs;
202}
203
204/* Get entry pc(or low pc, 1st entry of ranges) of the die */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400205static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400206{
207 Dwarf_Attribute attr;
208 Dwarf_Addr addr;
209 Dwarf_Off offs;
210 Dwarf_Ranges *ranges;
211 Dwarf_Signed cnt;
212 int ret;
213
214 /* Try to get entry pc */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400215 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400216 ERR_IF(ret == DW_DLV_ERROR);
217 if (ret == DW_DLV_OK) {
218 ret = dwarf_formaddr(attr, &addr, &__dw_error);
219 ERR_IF(ret != DW_DLV_OK);
220 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
221 return addr;
222 }
223
224 /* Try to get low pc */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400225 ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400226 ERR_IF(ret == DW_DLV_ERROR);
227 if (ret == DW_DLV_OK)
228 return addr;
229
230 /* Try to get ranges */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400231 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400232 ERR_IF(ret != DW_DLV_OK);
233 ret = dwarf_formref(attr, &offs, &__dw_error);
234 ERR_IF(ret != DW_DLV_OK);
235 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
236 &__dw_error);
237 ERR_IF(ret != DW_DLV_OK);
238 addr = ranges[0].dwr_addr1;
239 dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
240 return addr;
241}
242
243/*
244 * Search a Die from Die tree.
245 * Note: cur_link->die should be deallocated in this function.
246 */
247static int __search_die_tree(struct die_link *cur_link,
248 int (*die_cb)(struct die_link *, void *),
249 void *data)
250{
251 Dwarf_Die new_die;
252 struct die_link new_link;
253 int ret;
254
255 if (!die_cb)
256 return 0;
257
258 /* Check current die */
259 while (!(ret = die_cb(cur_link, data))) {
260 /* Check child die */
261 ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
262 ERR_IF(ret == DW_DLV_ERROR);
263 if (ret == DW_DLV_OK) {
264 new_link.parent = cur_link;
265 new_link.die = new_die;
266 ret = __search_die_tree(&new_link, die_cb, data);
267 if (ret)
268 break;
269 }
270
271 /* Move to next sibling */
272 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
273 &__dw_error);
274 ERR_IF(ret == DW_DLV_ERROR);
275 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
276 cur_link->die = new_die;
277 if (ret == DW_DLV_NO_ENTRY)
278 return 0;
279 }
280 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
281 return ret;
282}
283
284/* Search a die in its children's die tree */
285static int search_die_from_children(Dwarf_Die parent_die,
286 int (*die_cb)(struct die_link *, void *),
287 void *data)
288{
289 struct die_link new_link;
290 int ret;
291
292 new_link.parent = NULL;
293 ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
294 ERR_IF(ret == DW_DLV_ERROR);
295 if (ret == DW_DLV_OK)
296 return __search_die_tree(&new_link, die_cb, data);
297 else
298 return 0;
299}
300
301/* Find a locdesc corresponding to the address */
302static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
303 Dwarf_Addr addr)
304{
305 Dwarf_Signed lcnt;
306 Dwarf_Locdesc **llbuf;
307 int ret, i;
308
309 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
310 ERR_IF(ret != DW_DLV_OK);
311 ret = DW_DLV_NO_ENTRY;
312 for (i = 0; i < lcnt; ++i) {
313 if (llbuf[i]->ld_lopc <= addr &&
314 llbuf[i]->ld_hipc > addr) {
315 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
316 desc->ld_s =
317 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
318 ERR_IF(desc->ld_s == NULL);
319 memcpy(desc->ld_s, llbuf[i]->ld_s,
320 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
321 ret = DW_DLV_OK;
322 break;
323 }
324 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
325 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
326 }
327 /* Releasing loop */
328 for (; i < lcnt; ++i) {
329 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
330 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
331 }
332 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
333 return ret;
334}
335
336/*
337 * Probe finder related functions
338 */
339
340/* Show a location */
341static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
342{
343 Dwarf_Small op;
344 Dwarf_Unsigned regn;
345 Dwarf_Signed offs;
346 int deref = 0, ret;
347 const char *regs;
348
349 op = loc->lr_atom;
350
351 /* If this is based on frame buffer, set the offset */
352 if (op == DW_OP_fbreg) {
353 deref = 1;
354 offs = (Dwarf_Signed)loc->lr_number;
355 op = pf->fbloc.ld_s[0].lr_atom;
356 loc = &pf->fbloc.ld_s[0];
357 } else
358 offs = 0;
359
360 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
361 regn = op - DW_OP_breg0;
362 offs += (Dwarf_Signed)loc->lr_number;
363 deref = 1;
364 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
365 regn = op - DW_OP_reg0;
366 } else if (op == DW_OP_bregx) {
367 regn = loc->lr_number;
368 offs += (Dwarf_Signed)loc->lr_number2;
369 deref = 1;
370 } else if (op == DW_OP_regx) {
371 regn = loc->lr_number;
372 } else
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400373 die("Dwarf_OP %d is not supported.\n", op);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400374
375 regs = get_arch_regstr(regn);
376 if (!regs)
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400377 die("%lld exceeds max register number.\n", regn);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400378
379 if (deref)
380 ret = snprintf(pf->buf, pf->len,
381 " %s=%+lld(%s)", pf->var, offs, regs);
382 else
383 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
384 ERR_IF(ret < 0);
385 ERR_IF(ret >= pf->len);
386}
387
388/* Show a variables in kprobe event format */
389static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
390{
391 Dwarf_Attribute attr;
392 Dwarf_Locdesc ld;
393 int ret;
394
395 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error);
396 if (ret != DW_DLV_OK)
397 goto error;
398 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base));
399 if (ret != DW_DLV_OK)
400 goto error;
401 /* TODO? */
402 ERR_IF(ld.ld_cents != 1);
403 show_location(&ld.ld_s[0], pf);
404 free(ld.ld_s);
405 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
406 return ;
407error:
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400408 die("Failed to find the location of %s at this address.\n"
409 " Perhaps, it has been optimized out.\n", pf->var);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400410}
411
412static int variable_callback(struct die_link *dlink, void *data)
413{
414 struct probe_finder *pf = (struct probe_finder *)data;
415 Dwarf_Half tag;
416 int ret;
417
418 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
419 ERR_IF(ret == DW_DLV_ERROR);
420 if ((tag == DW_TAG_formal_parameter ||
421 tag == DW_TAG_variable) &&
422 (die_compare_name(dlink->die, pf->var) == 0)) {
423 show_variable(dlink->die, pf);
424 return 1;
425 }
426 /* TODO: Support struct members and arrays */
427 return 0;
428}
429
430/* Find a variable in a subprogram die */
431static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
432{
433 int ret;
434
435 if (!is_c_varname(pf->var)) {
436 /* Output raw parameters */
437 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
438 ERR_IF(ret < 0);
439 ERR_IF(ret >= pf->len);
440 return ;
441 }
442
443 debug("Searching '%s' variable in context.\n", pf->var);
444 /* Search child die for local variables and parameters. */
445 ret = search_die_from_children(sp_die, variable_callback, pf);
446 if (!ret)
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400447 die("Failed to find '%s' in this function.\n", pf->var);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400448}
449
450/* Get a frame base on the address */
451static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
452{
453 Dwarf_Attribute attr;
454 int ret;
455
456 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
457 ERR_IF(ret != DW_DLV_OK);
458 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
459 ERR_IF(ret != DW_DLV_OK);
460 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
461}
462
463static void free_current_frame_base(struct probe_finder *pf)
464{
465 free(pf->fbloc.ld_s);
466 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
467}
468
469/* Show a probe point to output buffer */
470static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
471 struct probe_finder *pf)
472{
473 struct probe_point *pp = pf->pp;
474 char *name;
475 char tmp[MAX_PROBE_BUFFER];
476 int ret, i, len;
477
478 /* Output name of probe point */
479 ret = dwarf_diename(sp_die, &name, &__dw_error);
480 ERR_IF(ret == DW_DLV_ERROR);
481 if (ret == DW_DLV_OK) {
482 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
483 (unsigned int)offs);
484 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
485 } else {
486 /* This function has no name. */
487 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr);
488 }
489 ERR_IF(ret < 0);
490 ERR_IF(ret >= MAX_PROBE_BUFFER);
491 len = ret;
492
493 /* Find each argument */
494 get_current_frame_base(sp_die, pf);
495 for (i = 0; i < pp->nr_args; i++) {
496 pf->var = pp->args[i];
497 pf->buf = &tmp[len];
498 pf->len = MAX_PROBE_BUFFER - len;
499 find_variable(sp_die, pf);
500 len += strlen(pf->buf);
501 }
502 free_current_frame_base(pf);
503
504 pp->probes[pp->found] = strdup(tmp);
505 pp->found++;
506}
507
508static int probeaddr_callback(struct die_link *dlink, void *data)
509{
510 struct probe_finder *pf = (struct probe_finder *)data;
511 Dwarf_Half tag;
512 Dwarf_Signed offs;
513 int ret;
514
515 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
516 ERR_IF(ret == DW_DLV_ERROR);
517 /* Check the address is in this subprogram */
518 if (tag == DW_TAG_subprogram &&
519 die_within_subprogram(dlink->die, pf->addr, &offs)) {
520 show_probepoint(dlink->die, offs, pf);
521 return 1;
522 }
523 return 0;
524}
525
526/* Find probe point from its line number */
527static void find_by_line(Dwarf_Die cu_die, struct probe_finder *pf)
528{
529 struct probe_point *pp = pf->pp;
530 Dwarf_Signed cnt, i;
531 Dwarf_Line *lines;
532 Dwarf_Unsigned lineno = 0;
533 Dwarf_Addr addr;
534 Dwarf_Unsigned fno;
535 int ret;
536
537 ret = dwarf_srclines(cu_die, &lines, &cnt, &__dw_error);
538 ERR_IF(ret != DW_DLV_OK);
539
540 for (i = 0; i < cnt; i++) {
541 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
542 ERR_IF(ret != DW_DLV_OK);
543 if (fno != pf->fno)
544 continue;
545
546 ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
547 ERR_IF(ret != DW_DLV_OK);
548 if (lineno != (Dwarf_Unsigned)pp->line)
549 continue;
550
551 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
552 ERR_IF(ret != DW_DLV_OK);
553 debug("Probe point found: 0x%llx\n", addr);
554 pf->addr = addr;
555 /* Search a real subprogram including this line, */
556 ret = search_die_from_children(cu_die, probeaddr_callback, pf);
557 if (ret == 0)
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400558 die("Probe point is not found in subprograms.\n");
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400559 /* Continuing, because target line might be inlined. */
560 }
561 dwarf_srclines_dealloc(__dw_debug, lines, cnt);
562}
563
564/* Search function from function name */
565static int probefunc_callback(struct die_link *dlink, void *data)
566{
567 struct probe_finder *pf = (struct probe_finder *)data;
568 struct probe_point *pp = pf->pp;
569 struct die_link *lk;
570 Dwarf_Signed offs;
571 Dwarf_Half tag;
572 int ret;
573
574 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
575 ERR_IF(ret == DW_DLV_ERROR);
576 if (tag == DW_TAG_subprogram) {
577 if (die_compare_name(dlink->die, pp->function) == 0) {
578 if (die_inlined_subprogram(dlink->die)) {
579 /* Inlined function, save it. */
580 ret = dwarf_die_CU_offset(dlink->die,
581 &pf->inl_offs,
582 &__dw_error);
583 ERR_IF(ret != DW_DLV_OK);
584 debug("inline definition offset %lld\n",
585 pf->inl_offs);
586 return 0;
587 }
588 /* Get probe address */
589 pf->addr = die_get_entrypc(dlink->die);
590 pf->addr += pp->offset;
591 /* TODO: Check the address in this function */
592 show_probepoint(dlink->die, pp->offset, pf);
593 /* Continue to search */
594 }
595 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
596 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
597 /* Get probe address */
598 pf->addr = die_get_entrypc(dlink->die);
599 pf->addr += pp->offset;
600 debug("found inline addr: 0x%llx\n", pf->addr);
601 /* Inlined function. Get a real subprogram */
602 for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
603 tag = 0;
604 dwarf_tag(lk->die, &tag, &__dw_error);
605 ERR_IF(ret == DW_DLV_ERROR);
606 if (tag == DW_TAG_subprogram &&
607 !die_inlined_subprogram(lk->die))
608 goto found;
609 }
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400610 die("Failed to find real subprogram.\n");
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400611found:
612 /* Get offset from subprogram */
613 ret = die_within_subprogram(lk->die, pf->addr, &offs);
614 ERR_IF(!ret);
615 show_probepoint(lk->die, offs, pf);
616 /* Continue to search */
617 }
618 }
619 return 0;
620}
621
622static void find_by_func(Dwarf_Die cu_die, struct probe_finder *pf)
623{
624 search_die_from_children(cu_die, probefunc_callback, pf);
625}
626
627/* Find a probe point */
628int find_probepoint(int fd, struct probe_point *pp)
629{
630 Dwarf_Half addr_size = 0;
631 Dwarf_Unsigned next_cuh = 0;
632 Dwarf_Die cu_die = 0;
633 int cu_number = 0, ret;
634 struct probe_finder pf = {.pp = pp};
635
636 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
637 if (ret != DW_DLV_OK)
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400638 die("Failed to call dwarf_init(). Maybe, not a dwarf file.\n");
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400639
640 pp->found = 0;
641 while (++cu_number) {
642 /* Search CU (Compilation Unit) */
643 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
644 &addr_size, &next_cuh, &__dw_error);
645 ERR_IF(ret == DW_DLV_ERROR);
646 if (ret == DW_DLV_NO_ENTRY)
647 break;
648
649 /* Get the DIE(Debugging Information Entry) of this CU */
650 ret = dwarf_siblingof(__dw_debug, 0, &cu_die, &__dw_error);
651 ERR_IF(ret != DW_DLV_OK);
652
653 /* Check if target file is included. */
654 if (pp->file)
655 pf.fno = die_get_fileno(cu_die, pp->file);
656
657 if (!pp->file || pf.fno) {
658 /* Save CU base address (for frame_base) */
659 ret = dwarf_lowpc(cu_die, &pf.cu_base, &__dw_error);
660 ERR_IF(ret == DW_DLV_ERROR);
661 if (ret == DW_DLV_NO_ENTRY)
662 pf.cu_base = 0;
663 if (pp->line)
664 find_by_line(cu_die, &pf);
665 if (pp->function)
666 find_by_func(cu_die, &pf);
667 }
668 dwarf_dealloc(__dw_debug, cu_die, DW_DLA_DIE);
669 }
670 ret = dwarf_finish(__dw_debug, &__dw_error);
671 ERR_IF(ret != DW_DLV_OK);
672
673 return pp->found;
674}
675