kprobe-tracer: Compare both of event-name and event-group to find probe
[linux-2.6-block.git] / tools / perf / util / probe-finder.c
CommitLineData
4ea42b18
MH
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>
074fc0e4 34
89c69c0e
MH
35#include "event.h"
36#include "debug.h"
074fc0e4 37#include "util.h"
4ea42b18
MH
38#include "probe-finder.h"
39
40
41/* Dwarf_Die Linkage to parent Die */
42struct die_link {
43 struct die_link *parent; /* Parent die */
44 Dwarf_Die die; /* Current die */
45};
46
47static Dwarf_Debug __dw_debug;
48static Dwarf_Error __dw_error;
49
4ea42b18
MH
50/*
51 * Generic dwarf analysis helpers
52 */
53
54#define X86_32_MAX_REGS 8
55const 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
67const 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) */
96static 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 */
105static 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. */
117static Dwarf_Unsigned die_get_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)
b7cb10e7 139 pr_debug("found fno: %d\n", (int)found);
4ea42b18
MH
140 return found;
141}
142
143/* Compare diename and tname */
074fc0e4 144static int die_compare_name(Dwarf_Die dw_die, const char *tname)
4ea42b18
MH
145{
146 char *name;
147 int ret;
074fc0e4 148 ret = dwarf_diename(dw_die, &name, &__dw_error);
9769833b 149 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
150 if (ret == DW_DLV_OK) {
151 ret = strcmp(tname, name);
152 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
153 } else
154 ret = -1;
155 return ret;
156}
157
158/* Check the address is in the subprogram(function). */
159static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr,
160 Dwarf_Signed *offs)
161{
162 Dwarf_Addr lopc, hipc;
163 int ret;
164
165 /* TODO: check ranges */
166 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
9769833b 167 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
168 if (ret == DW_DLV_NO_ENTRY)
169 return 0;
170 ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
9769833b 171 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
172 if (lopc <= addr && addr < hipc) {
173 *offs = addr - lopc;
174 return 1;
175 } else
176 return 0;
177}
178
179/* Check the die is inlined function */
074fc0e4 180static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
4ea42b18
MH
181{
182 /* TODO: check strictly */
183 Dwarf_Bool inl;
184 int ret;
185
074fc0e4 186 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error);
9769833b 187 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
188 return inl;
189}
190
191/* Get the offset of abstruct_origin */
074fc0e4 192static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
4ea42b18
MH
193{
194 Dwarf_Attribute attr;
195 Dwarf_Off cu_offs;
196 int ret;
197
074fc0e4 198 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error);
9769833b 199 DIE_IF(ret != DW_DLV_OK);
4ea42b18 200 ret = dwarf_formref(attr, &cu_offs, &__dw_error);
9769833b 201 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
202 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
203 return cu_offs;
204}
205
206/* Get entry pc(or low pc, 1st entry of ranges) of the die */
074fc0e4 207static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
4ea42b18
MH
208{
209 Dwarf_Attribute attr;
210 Dwarf_Addr addr;
211 Dwarf_Off offs;
212 Dwarf_Ranges *ranges;
213 Dwarf_Signed cnt;
214 int ret;
215
216 /* Try to get entry pc */
074fc0e4 217 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error);
9769833b 218 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
219 if (ret == DW_DLV_OK) {
220 ret = dwarf_formaddr(attr, &addr, &__dw_error);
9769833b 221 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
222 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
223 return addr;
224 }
225
226 /* Try to get low pc */
074fc0e4 227 ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
9769833b 228 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
229 if (ret == DW_DLV_OK)
230 return addr;
231
232 /* Try to get ranges */
074fc0e4 233 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
9769833b 234 DIE_IF(ret != DW_DLV_OK);
4ea42b18 235 ret = dwarf_formref(attr, &offs, &__dw_error);
9769833b 236 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
237 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
238 &__dw_error);
9769833b 239 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
240 addr = ranges[0].dwr_addr1;
241 dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
242 return addr;
243}
244
245/*
246 * Search a Die from Die tree.
247 * Note: cur_link->die should be deallocated in this function.
248 */
249static int __search_die_tree(struct die_link *cur_link,
250 int (*die_cb)(struct die_link *, void *),
251 void *data)
252{
253 Dwarf_Die new_die;
254 struct die_link new_link;
255 int ret;
256
257 if (!die_cb)
258 return 0;
259
260 /* Check current die */
261 while (!(ret = die_cb(cur_link, data))) {
262 /* Check child die */
263 ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
9769833b 264 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
265 if (ret == DW_DLV_OK) {
266 new_link.parent = cur_link;
267 new_link.die = new_die;
268 ret = __search_die_tree(&new_link, die_cb, data);
269 if (ret)
270 break;
271 }
272
273 /* Move to next sibling */
274 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
275 &__dw_error);
9769833b 276 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
277 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
278 cur_link->die = new_die;
279 if (ret == DW_DLV_NO_ENTRY)
280 return 0;
281 }
282 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
283 return ret;
284}
285
286/* Search a die in its children's die tree */
287static int search_die_from_children(Dwarf_Die parent_die,
288 int (*die_cb)(struct die_link *, void *),
289 void *data)
290{
291 struct die_link new_link;
292 int ret;
293
294 new_link.parent = NULL;
295 ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
9769833b 296 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
297 if (ret == DW_DLV_OK)
298 return __search_die_tree(&new_link, die_cb, data);
299 else
300 return 0;
301}
302
303/* Find a locdesc corresponding to the address */
304static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
305 Dwarf_Addr addr)
306{
307 Dwarf_Signed lcnt;
308 Dwarf_Locdesc **llbuf;
309 int ret, i;
310
311 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
9769833b 312 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
313 ret = DW_DLV_NO_ENTRY;
314 for (i = 0; i < lcnt; ++i) {
315 if (llbuf[i]->ld_lopc <= addr &&
316 llbuf[i]->ld_hipc > addr) {
317 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
318 desc->ld_s =
319 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
9769833b 320 DIE_IF(desc->ld_s == NULL);
4ea42b18
MH
321 memcpy(desc->ld_s, llbuf[i]->ld_s,
322 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
323 ret = DW_DLV_OK;
324 break;
325 }
326 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
327 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
328 }
329 /* Releasing loop */
330 for (; i < lcnt; ++i) {
331 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
332 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
333 }
334 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
335 return ret;
336}
337
338/*
339 * Probe finder related functions
340 */
341
342/* Show a location */
343static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
344{
345 Dwarf_Small op;
346 Dwarf_Unsigned regn;
347 Dwarf_Signed offs;
348 int deref = 0, ret;
349 const char *regs;
350
351 op = loc->lr_atom;
352
353 /* If this is based on frame buffer, set the offset */
354 if (op == DW_OP_fbreg) {
355 deref = 1;
356 offs = (Dwarf_Signed)loc->lr_number;
357 op = pf->fbloc.ld_s[0].lr_atom;
358 loc = &pf->fbloc.ld_s[0];
359 } else
360 offs = 0;
361
362 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
363 regn = op - DW_OP_breg0;
364 offs += (Dwarf_Signed)loc->lr_number;
365 deref = 1;
366 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
367 regn = op - DW_OP_reg0;
368 } else if (op == DW_OP_bregx) {
369 regn = loc->lr_number;
370 offs += (Dwarf_Signed)loc->lr_number2;
371 deref = 1;
372 } else if (op == DW_OP_regx) {
373 regn = loc->lr_number;
374 } else
074fc0e4 375 die("Dwarf_OP %d is not supported.\n", op);
4ea42b18
MH
376
377 regs = get_arch_regstr(regn);
378 if (!regs)
074fc0e4 379 die("%lld exceeds max register number.\n", regn);
4ea42b18
MH
380
381 if (deref)
382 ret = snprintf(pf->buf, pf->len,
383 " %s=%+lld(%s)", pf->var, offs, regs);
384 else
385 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
9769833b
MH
386 DIE_IF(ret < 0);
387 DIE_IF(ret >= pf->len);
4ea42b18
MH
388}
389
390/* Show a variables in kprobe event format */
391static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
392{
393 Dwarf_Attribute attr;
394 Dwarf_Locdesc ld;
395 int ret;
396
397 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error);
398 if (ret != DW_DLV_OK)
399 goto error;
400 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base));
401 if (ret != DW_DLV_OK)
402 goto error;
403 /* TODO? */
9769833b 404 DIE_IF(ld.ld_cents != 1);
4ea42b18
MH
405 show_location(&ld.ld_s[0], pf);
406 free(ld.ld_s);
407 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
408 return ;
409error:
074fc0e4
MH
410 die("Failed to find the location of %s at this address.\n"
411 " Perhaps, it has been optimized out.\n", pf->var);
4ea42b18
MH
412}
413
414static int variable_callback(struct die_link *dlink, void *data)
415{
416 struct probe_finder *pf = (struct probe_finder *)data;
417 Dwarf_Half tag;
418 int ret;
419
420 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
9769833b 421 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
422 if ((tag == DW_TAG_formal_parameter ||
423 tag == DW_TAG_variable) &&
424 (die_compare_name(dlink->die, pf->var) == 0)) {
425 show_variable(dlink->die, pf);
426 return 1;
427 }
428 /* TODO: Support struct members and arrays */
429 return 0;
430}
431
432/* Find a variable in a subprogram die */
433static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
434{
435 int ret;
436
437 if (!is_c_varname(pf->var)) {
438 /* Output raw parameters */
439 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
9769833b
MH
440 DIE_IF(ret < 0);
441 DIE_IF(ret >= pf->len);
4ea42b18
MH
442 return ;
443 }
444
b7cb10e7 445 pr_debug("Searching '%s' variable in context.\n", pf->var);
4ea42b18
MH
446 /* Search child die for local variables and parameters. */
447 ret = search_die_from_children(sp_die, variable_callback, pf);
448 if (!ret)
074fc0e4 449 die("Failed to find '%s' in this function.\n", pf->var);
4ea42b18
MH
450}
451
452/* Get a frame base on the address */
453static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
454{
455 Dwarf_Attribute attr;
456 int ret;
457
458 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
9769833b 459 DIE_IF(ret != DW_DLV_OK);
4ea42b18 460 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
9769833b 461 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
462 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
463}
464
465static void free_current_frame_base(struct probe_finder *pf)
466{
467 free(pf->fbloc.ld_s);
468 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
469}
470
471/* Show a probe point to output buffer */
472static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
473 struct probe_finder *pf)
474{
475 struct probe_point *pp = pf->pp;
476 char *name;
477 char tmp[MAX_PROBE_BUFFER];
478 int ret, i, len;
479
480 /* Output name of probe point */
481 ret = dwarf_diename(sp_die, &name, &__dw_error);
9769833b 482 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
483 if (ret == DW_DLV_OK) {
484 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
485 (unsigned int)offs);
486 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
487 } else {
488 /* This function has no name. */
489 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr);
490 }
9769833b
MH
491 DIE_IF(ret < 0);
492 DIE_IF(ret >= MAX_PROBE_BUFFER);
4ea42b18
MH
493 len = ret;
494
495 /* Find each argument */
496 get_current_frame_base(sp_die, pf);
497 for (i = 0; i < pp->nr_args; i++) {
498 pf->var = pp->args[i];
499 pf->buf = &tmp[len];
500 pf->len = MAX_PROBE_BUFFER - len;
501 find_variable(sp_die, pf);
502 len += strlen(pf->buf);
503 }
504 free_current_frame_base(pf);
505
506 pp->probes[pp->found] = strdup(tmp);
507 pp->found++;
508}
509
510static int probeaddr_callback(struct die_link *dlink, void *data)
511{
512 struct probe_finder *pf = (struct probe_finder *)data;
513 Dwarf_Half tag;
514 Dwarf_Signed offs;
515 int ret;
516
517 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
9769833b 518 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
519 /* Check the address is in this subprogram */
520 if (tag == DW_TAG_subprogram &&
521 die_within_subprogram(dlink->die, pf->addr, &offs)) {
522 show_probepoint(dlink->die, offs, pf);
523 return 1;
524 }
525 return 0;
526}
527
528/* Find probe point from its line number */
529static void find_by_line(Dwarf_Die cu_die, struct probe_finder *pf)
530{
531 struct probe_point *pp = pf->pp;
532 Dwarf_Signed cnt, i;
533 Dwarf_Line *lines;
534 Dwarf_Unsigned lineno = 0;
535 Dwarf_Addr addr;
536 Dwarf_Unsigned fno;
537 int ret;
538
539 ret = dwarf_srclines(cu_die, &lines, &cnt, &__dw_error);
9769833b 540 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
541
542 for (i = 0; i < cnt; i++) {
543 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
9769833b 544 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
545 if (fno != pf->fno)
546 continue;
547
548 ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
9769833b 549 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
550 if (lineno != (Dwarf_Unsigned)pp->line)
551 continue;
552
553 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
9769833b 554 DIE_IF(ret != DW_DLV_OK);
b7cb10e7 555 pr_debug("Probe point found: 0x%llx\n", addr);
4ea42b18
MH
556 pf->addr = addr;
557 /* Search a real subprogram including this line, */
558 ret = search_die_from_children(cu_die, probeaddr_callback, pf);
559 if (ret == 0)
074fc0e4 560 die("Probe point is not found in subprograms.\n");
4ea42b18
MH
561 /* Continuing, because target line might be inlined. */
562 }
563 dwarf_srclines_dealloc(__dw_debug, lines, cnt);
564}
565
566/* Search function from function name */
567static int probefunc_callback(struct die_link *dlink, void *data)
568{
569 struct probe_finder *pf = (struct probe_finder *)data;
570 struct probe_point *pp = pf->pp;
571 struct die_link *lk;
572 Dwarf_Signed offs;
573 Dwarf_Half tag;
574 int ret;
575
576 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
9769833b 577 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
578 if (tag == DW_TAG_subprogram) {
579 if (die_compare_name(dlink->die, pp->function) == 0) {
580 if (die_inlined_subprogram(dlink->die)) {
581 /* Inlined function, save it. */
582 ret = dwarf_die_CU_offset(dlink->die,
583 &pf->inl_offs,
584 &__dw_error);
9769833b 585 DIE_IF(ret != DW_DLV_OK);
b7cb10e7
ACM
586 pr_debug("inline definition offset %lld\n",
587 pf->inl_offs);
4ea42b18
MH
588 return 0;
589 }
590 /* Get probe address */
591 pf->addr = die_get_entrypc(dlink->die);
592 pf->addr += pp->offset;
593 /* TODO: Check the address in this function */
594 show_probepoint(dlink->die, pp->offset, pf);
595 /* Continue to search */
596 }
597 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
598 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
599 /* Get probe address */
600 pf->addr = die_get_entrypc(dlink->die);
601 pf->addr += pp->offset;
b7cb10e7 602 pr_debug("found inline addr: 0x%llx\n", pf->addr);
4ea42b18
MH
603 /* Inlined function. Get a real subprogram */
604 for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
605 tag = 0;
606 dwarf_tag(lk->die, &tag, &__dw_error);
9769833b 607 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
608 if (tag == DW_TAG_subprogram &&
609 !die_inlined_subprogram(lk->die))
610 goto found;
611 }
074fc0e4 612 die("Failed to find real subprogram.\n");
4ea42b18
MH
613found:
614 /* Get offset from subprogram */
615 ret = die_within_subprogram(lk->die, pf->addr, &offs);
9769833b 616 DIE_IF(!ret);
4ea42b18
MH
617 show_probepoint(lk->die, offs, pf);
618 /* Continue to search */
619 }
620 }
621 return 0;
622}
623
624static void find_by_func(Dwarf_Die cu_die, struct probe_finder *pf)
625{
626 search_die_from_children(cu_die, probefunc_callback, pf);
627}
628
629/* Find a probe point */
630int find_probepoint(int fd, struct probe_point *pp)
631{
632 Dwarf_Half addr_size = 0;
633 Dwarf_Unsigned next_cuh = 0;
634 Dwarf_Die cu_die = 0;
635 int cu_number = 0, ret;
636 struct probe_finder pf = {.pp = pp};
637
638 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
639 if (ret != DW_DLV_OK)
074fc0e4 640 die("Failed to call dwarf_init(). Maybe, not a dwarf file.\n");
4ea42b18
MH
641
642 pp->found = 0;
643 while (++cu_number) {
644 /* Search CU (Compilation Unit) */
645 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
646 &addr_size, &next_cuh, &__dw_error);
9769833b 647 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
648 if (ret == DW_DLV_NO_ENTRY)
649 break;
650
651 /* Get the DIE(Debugging Information Entry) of this CU */
652 ret = dwarf_siblingof(__dw_debug, 0, &cu_die, &__dw_error);
9769833b 653 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
654
655 /* Check if target file is included. */
656 if (pp->file)
657 pf.fno = die_get_fileno(cu_die, pp->file);
658
659 if (!pp->file || pf.fno) {
660 /* Save CU base address (for frame_base) */
661 ret = dwarf_lowpc(cu_die, &pf.cu_base, &__dw_error);
9769833b 662 DIE_IF(ret == DW_DLV_ERROR);
4ea42b18
MH
663 if (ret == DW_DLV_NO_ENTRY)
664 pf.cu_base = 0;
665 if (pp->line)
666 find_by_line(cu_die, &pf);
667 if (pp->function)
668 find_by_func(cu_die, &pf);
669 }
670 dwarf_dealloc(__dw_debug, cu_die, DW_DLA_DIE);
671 }
672 ret = dwarf_finish(__dw_debug, &__dw_error);
9769833b 673 DIE_IF(ret != DW_DLV_OK);
4ea42b18
MH
674
675 return pp->found;
676}
677