blob: 4b852c0d16a5b24a37589b2dd8a2f52f40c28169 [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
Masami Hiramatsu89c69c02009-10-16 20:08:10 -040035#include "event.h"
36#include "debug.h"
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -040037#include "util.h"
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040038#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
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040050/*
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);
Juha Leppanend56728b2009-12-07 12:00:40 -0500109 while (--i1 >= 0 && --i2 >= 0) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400110 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. */
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400117static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400118{
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)
Arnaldo Carvalho de Melob7cb10e2009-10-21 17:34:06 -0200139 pr_debug("found fno: %d\n", (int)found);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400140 return found;
141}
142
143/* Compare diename and tname */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400144static int die_compare_name(Dwarf_Die dw_die, const char *tname)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400145{
146 char *name;
147 int ret;
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400148 ret = dwarf_diename(dw_die, &name, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400149 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400150 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);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400167 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400168 if (ret == DW_DLV_NO_ENTRY)
169 return 0;
170 ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400171 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400172 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 */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400180static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400181{
182 /* TODO: check strictly */
183 Dwarf_Bool inl;
184 int ret;
185
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400186 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400187 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400188 return inl;
189}
190
191/* Get the offset of abstruct_origin */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400192static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400193{
194 Dwarf_Attribute attr;
195 Dwarf_Off cu_offs;
196 int ret;
197
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400198 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400199 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400200 ret = dwarf_formref(attr, &cu_offs, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400201 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400202 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 */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400207static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400208{
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 */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400217 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400218 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400219 if (ret == DW_DLV_OK) {
220 ret = dwarf_formaddr(attr, &addr, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400221 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400222 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
223 return addr;
224 }
225
226 /* Try to get low pc */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400227 ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400228 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400229 if (ret == DW_DLV_OK)
230 return addr;
231
232 /* Try to get ranges */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400233 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400234 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400235 ret = dwarf_formref(attr, &offs, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400236 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400237 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
238 &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400239 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400240 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);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400264 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400265 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);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400276 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400277 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);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400296 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400297 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);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400312 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400313 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);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400320 DIE_IF(desc->ld_s == NULL);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400321 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
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400338/* Get decl_file attribute value (file number) */
339static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die)
340{
341 Dwarf_Attribute attr;
342 Dwarf_Unsigned fno;
343 int ret;
344
345 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error);
346 DIE_IF(ret != DW_DLV_OK);
347 dwarf_formudata(attr, &fno, &__dw_error);
348 DIE_IF(ret != DW_DLV_OK);
349 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
350 return fno;
351}
352
353/* Get decl_line attribute value (line number) */
354static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
355{
356 Dwarf_Attribute attr;
357 Dwarf_Unsigned lno;
358 int ret;
359
360 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error);
361 DIE_IF(ret != DW_DLV_OK);
362 dwarf_formudata(attr, &lno, &__dw_error);
363 DIE_IF(ret != DW_DLV_OK);
364 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
365 return lno;
366}
367
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400368/*
369 * Probe finder related functions
370 */
371
372/* Show a location */
373static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
374{
375 Dwarf_Small op;
376 Dwarf_Unsigned regn;
377 Dwarf_Signed offs;
378 int deref = 0, ret;
379 const char *regs;
380
381 op = loc->lr_atom;
382
383 /* If this is based on frame buffer, set the offset */
384 if (op == DW_OP_fbreg) {
385 deref = 1;
386 offs = (Dwarf_Signed)loc->lr_number;
387 op = pf->fbloc.ld_s[0].lr_atom;
388 loc = &pf->fbloc.ld_s[0];
389 } else
390 offs = 0;
391
392 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
393 regn = op - DW_OP_breg0;
394 offs += (Dwarf_Signed)loc->lr_number;
395 deref = 1;
396 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
397 regn = op - DW_OP_reg0;
398 } else if (op == DW_OP_bregx) {
399 regn = loc->lr_number;
400 offs += (Dwarf_Signed)loc->lr_number2;
401 deref = 1;
402 } else if (op == DW_OP_regx) {
403 regn = loc->lr_number;
404 } else
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400405 die("Dwarf_OP %d is not supported.\n", op);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400406
407 regs = get_arch_regstr(regn);
408 if (!regs)
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400409 die("%lld exceeds max register number.\n", regn);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400410
411 if (deref)
412 ret = snprintf(pf->buf, pf->len,
413 " %s=%+lld(%s)", pf->var, offs, regs);
414 else
415 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400416 DIE_IF(ret < 0);
417 DIE_IF(ret >= pf->len);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400418}
419
420/* Show a variables in kprobe event format */
421static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
422{
423 Dwarf_Attribute attr;
424 Dwarf_Locdesc ld;
425 int ret;
426
427 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error);
428 if (ret != DW_DLV_OK)
429 goto error;
430 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base));
431 if (ret != DW_DLV_OK)
432 goto error;
433 /* TODO? */
Masami Hiramatsu97698332009-10-16 20:08:18 -0400434 DIE_IF(ld.ld_cents != 1);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400435 show_location(&ld.ld_s[0], pf);
436 free(ld.ld_s);
437 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
438 return ;
439error:
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400440 die("Failed to find the location of %s at this address.\n"
441 " Perhaps, it has been optimized out.\n", pf->var);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400442}
443
444static int variable_callback(struct die_link *dlink, void *data)
445{
446 struct probe_finder *pf = (struct probe_finder *)data;
447 Dwarf_Half tag;
448 int ret;
449
450 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400451 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400452 if ((tag == DW_TAG_formal_parameter ||
453 tag == DW_TAG_variable) &&
454 (die_compare_name(dlink->die, pf->var) == 0)) {
455 show_variable(dlink->die, pf);
456 return 1;
457 }
458 /* TODO: Support struct members and arrays */
459 return 0;
460}
461
462/* Find a variable in a subprogram die */
463static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
464{
465 int ret;
466
467 if (!is_c_varname(pf->var)) {
468 /* Output raw parameters */
469 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400470 DIE_IF(ret < 0);
471 DIE_IF(ret >= pf->len);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400472 return ;
473 }
474
Arnaldo Carvalho de Melob7cb10e2009-10-21 17:34:06 -0200475 pr_debug("Searching '%s' variable in context.\n", pf->var);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400476 /* Search child die for local variables and parameters. */
477 ret = search_die_from_children(sp_die, variable_callback, pf);
478 if (!ret)
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400479 die("Failed to find '%s' in this function.\n", pf->var);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400480}
481
482/* Get a frame base on the address */
483static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
484{
485 Dwarf_Attribute attr;
486 int ret;
487
488 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400489 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400490 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
Masami Hiramatsu97698332009-10-16 20:08:18 -0400491 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400492 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
493}
494
495static void free_current_frame_base(struct probe_finder *pf)
496{
497 free(pf->fbloc.ld_s);
498 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
499}
500
501/* Show a probe point to output buffer */
502static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
503 struct probe_finder *pf)
504{
505 struct probe_point *pp = pf->pp;
506 char *name;
507 char tmp[MAX_PROBE_BUFFER];
508 int ret, i, len;
509
510 /* Output name of probe point */
511 ret = dwarf_diename(sp_die, &name, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400512 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400513 if (ret == DW_DLV_OK) {
514 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
515 (unsigned int)offs);
Masami Hiramatsu253977b2009-10-27 16:43:10 -0400516 /* Copy the function name if possible */
517 if (!pp->function) {
518 pp->function = strdup(name);
519 pp->offset = offs;
520 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400521 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
522 } else {
523 /* This function has no name. */
524 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr);
Masami Hiramatsu253977b2009-10-27 16:43:10 -0400525 if (!pp->function) {
526 /* TODO: Use _stext */
527 pp->function = strdup("");
528 pp->offset = (int)pf->addr;
529 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400530 }
Masami Hiramatsu97698332009-10-16 20:08:18 -0400531 DIE_IF(ret < 0);
532 DIE_IF(ret >= MAX_PROBE_BUFFER);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400533 len = ret;
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400534 pr_debug("Probe point found: %s\n", tmp);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400535
536 /* Find each argument */
537 get_current_frame_base(sp_die, pf);
538 for (i = 0; i < pp->nr_args; i++) {
539 pf->var = pp->args[i];
540 pf->buf = &tmp[len];
541 pf->len = MAX_PROBE_BUFFER - len;
542 find_variable(sp_die, pf);
543 len += strlen(pf->buf);
544 }
545 free_current_frame_base(pf);
546
547 pp->probes[pp->found] = strdup(tmp);
548 pp->found++;
549}
550
551static int probeaddr_callback(struct die_link *dlink, void *data)
552{
553 struct probe_finder *pf = (struct probe_finder *)data;
554 Dwarf_Half tag;
555 Dwarf_Signed offs;
556 int ret;
557
558 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400559 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400560 /* Check the address is in this subprogram */
561 if (tag == DW_TAG_subprogram &&
562 die_within_subprogram(dlink->die, pf->addr, &offs)) {
563 show_probepoint(dlink->die, offs, pf);
564 return 1;
565 }
566 return 0;
567}
568
569/* Find probe point from its line number */
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400570static void find_by_line(struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400571{
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400572 Dwarf_Signed cnt, i, clm;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400573 Dwarf_Line *lines;
574 Dwarf_Unsigned lineno = 0;
575 Dwarf_Addr addr;
576 Dwarf_Unsigned fno;
577 int ret;
578
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400579 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400580 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400581
582 for (i = 0; i < cnt; i++) {
583 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400584 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400585 if (fno != pf->fno)
586 continue;
587
588 ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400589 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400590 if (lineno != pf->lno)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400591 continue;
592
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400593 ret = dwarf_lineoff(lines[i], &clm, &__dw_error);
594 DIE_IF(ret != DW_DLV_OK);
595
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400596 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400597 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400598 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
599 (int)i, (unsigned)lineno, (int)clm, addr);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400600 pf->addr = addr;
601 /* Search a real subprogram including this line, */
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400602 ret = search_die_from_children(pf->cu_die,
603 probeaddr_callback, pf);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400604 if (ret == 0)
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400605 die("Probe point is not found in subprograms.\n");
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400606 /* Continuing, because target line might be inlined. */
607 }
608 dwarf_srclines_dealloc(__dw_debug, lines, cnt);
609}
610
611/* Search function from function name */
612static int probefunc_callback(struct die_link *dlink, void *data)
613{
614 struct probe_finder *pf = (struct probe_finder *)data;
615 struct probe_point *pp = pf->pp;
616 struct die_link *lk;
617 Dwarf_Signed offs;
618 Dwarf_Half tag;
619 int ret;
620
621 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400622 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400623 if (tag == DW_TAG_subprogram) {
624 if (die_compare_name(dlink->die, pp->function) == 0) {
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400625 if (pp->line) { /* Function relative line */
626 pf->fno = die_get_decl_file(dlink->die);
627 pf->lno = die_get_decl_line(dlink->die)
628 + pp->line;
629 find_by_line(pf);
630 return 1;
631 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400632 if (die_inlined_subprogram(dlink->die)) {
633 /* Inlined function, save it. */
634 ret = dwarf_die_CU_offset(dlink->die,
635 &pf->inl_offs,
636 &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400637 DIE_IF(ret != DW_DLV_OK);
Arnaldo Carvalho de Melob7cb10e2009-10-21 17:34:06 -0200638 pr_debug("inline definition offset %lld\n",
639 pf->inl_offs);
Masami Hiramatsu8030c5f2009-10-27 16:42:53 -0400640 return 0; /* Continue to search */
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400641 }
642 /* Get probe address */
643 pf->addr = die_get_entrypc(dlink->die);
644 pf->addr += pp->offset;
645 /* TODO: Check the address in this function */
646 show_probepoint(dlink->die, pp->offset, pf);
Masami Hiramatsu8030c5f2009-10-27 16:42:53 -0400647 return 1; /* Exit; no same symbol in this CU. */
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400648 }
649 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
650 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
651 /* Get probe address */
652 pf->addr = die_get_entrypc(dlink->die);
653 pf->addr += pp->offset;
Arnaldo Carvalho de Melob7cb10e2009-10-21 17:34:06 -0200654 pr_debug("found inline addr: 0x%llx\n", pf->addr);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400655 /* Inlined function. Get a real subprogram */
656 for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
657 tag = 0;
658 dwarf_tag(lk->die, &tag, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400659 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400660 if (tag == DW_TAG_subprogram &&
661 !die_inlined_subprogram(lk->die))
662 goto found;
663 }
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400664 die("Failed to find real subprogram.\n");
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400665found:
666 /* Get offset from subprogram */
667 ret = die_within_subprogram(lk->die, pf->addr, &offs);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400668 DIE_IF(!ret);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400669 show_probepoint(lk->die, offs, pf);
670 /* Continue to search */
671 }
672 }
673 return 0;
674}
675
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400676static void find_by_func(struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400677{
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400678 search_die_from_children(pf->cu_die, probefunc_callback, pf);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400679}
680
681/* Find a probe point */
682int find_probepoint(int fd, struct probe_point *pp)
683{
684 Dwarf_Half addr_size = 0;
685 Dwarf_Unsigned next_cuh = 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400686 int cu_number = 0, ret;
687 struct probe_finder pf = {.pp = pp};
688
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
Masami Hiramatsu411edfe2009-12-15 10:31:35 -0500690 if (ret != DW_DLV_OK)
Masami Hiramatsua225a1d2009-11-03 19:12:30 -0500691 return -ENOENT;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400692
693 pp->found = 0;
694 while (++cu_number) {
695 /* Search CU (Compilation Unit) */
696 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
697 &addr_size, &next_cuh, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400698 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400699 if (ret == DW_DLV_NO_ENTRY)
700 break;
701
702 /* Get the DIE(Debugging Information Entry) of this CU */
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400703 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400704 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400705
706 /* Check if target file is included. */
707 if (pp->file)
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400708 pf.fno = cu_find_fileno(pf.cu_die, pp->file);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400709
710 if (!pp->file || pf.fno) {
711 /* Save CU base address (for frame_base) */
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400712 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400713 DIE_IF(ret == DW_DLV_ERROR);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400714 if (ret == DW_DLV_NO_ENTRY)
715 pf.cu_base = 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400716 if (pp->function)
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400717 find_by_func(&pf);
718 else {
719 pf.lno = pp->line;
720 find_by_line(&pf);
721 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400722 }
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400723 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400724 }
725 ret = dwarf_finish(__dw_debug, &__dw_error);
Masami Hiramatsu97698332009-10-16 20:08:18 -0400726 DIE_IF(ret != DW_DLV_OK);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400727
728 return pp->found;
729}
730