blob: db52ec2e84de850dcf5130d77268c5fe39c50bd2 [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 Hiramatsu2a9c8c32010-02-25 08:36:12 -050035#include "string.h"
Masami Hiramatsu89c69c02009-10-16 20:08:10 -040036#include "event.h"
37#include "debug.h"
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -040038#include "util.h"
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040039#include "probe-finder.h"
40
41
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040042/*
43 * Generic dwarf analysis helpers
44 */
45
46#define X86_32_MAX_REGS 8
47const char *x86_32_regs_table[X86_32_MAX_REGS] = {
48 "%ax",
49 "%cx",
50 "%dx",
51 "%bx",
52 "$stack", /* Stack address instead of %sp */
53 "%bp",
54 "%si",
55 "%di",
56};
57
58#define X86_64_MAX_REGS 16
59const char *x86_64_regs_table[X86_64_MAX_REGS] = {
60 "%ax",
61 "%dx",
62 "%cx",
63 "%bx",
64 "%si",
65 "%di",
66 "%bp",
67 "%sp",
68 "%r8",
69 "%r9",
70 "%r10",
71 "%r11",
72 "%r12",
73 "%r13",
74 "%r14",
75 "%r15",
76};
77
78/* TODO: switching by dwarf address size */
79#ifdef __x86_64__
80#define ARCH_MAX_REGS X86_64_MAX_REGS
81#define arch_regs_table x86_64_regs_table
82#else
83#define ARCH_MAX_REGS X86_32_MAX_REGS
84#define arch_regs_table x86_32_regs_table
85#endif
86
87/* Return architecture dependent register string (for kprobe-tracer) */
88static const char *get_arch_regstr(unsigned int n)
89{
90 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
91}
92
93/*
94 * Compare the tail of two strings.
95 * Return 0 if whole of either string is same as another's tail part.
96 */
97static int strtailcmp(const char *s1, const char *s2)
98{
99 int i1 = strlen(s1);
100 int i2 = strlen(s2);
Juha Leppanend56728b2009-12-07 12:00:40 -0500101 while (--i1 >= 0 && --i2 >= 0) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400102 if (s1[i1] != s2[i2])
103 return s1[i1] - s2[i2];
104 }
105 return 0;
106}
107
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500108/* Line number list operations */
109
110/* Add a line to line number list */
111static void line_list__add_line(struct list_head *head, unsigned int line)
112{
113 struct line_node *ln;
114 struct list_head *p;
115
116 /* Reverse search, because new line will be the last one */
117 list_for_each_entry_reverse(ln, head, list) {
118 if (ln->line < line) {
119 p = &ln->list;
120 goto found;
121 } else if (ln->line == line) /* Already exist */
122 return ;
123 }
124 /* List is empty, or the smallest entry */
125 p = head;
126found:
127 pr_debug("line list: add a line %u\n", line);
Masami Hiramatsu31facc52010-03-16 18:05:30 -0400128 ln = xzalloc(sizeof(struct line_node));
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500129 ln->line = line;
130 INIT_LIST_HEAD(&ln->list);
131 list_add(&ln->list, p);
132}
133
134/* Check if the line in line number list */
135static int line_list__has_line(struct list_head *head, unsigned int line)
136{
137 struct line_node *ln;
138
139 /* Reverse search, because new line will be the last one */
140 list_for_each_entry(ln, head, list)
141 if (ln->line == line)
142 return 1;
143
144 return 0;
145}
146
147/* Init line number list */
148static void line_list__init(struct list_head *head)
149{
150 INIT_LIST_HEAD(head);
151}
152
153/* Free line number list */
154static void line_list__free(struct list_head *head)
155{
156 struct line_node *ln;
157 while (!list_empty(head)) {
158 ln = list_first_entry(head, struct line_node, list);
159 list_del(&ln->list);
160 free(ln);
161 }
162}
163
164/* Dwarf wrappers */
165
166/* Find the realpath of the target file. */
167static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400168{
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500169 Dwarf_Files *files;
170 size_t nfiles, i;
Arnaldo Carvalho de Meloaccd3cc2010-03-05 12:51:04 -0300171 const char *src = NULL;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400172 int ret;
173
174 if (!fname)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500175 return NULL;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500176
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500177 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500178 if (ret != 0)
179 return NULL;
180
181 for (i = 0; i < nfiles; i++) {
182 src = dwarf_filesrc(files, i, NULL, NULL);
183 if (strtailcmp(src, fname) == 0)
184 break;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500185 }
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500186 return src;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500187}
188
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400189/* Compare diename and tname */
190static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
191{
192 const char *name;
193 name = dwarf_diename(dw_die);
194 DIE_IF(name == NULL);
195 return strcmp(tname, name);
196}
197
198/* Get entry pc(or low pc, 1st entry of ranges) of the die */
199static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
200{
201 Dwarf_Addr epc;
202 int ret;
203
204 ret = dwarf_entrypc(dw_die, &epc);
205 DIE_IF(ret == -1);
206 return epc;
207}
208
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400209/* Get type die, but skip qualifiers and typedef */
210static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
211{
212 Dwarf_Attribute attr;
213 int tag;
214
215 do {
216 if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
217 dwarf_formref_die(&attr, die_mem) == NULL)
218 return NULL;
219
220 tag = dwarf_tag(die_mem);
221 vr_die = die_mem;
222 } while (tag == DW_TAG_const_type ||
223 tag == DW_TAG_restrict_type ||
224 tag == DW_TAG_volatile_type ||
225 tag == DW_TAG_shared_type ||
226 tag == DW_TAG_typedef);
227
228 return die_mem;
229}
230
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400231/* Return values for die_find callbacks */
232enum {
233 DIE_FIND_CB_FOUND = 0, /* End of Search */
234 DIE_FIND_CB_CHILD = 1, /* Search only children */
235 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
236 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
237};
238
239/* Search a child die */
240static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
241 int (*callback)(Dwarf_Die *, void *),
242 void *data, Dwarf_Die *die_mem)
243{
244 Dwarf_Die child_die;
245 int ret;
246
247 ret = dwarf_child(rt_die, die_mem);
248 if (ret != 0)
249 return NULL;
250
251 do {
252 ret = callback(die_mem, data);
253 if (ret == DIE_FIND_CB_FOUND)
254 return die_mem;
255
256 if ((ret & DIE_FIND_CB_CHILD) &&
257 die_find_child(die_mem, callback, data, &child_die)) {
258 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
259 return die_mem;
260 }
261 } while ((ret & DIE_FIND_CB_SIBLING) &&
262 dwarf_siblingof(die_mem, die_mem) == 0);
263
264 return NULL;
265}
266
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500267struct __addr_die_search_param {
268 Dwarf_Addr addr;
269 Dwarf_Die *die_mem;
270};
271
272static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
273{
274 struct __addr_die_search_param *ad = data;
275
276 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
277 dwarf_haspc(fn_die, ad->addr)) {
278 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
279 return DWARF_CB_ABORT;
280 }
281 return DWARF_CB_OK;
282}
283
284/* Search a real subprogram including this line, */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400285static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
286 Dwarf_Die *die_mem)
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500287{
288 struct __addr_die_search_param ad;
289 ad.addr = addr;
290 ad.die_mem = die_mem;
291 /* dwarf_getscopes can't find subprogram. */
292 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
293 return NULL;
294 else
295 return die_mem;
296}
297
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400298/* die_find callback for inline function search */
299static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
300{
301 Dwarf_Addr *addr = data;
302
303 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
304 dwarf_haspc(die_mem, *addr))
305 return DIE_FIND_CB_FOUND;
306
307 return DIE_FIND_CB_CONTINUE;
308}
309
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500310/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400311static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
312 Dwarf_Die *die_mem)
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500313{
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400314 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500315}
316
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400317static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400318{
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400319 const char *name = data;
320 int tag;
321
322 tag = dwarf_tag(die_mem);
323 if ((tag == DW_TAG_formal_parameter ||
324 tag == DW_TAG_variable) &&
325 (die_compare_name(die_mem, name) == 0))
326 return DIE_FIND_CB_FOUND;
327
328 return DIE_FIND_CB_CONTINUE;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400329}
330
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400331/* Find a variable called 'name' */
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500332static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
333 Dwarf_Die *die_mem)
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500334{
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400335 return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
336 die_mem);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400337}
338
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400339static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
340{
341 const char *name = data;
342
343 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
344 (die_compare_name(die_mem, name) == 0))
345 return DIE_FIND_CB_FOUND;
346
347 return DIE_FIND_CB_SIBLING;
348}
349
350/* Find a member called 'name' */
351static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
352 Dwarf_Die *die_mem)
353{
354 return die_find_child(st_die, __die_find_member_cb, (void *)name,
355 die_mem);
356}
357
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400358/*
359 * Probe finder related functions
360 */
361
362/* Show a location */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400363static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400364{
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500365 unsigned int regn;
366 Dwarf_Word offs = 0;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400367 bool ref = false;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400368 const char *regs;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400369 struct kprobe_trace_arg *tvar = pf->tvar;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400370
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500371 /* TODO: support CFA */
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400372 /* If this is based on frame buffer, set the offset */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500373 if (op->atom == DW_OP_fbreg) {
374 if (pf->fb_ops == NULL)
375 die("The attribute of frame base is not supported.\n");
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400376 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500377 offs = op->number;
378 op = &pf->fb_ops[0];
379 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400380
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500381 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
382 regn = op->atom - DW_OP_breg0;
383 offs += op->number;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400384 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500385 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
386 regn = op->atom - DW_OP_reg0;
387 } else if (op->atom == DW_OP_bregx) {
388 regn = op->number;
389 offs += op->number2;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400390 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500391 } else if (op->atom == DW_OP_regx) {
392 regn = op->number;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400393 } else
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500394 die("DW_OP %d is not supported.", op->atom);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400395
396 regs = get_arch_regstr(regn);
397 if (!regs)
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500398 die("%u exceeds max register number.", regn);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400399
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400400 tvar->value = xstrdup(regs);
401 if (ref) {
402 tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
403 tvar->ref->offset = (long)offs;
404 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400405}
406
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400407static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
408 struct perf_probe_arg_field *field,
409 struct kprobe_trace_arg_ref **ref_ptr)
410{
411 struct kprobe_trace_arg_ref *ref = *ref_ptr;
412 Dwarf_Attribute attr;
413 Dwarf_Die member;
414 Dwarf_Die type;
415 Dwarf_Word offs;
416
417 pr_debug("converting %s in %s\n", field->name, varname);
418 if (die_get_real_type(vr_die, &type) == NULL)
419 die("Failed to get a type information of %s.", varname);
420
421 /* Check the pointer and dereference */
422 if (dwarf_tag(&type) == DW_TAG_pointer_type) {
423 if (!field->ref)
424 die("Semantic error: %s must be referred by '->'",
425 field->name);
426 /* Get the type pointed by this pointer */
427 if (die_get_real_type(&type, &type) == NULL)
428 die("Failed to get a type information of %s.", varname);
429
430 ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
431 if (*ref_ptr)
432 (*ref_ptr)->next = ref;
433 else
434 *ref_ptr = ref;
435 } else {
436 if (field->ref)
437 die("Semantic error: %s must be referred by '.'",
438 field->name);
439 if (!ref)
440 die("Structure on a register is not supported yet.");
441 }
442
443 /* Verify it is a data structure */
444 if (dwarf_tag(&type) != DW_TAG_structure_type)
445 die("%s is not a data structure.", varname);
446
447 if (die_find_member(&type, field->name, &member) == NULL)
448 die("%s(tyep:%s) has no member %s.", varname,
449 dwarf_diename(&type), field->name);
450
451 /* Get the offset of the field */
452 if (dwarf_attr(&member, DW_AT_data_member_location, &attr) == NULL ||
453 dwarf_formudata(&attr, &offs) != 0)
454 die("Failed to get the offset of %s.", field->name);
455 ref->offset += (long)offs;
456
457 /* Converting next field */
458 if (field->next)
459 convert_variable_fields(&member, field->name, field->next,
460 &ref);
461}
462
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400463/* Show a variables in kprobe event format */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400464static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400465{
466 Dwarf_Attribute attr;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500467 Dwarf_Op *expr;
468 size_t nexpr;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400469 int ret;
470
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500471 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400472 goto error;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500473 /* TODO: handle more than 1 exprs */
Masami Hiramatsud0cb4262010-03-15 13:02:35 -0400474 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500475 if (ret <= 0 || nexpr == 0)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400476 goto error;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500477
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400478 convert_location(expr, pf);
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400479
480 if (pf->pvar->field)
481 convert_variable_fields(vr_die, pf->pvar->name,
482 pf->pvar->field, &pf->tvar->ref);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500483 /* *expr will be cached in libdw. Don't free it. */
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400484 return ;
485error:
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500486 /* TODO: Support const_value */
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -0400487 die("Failed to find the location of %s at this address.\n"
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400488 " Perhaps, it has been optimized out.", pf->pvar->name);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400489}
490
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400491/* Find a variable in a subprogram die */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500492static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400493{
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500494 Dwarf_Die vr_die;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400495 char buf[128];
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400496
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500497 /* TODO: Support struct members and arrays */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400498 if (!is_c_varname(pf->pvar->name)) {
499 /* Copy raw parameters */
500 pf->tvar->value = xstrdup(pf->pvar->name);
501 } else {
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400502 synthesize_perf_probe_arg(pf->pvar, buf, 128);
503 pf->tvar->name = xstrdup(buf);
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400504 pr_debug("Searching '%s' variable in context.\n",
505 pf->pvar->name);
506 /* Search child die for local variables and parameters. */
507 if (!die_find_variable(sp_die, pf->pvar->name, &vr_die))
508 die("Failed to find '%s' in this function.",
509 pf->pvar->name);
510 convert_variable(&vr_die, pf);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400511 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400512}
513
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400514/* Show a probe point to output buffer */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400515static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400516{
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400517 struct kprobe_trace_event *tev;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500518 Dwarf_Addr eaddr;
519 Dwarf_Die die_mem;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500520 const char *name;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400521 int ret, i;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500522 Dwarf_Attribute fb_attr;
523 size_t nops;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400524
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400525 if (pf->ntevs == MAX_PROBES)
526 die("Too many( > %d) probe point found.\n", MAX_PROBES);
527 tev = &pf->tevs[pf->ntevs++];
528
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500529 /* If no real subprogram, find a real one */
530 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400531 sp_die = die_find_real_subprogram(&pf->cu_die,
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500532 pf->addr, &die_mem);
533 if (!sp_die)
534 die("Probe point is not found in subprograms.");
535 }
536
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400537 /* Copy the name of probe point */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500538 name = dwarf_diename(sp_die);
539 if (name) {
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500540 dwarf_entrypc(sp_die, &eaddr);
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400541 tev->point.symbol = xstrdup(name);
542 tev->point.offset = (unsigned long)(pf->addr - eaddr);
543 } else
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400544 /* This function has no name. */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400545 tev->point.offset = (unsigned long)pf->addr;
546
547 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
548 tev->point.offset);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400549
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500550 /* Get the frame base attribute/ops */
551 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
Masami Hiramatsud0cb4262010-03-15 13:02:35 -0400552 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500553 if (ret <= 0 || nops == 0)
554 pf->fb_ops = NULL;
555
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400556 /* Find each argument */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500557 /* TODO: use dwarf_cfi_addrframe */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400558 tev->nargs = pf->pev->nargs;
559 tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
560 for (i = 0; i < pf->pev->nargs; i++) {
561 pf->pvar = &pf->pev->args[i];
562 pf->tvar = &tev->args[i];
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400563 find_variable(sp_die, pf);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400564 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500565
566 /* *pf->fb_ops will be cached in libdw. Don't free it. */
567 pf->fb_ops = NULL;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400568}
569
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400570/* Find probe point from its line number */
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500571static void find_probe_point_by_line(struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400572{
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500573 Dwarf_Lines *lines;
574 Dwarf_Line *line;
575 size_t nlines, i;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500576 Dwarf_Addr addr;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500577 int lineno;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400578 int ret;
579
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500580 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
581 DIE_IF(ret != 0);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400582
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500583 for (i = 0; i < nlines; i++) {
584 line = dwarf_onesrcline(lines, i);
585 dwarf_lineno(line, &lineno);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400586 if (lineno != pf->lno)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400587 continue;
588
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500589 /* TODO: Get fileno from line, but how? */
590 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
591 continue;
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400592
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500593 ret = dwarf_lineaddr(line, &addr);
594 DIE_IF(ret != 0);
595 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
596 (int)i, lineno, (uintmax_t)addr);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400597 pf->addr = addr;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500598
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400599 convert_probe_point(NULL, pf);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400600 /* Continuing, because target line might be inlined. */
601 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400602}
603
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500604/* Find lines which match lazy pattern */
605static int find_lazy_match_lines(struct list_head *head,
606 const char *fname, const char *pat)
607{
608 char *fbuf, *p1, *p2;
609 int fd, line, nlines = 0;
610 struct stat st;
611
612 fd = open(fname, O_RDONLY);
613 if (fd < 0)
614 die("failed to open %s", fname);
615 DIE_IF(fstat(fd, &st) < 0);
Masami Hiramatsu31facc52010-03-16 18:05:30 -0400616 fbuf = xmalloc(st.st_size + 2);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500617 DIE_IF(read(fd, fbuf, st.st_size) < 0);
618 close(fd);
619 fbuf[st.st_size] = '\n'; /* Dummy line */
620 fbuf[st.st_size + 1] = '\0';
621 p1 = fbuf;
622 line = 1;
623 while ((p2 = strchr(p1, '\n')) != NULL) {
624 *p2 = '\0';
625 if (strlazymatch(p1, pat)) {
626 line_list__add_line(head, line);
627 nlines++;
628 }
629 line++;
630 p1 = p2 + 1;
631 }
632 free(fbuf);
633 return nlines;
634}
635
636/* Find probe points from lazy pattern */
637static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
638{
639 Dwarf_Lines *lines;
640 Dwarf_Line *line;
641 size_t nlines, i;
642 Dwarf_Addr addr;
643 Dwarf_Die die_mem;
644 int lineno;
645 int ret;
646
647 if (list_empty(&pf->lcache)) {
648 /* Matching lazy line pattern */
649 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400650 pf->pev->point.lazy_line);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500651 if (ret <= 0)
652 die("No matched lines found in %s.", pf->fname);
653 }
654
655 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
656 DIE_IF(ret != 0);
657 for (i = 0; i < nlines; i++) {
658 line = dwarf_onesrcline(lines, i);
659
660 dwarf_lineno(line, &lineno);
661 if (!line_list__has_line(&pf->lcache, lineno))
662 continue;
663
664 /* TODO: Get fileno from line, but how? */
665 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
666 continue;
667
668 ret = dwarf_lineaddr(line, &addr);
669 DIE_IF(ret != 0);
670 if (sp_die) {
671 /* Address filtering 1: does sp_die include addr? */
672 if (!dwarf_haspc(sp_die, addr))
673 continue;
674 /* Address filtering 2: No child include addr? */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400675 if (die_find_inlinefunc(sp_die, addr, &die_mem))
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500676 continue;
677 }
678
679 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
680 (int)i, lineno, (unsigned long long)addr);
681 pf->addr = addr;
682
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400683 convert_probe_point(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500684 /* Continuing, because target line might be inlined. */
685 }
686 /* TODO: deallocate lines, but how? */
687}
688
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500689static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400690{
691 struct probe_finder *pf = (struct probe_finder *)data;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400692 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400693
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500694 if (pp->lazy_line)
695 find_probe_point_lazy(in_die, pf);
696 else {
697 /* Get probe address */
698 pf->addr = die_get_entrypc(in_die);
699 pf->addr += pp->offset;
700 pr_debug("found inline addr: 0x%jx\n",
701 (uintmax_t)pf->addr);
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500702
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400703 convert_probe_point(in_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500704 }
705
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500706 return DWARF_CB_OK;
707}
708
709/* Search function from function name */
710static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
711{
712 struct probe_finder *pf = (struct probe_finder *)data;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400713 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500714
715 /* Check tag and diename */
716 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
717 die_compare_name(sp_die, pp->function) != 0)
718 return 0;
719
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500720 pf->fname = dwarf_decl_file(sp_die);
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500721 if (pp->line) { /* Function relative line */
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500722 dwarf_decl_line(sp_die, &pf->lno);
723 pf->lno += pp->line;
724 find_probe_point_by_line(pf);
725 } else if (!dwarf_func_inline(sp_die)) {
726 /* Real function */
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500727 if (pp->lazy_line)
728 find_probe_point_lazy(sp_die, pf);
729 else {
730 pf->addr = die_get_entrypc(sp_die);
731 pf->addr += pp->offset;
732 /* TODO: Check the address in this function */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400733 convert_probe_point(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500734 }
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500735 } else
736 /* Inlined function: search instances */
737 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
738
739 return 1; /* Exit; no same symbol in this CU. */
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400740}
741
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500742static void find_probe_point_by_func(struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400743{
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500744 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400745}
746
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400747/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
748int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
749 struct kprobe_trace_event **tevs)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400750{
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400751 struct probe_finder pf = {.pev = pev};
752 struct perf_probe_point *pp = &pev->point;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500753 Dwarf_Off off, noff;
754 size_t cuhl;
755 Dwarf_Die *diep;
756 Dwarf *dbg;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400757
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400758 pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES);
759 *tevs = pf.tevs;
760 pf.ntevs = 0;
761
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500762 dbg = dwarf_begin(fd, DWARF_C_READ);
763 if (!dbg)
Masami Hiramatsua225a1d2009-11-03 19:12:30 -0500764 return -ENOENT;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400765
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500766 off = 0;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500767 line_list__init(&pf.lcache);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500768 /* Loop on CUs (Compilation Unit) */
769 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400770 /* Get the DIE(Debugging Information Entry) of this CU */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500771 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
772 if (!diep)
773 continue;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400774
775 /* Check if target file is included. */
776 if (pp->file)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500777 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500778 else
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500779 pf.fname = NULL;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400780
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500781 if (!pp->file || pf.fname) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400782 if (pp->function)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500783 find_probe_point_by_func(&pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500784 else if (pp->lazy_line)
785 find_probe_point_lazy(NULL, &pf);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400786 else {
787 pf.lno = pp->line;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500788 find_probe_point_by_line(&pf);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400789 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400790 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500791 off = noff;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400792 }
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500793 line_list__free(&pf.lcache);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500794 dwarf_end(dbg);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400795
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400796 return pf.ntevs;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400797}
798
Masami Hiramatsufb1587d2010-03-16 18:06:19 -0400799/* Reverse search */
800int find_perf_probe_point(int fd, unsigned long addr,
801 struct perf_probe_point *ppt)
802{
803 Dwarf_Die cudie, spdie, indie;
804 Dwarf *dbg;
805 Dwarf_Line *line;
806 Dwarf_Addr laddr, eaddr;
807 const char *tmp;
808 int lineno, ret = 0;
809
810 dbg = dwarf_begin(fd, DWARF_C_READ);
811 if (!dbg)
812 return -ENOENT;
813
814 /* Find cu die */
815 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie))
816 return -EINVAL;
817
818 /* Find a corresponding line */
819 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
820 if (line) {
821 dwarf_lineaddr(line, &laddr);
822 if ((Dwarf_Addr)addr == laddr) {
823 dwarf_lineno(line, &lineno);
824 ppt->line = lineno;
825
826 tmp = dwarf_linesrc(line, NULL, NULL);
827 DIE_IF(!tmp);
828 ppt->file = xstrdup(tmp);
829 ret = 1;
830 }
831 }
832
833 /* Find a corresponding function */
834 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
835 tmp = dwarf_diename(&spdie);
836 if (!tmp)
837 goto end;
838
839 dwarf_entrypc(&spdie, &eaddr);
840 if (!lineno) {
841 /* We don't have a line number, let's use offset */
842 ppt->function = xstrdup(tmp);
843 ppt->offset = addr - (unsigned long)eaddr;
844 ret = 1;
845 goto end;
846 }
847 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) {
848 /* addr in an inline function */
849 tmp = dwarf_diename(&indie);
850 if (!tmp)
851 goto end;
852 dwarf_decl_line(&indie, &lineno);
853 } else {
854 if (eaddr == addr) /* No offset: function entry */
855 lineno = ppt->line;
856 else
857 dwarf_decl_line(&spdie, &lineno);
858 }
859 ppt->function = xstrdup(tmp);
860 ppt->line -= lineno; /* Make a relative line number */
861 }
862
863end:
864 dwarf_end(dbg);
865 return ret;
866}
867
868
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500869/* Find line range from its line number */
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500870static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500871{
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500872 Dwarf_Lines *lines;
873 Dwarf_Line *line;
874 size_t nlines, i;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500875 Dwarf_Addr addr;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500876 int lineno;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500877 int ret;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500878 const char *src;
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500879 Dwarf_Die die_mem;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500880
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500881 line_list__init(&lf->lr->line_list);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500882 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
883 DIE_IF(ret != 0);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500884
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500885 for (i = 0; i < nlines; i++) {
886 line = dwarf_onesrcline(lines, i);
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500887 ret = dwarf_lineno(line, &lineno);
888 DIE_IF(ret != 0);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500889 if (lf->lno_s > lineno || lf->lno_e < lineno)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500890 continue;
891
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500892 if (sp_die) {
893 /* Address filtering 1: does sp_die include addr? */
894 ret = dwarf_lineaddr(line, &addr);
895 DIE_IF(ret != 0);
896 if (!dwarf_haspc(sp_die, addr))
897 continue;
898
899 /* Address filtering 2: No child include addr? */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400900 if (die_find_inlinefunc(sp_die, addr, &die_mem))
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500901 continue;
902 }
903
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500904 /* TODO: Get fileno from line, but how? */
905 src = dwarf_linesrc(line, NULL, NULL);
906 if (strtailcmp(src, lf->fname) != 0)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500907 continue;
908
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500909 /* Copy real path */
910 if (!lf->lr->path)
Masami Hiramatsu31facc52010-03-16 18:05:30 -0400911 lf->lr->path = xstrdup(src);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500912 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500913 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500914 /* Update status */
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500915 if (!list_empty(&lf->lr->line_list))
916 lf->found = 1;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500917 else {
918 free(lf->lr->path);
919 lf->lr->path = NULL;
920 }
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500921}
922
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500923static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
924{
925 find_line_range_by_line(in_die, (struct line_finder *)data);
926 return DWARF_CB_ABORT; /* No need to find other instances */
927}
928
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500929/* Search function from function name */
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500930static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500931{
932 struct line_finder *lf = (struct line_finder *)data;
933 struct line_range *lr = lf->lr;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500934
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500935 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
936 die_compare_name(sp_die, lr->function) == 0) {
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500937 lf->fname = dwarf_decl_file(sp_die);
938 dwarf_decl_line(sp_die, &lr->offset);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500939 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500940 lf->lno_s = lr->offset + lr->start;
941 if (!lr->end)
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500942 lf->lno_e = INT_MAX;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500943 else
944 lf->lno_e = lr->offset + lr->end;
945 lr->start = lf->lno_s;
946 lr->end = lf->lno_e;
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500947 if (dwarf_func_inline(sp_die))
948 dwarf_func_inline_instances(sp_die,
949 line_range_inline_cb, lf);
950 else
951 find_line_range_by_line(sp_die, lf);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500952 return 1;
953 }
954 return 0;
955}
956
957static void find_line_range_by_func(struct line_finder *lf)
958{
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500959 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500960}
961
962int find_line_range(int fd, struct line_range *lr)
963{
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500964 struct line_finder lf = {.lr = lr, .found = 0};
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500965 int ret;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500966 Dwarf_Off off = 0, noff;
967 size_t cuhl;
968 Dwarf_Die *diep;
969 Dwarf *dbg;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500970
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500971 dbg = dwarf_begin(fd, DWARF_C_READ);
972 if (!dbg)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500973 return -ENOENT;
974
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500975 /* Loop on CUs (Compilation Unit) */
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500976 while (!lf.found) {
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500977 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
978 if (ret != 0)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500979 break;
980
981 /* Get the DIE(Debugging Information Entry) of this CU */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500982 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
983 if (!diep)
984 continue;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500985
986 /* Check if target file is included. */
987 if (lr->file)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500988 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500989 else
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500990 lf.fname = 0;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500991
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500992 if (!lr->file || lf.fname) {
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500993 if (lr->function)
994 find_line_range_by_func(&lf);
995 else {
996 lf.lno_s = lr->start;
997 if (!lr->end)
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500998 lf.lno_e = INT_MAX;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500999 else
1000 lf.lno_e = lr->end;
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001001 find_line_range_by_line(NULL, &lf);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001002 }
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001003 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001004 off = noff;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001005 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001006 pr_debug("path: %lx\n", (unsigned long)lr->path);
1007 dwarf_end(dbg);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001008 return lf.found;
1009}
1010