blob: 3e64e1fa105140fa910987f00324d62c5cdf0c8a [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>
Ian Munsiecd932c52010-04-20 16:58:32 +100034#include <dwarf-regs.h>
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -040035
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -050036#include "string.h"
Masami Hiramatsu89c69c02009-10-16 20:08:10 -040037#include "event.h"
38#include "debug.h"
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -040039#include "util.h"
Chase Douglas9ed7e1b2010-06-14 15:26:30 -040040#include "symbol.h"
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040041#include "probe-finder.h"
42
Masami Hiramatsu49849122010-04-12 13:17:15 -040043/* Kprobe tracer basic type is up to u64 */
44#define MAX_BASIC_TYPE_BITS 64
45
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040046/*
47 * Compare the tail of two strings.
48 * Return 0 if whole of either string is same as another's tail part.
49 */
50static int strtailcmp(const char *s1, const char *s2)
51{
52 int i1 = strlen(s1);
53 int i2 = strlen(s2);
Juha Leppanend56728b2009-12-07 12:00:40 -050054 while (--i1 >= 0 && --i2 >= 0) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040055 if (s1[i1] != s2[i2])
56 return s1[i1] - s2[i2];
57 }
58 return 0;
59}
60
Chase Douglas9ed7e1b2010-06-14 15:26:30 -040061/*
62 * Find a src file from a DWARF tag path. Prepend optional source path prefix
63 * and chop off leading directories that do not exist. Result is passed back as
64 * a newly allocated path on success.
65 * Return 0 if file was found and readable, -errno otherwise.
66 */
67static int get_real_path(const char *raw_path, char **new_path)
68{
69 if (!symbol_conf.source_prefix) {
70 if (access(raw_path, R_OK) == 0) {
71 *new_path = strdup(raw_path);
72 return 0;
73 } else
74 return -errno;
75 }
76
77 *new_path = malloc((strlen(symbol_conf.source_prefix) +
78 strlen(raw_path) + 2));
79 if (!*new_path)
80 return -ENOMEM;
81
82 for (;;) {
83 sprintf(*new_path, "%s/%s", symbol_conf.source_prefix,
84 raw_path);
85
86 if (access(*new_path, R_OK) == 0)
87 return 0;
88
89 switch (errno) {
90 case ENAMETOOLONG:
91 case ENOENT:
92 case EROFS:
93 case EFAULT:
94 raw_path = strchr(++raw_path, '/');
95 if (!raw_path) {
96 free(*new_path);
97 *new_path = NULL;
98 return -ENOENT;
99 }
100 continue;
101
102 default:
103 free(*new_path);
104 *new_path = NULL;
105 return -errno;
106 }
107 }
108}
109
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500110/* Line number list operations */
111
112/* Add a line to line number list */
Masami Hiramatsud3b63d72010-04-14 18:39:42 -0400113static int line_list__add_line(struct list_head *head, int line)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500114{
115 struct line_node *ln;
116 struct list_head *p;
117
118 /* Reverse search, because new line will be the last one */
119 list_for_each_entry_reverse(ln, head, list) {
120 if (ln->line < line) {
121 p = &ln->list;
122 goto found;
123 } else if (ln->line == line) /* Already exist */
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400124 return 1;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500125 }
126 /* List is empty, or the smallest entry */
127 p = head;
128found:
129 pr_debug("line list: add a line %u\n", line);
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400130 ln = zalloc(sizeof(struct line_node));
131 if (ln == NULL)
132 return -ENOMEM;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500133 ln->line = line;
134 INIT_LIST_HEAD(&ln->list);
135 list_add(&ln->list, p);
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400136 return 0;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500137}
138
139/* Check if the line in line number list */
Masami Hiramatsud3b63d72010-04-14 18:39:42 -0400140static int line_list__has_line(struct list_head *head, int line)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500141{
142 struct line_node *ln;
143
144 /* Reverse search, because new line will be the last one */
145 list_for_each_entry(ln, head, list)
146 if (ln->line == line)
147 return 1;
148
149 return 0;
150}
151
152/* Init line number list */
153static void line_list__init(struct list_head *head)
154{
155 INIT_LIST_HEAD(head);
156}
157
158/* Free line number list */
159static void line_list__free(struct list_head *head)
160{
161 struct line_node *ln;
162 while (!list_empty(head)) {
163 ln = list_first_entry(head, struct line_node, list);
164 list_del(&ln->list);
165 free(ln);
166 }
167}
168
169/* Dwarf wrappers */
170
171/* Find the realpath of the target file. */
172static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400173{
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500174 Dwarf_Files *files;
175 size_t nfiles, i;
Arnaldo Carvalho de Meloaccd3cc2010-03-05 12:51:04 -0300176 const char *src = NULL;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400177 int ret;
178
179 if (!fname)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500180 return NULL;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500181
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500182 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500183 if (ret != 0)
184 return NULL;
185
186 for (i = 0; i < nfiles; i++) {
187 src = dwarf_filesrc(files, i, NULL, NULL);
188 if (strtailcmp(src, fname) == 0)
189 break;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500190 }
Masami Hiramatsuc9e38582010-04-02 12:50:45 -0400191 if (i == nfiles)
192 return NULL;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500193 return src;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500194}
195
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400196/* Compare diename and tname */
197static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
198{
199 const char *name;
200 name = dwarf_diename(dw_die);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400201 return name ? strcmp(tname, name) : -1;
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400202}
203
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400204/* Get type die, but skip qualifiers and typedef */
205static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
206{
207 Dwarf_Attribute attr;
208 int tag;
209
210 do {
211 if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
212 dwarf_formref_die(&attr, die_mem) == NULL)
213 return NULL;
214
215 tag = dwarf_tag(die_mem);
216 vr_die = die_mem;
217 } while (tag == DW_TAG_const_type ||
218 tag == DW_TAG_restrict_type ||
219 tag == DW_TAG_volatile_type ||
220 tag == DW_TAG_shared_type ||
221 tag == DW_TAG_typedef);
222
223 return die_mem;
224}
225
Masami Hiramatsu49849122010-04-12 13:17:15 -0400226static bool die_is_signed_type(Dwarf_Die *tp_die)
227{
228 Dwarf_Attribute attr;
229 Dwarf_Word ret;
230
231 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL ||
232 dwarf_formudata(&attr, &ret) != 0)
233 return false;
234
235 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
236 ret == DW_ATE_signed_fixed);
237}
238
239static int die_get_byte_size(Dwarf_Die *tp_die)
240{
241 Dwarf_Attribute attr;
242 Dwarf_Word ret;
243
244 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL ||
245 dwarf_formudata(&attr, &ret) != 0)
246 return 0;
247
248 return (int)ret;
249}
250
Masami Hiramatsude1439d2010-04-14 17:44:00 -0300251/* Get data_member_location offset */
252static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
253{
254 Dwarf_Attribute attr;
255 Dwarf_Op *expr;
256 size_t nexpr;
257 int ret;
258
259 if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
260 return -ENOENT;
261
262 if (dwarf_formudata(&attr, offs) != 0) {
263 /* DW_AT_data_member_location should be DW_OP_plus_uconst */
264 ret = dwarf_getlocation(&attr, &expr, &nexpr);
265 if (ret < 0 || nexpr == 0)
266 return -ENOENT;
267
268 if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
269 pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
270 expr[0].atom, nexpr);
271 return -ENOTSUP;
272 }
273 *offs = (Dwarf_Word)expr[0].number;
274 }
275 return 0;
276}
277
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400278/* Return values for die_find callbacks */
279enum {
280 DIE_FIND_CB_FOUND = 0, /* End of Search */
281 DIE_FIND_CB_CHILD = 1, /* Search only children */
282 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
283 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
284};
285
286/* Search a child die */
287static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
288 int (*callback)(Dwarf_Die *, void *),
289 void *data, Dwarf_Die *die_mem)
290{
291 Dwarf_Die child_die;
292 int ret;
293
294 ret = dwarf_child(rt_die, die_mem);
295 if (ret != 0)
296 return NULL;
297
298 do {
299 ret = callback(die_mem, data);
300 if (ret == DIE_FIND_CB_FOUND)
301 return die_mem;
302
303 if ((ret & DIE_FIND_CB_CHILD) &&
304 die_find_child(die_mem, callback, data, &child_die)) {
305 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
306 return die_mem;
307 }
308 } while ((ret & DIE_FIND_CB_SIBLING) &&
309 dwarf_siblingof(die_mem, die_mem) == 0);
310
311 return NULL;
312}
313
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500314struct __addr_die_search_param {
315 Dwarf_Addr addr;
316 Dwarf_Die *die_mem;
317};
318
319static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
320{
321 struct __addr_die_search_param *ad = data;
322
323 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
324 dwarf_haspc(fn_die, ad->addr)) {
325 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
326 return DWARF_CB_ABORT;
327 }
328 return DWARF_CB_OK;
329}
330
331/* Search a real subprogram including this line, */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400332static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
333 Dwarf_Die *die_mem)
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500334{
335 struct __addr_die_search_param ad;
336 ad.addr = addr;
337 ad.die_mem = die_mem;
338 /* dwarf_getscopes can't find subprogram. */
339 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
340 return NULL;
341 else
342 return die_mem;
343}
344
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400345/* die_find callback for inline function search */
346static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
347{
348 Dwarf_Addr *addr = data;
349
350 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
351 dwarf_haspc(die_mem, *addr))
352 return DIE_FIND_CB_FOUND;
353
354 return DIE_FIND_CB_CONTINUE;
355}
356
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500357/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400358static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
359 Dwarf_Die *die_mem)
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500360{
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400361 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500362}
363
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400364static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400365{
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400366 const char *name = data;
367 int tag;
368
369 tag = dwarf_tag(die_mem);
370 if ((tag == DW_TAG_formal_parameter ||
371 tag == DW_TAG_variable) &&
372 (die_compare_name(die_mem, name) == 0))
373 return DIE_FIND_CB_FOUND;
374
375 return DIE_FIND_CB_CONTINUE;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400376}
377
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400378/* Find a variable called 'name' */
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500379static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
380 Dwarf_Die *die_mem)
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500381{
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400382 return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
383 die_mem);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400384}
385
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400386static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
387{
388 const char *name = data;
389
390 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
391 (die_compare_name(die_mem, name) == 0))
392 return DIE_FIND_CB_FOUND;
393
394 return DIE_FIND_CB_SIBLING;
395}
396
397/* Find a member called 'name' */
398static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
399 Dwarf_Die *die_mem)
400{
401 return die_find_child(st_die, __die_find_member_cb, (void *)name,
402 die_mem);
403}
404
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400405/*
406 * Probe finder related functions
407 */
408
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400409static struct kprobe_trace_arg_ref *alloc_trace_arg_ref(long offs)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400410{
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400411 struct kprobe_trace_arg_ref *ref;
412 ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
413 if (ref != NULL)
414 ref->offset = offs;
415 return ref;
416}
417
418/* Show a location */
419static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
420{
421 Dwarf_Attribute attr;
422 Dwarf_Op *op;
423 size_t nops;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500424 unsigned int regn;
425 Dwarf_Word offs = 0;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400426 bool ref = false;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400427 const char *regs;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400428 struct kprobe_trace_arg *tvar = pf->tvar;
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400429 int ret;
430
431 /* TODO: handle more than 1 exprs */
432 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
433 dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
434 nops == 0) {
435 /* TODO: Support const_value */
436 pr_err("Failed to find the location of %s at this address.\n"
437 " Perhaps, it has been optimized out.\n", pf->pvar->var);
438 return -ENOENT;
439 }
440
441 if (op->atom == DW_OP_addr) {
442 /* Static variables on memory (not stack), make @varname */
443 ret = strlen(dwarf_diename(vr_die));
444 tvar->value = zalloc(ret + 2);
445 if (tvar->value == NULL)
446 return -ENOMEM;
447 snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
448 tvar->ref = alloc_trace_arg_ref((long)offs);
449 if (tvar->ref == NULL)
450 return -ENOMEM;
451 return 0;
452 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400453
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400454 /* If this is based on frame buffer, set the offset */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500455 if (op->atom == DW_OP_fbreg) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400456 if (pf->fb_ops == NULL) {
457 pr_warning("The attribute of frame base is not "
458 "supported.\n");
459 return -ENOTSUP;
460 }
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400461 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500462 offs = op->number;
463 op = &pf->fb_ops[0];
464 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400465
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500466 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
467 regn = op->atom - DW_OP_breg0;
468 offs += op->number;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400469 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500470 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
471 regn = op->atom - DW_OP_reg0;
472 } else if (op->atom == DW_OP_bregx) {
473 regn = op->number;
474 offs += op->number2;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400475 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500476 } else if (op->atom == DW_OP_regx) {
477 regn = op->number;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400478 } else {
479 pr_warning("DW_OP %x is not supported.\n", op->atom);
480 return -ENOTSUP;
481 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400482
483 regs = get_arch_regstr(regn);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400484 if (!regs) {
Ian Munsiecd932c52010-04-20 16:58:32 +1000485 pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400486 return -ERANGE;
487 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400488
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400489 tvar->value = strdup(regs);
490 if (tvar->value == NULL)
491 return -ENOMEM;
492
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400493 if (ref) {
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400494 tvar->ref = alloc_trace_arg_ref((long)offs);
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400495 if (tvar->ref == NULL)
496 return -ENOMEM;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400497 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400498 return 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400499}
500
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400501static int convert_variable_type(Dwarf_Die *vr_die,
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400502 struct kprobe_trace_arg *tvar,
503 const char *cast)
Masami Hiramatsu49849122010-04-12 13:17:15 -0400504{
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400505 struct kprobe_trace_arg_ref **ref_ptr = &tvar->ref;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400506 Dwarf_Die type;
507 char buf[16];
508 int ret;
509
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400510 /* TODO: check all types */
511 if (cast && strcmp(cast, "string") != 0) {
512 /* Non string type is OK */
513 tvar->type = strdup(cast);
514 return (tvar->type == NULL) ? -ENOMEM : 0;
515 }
516
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400517 if (die_get_real_type(vr_die, &type) == NULL) {
518 pr_warning("Failed to get a type information of %s.\n",
519 dwarf_diename(vr_die));
520 return -ENOENT;
521 }
Masami Hiramatsu49849122010-04-12 13:17:15 -0400522
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400523 pr_debug("%s type is %s.\n",
524 dwarf_diename(vr_die), dwarf_diename(&type));
525
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400526 if (cast && strcmp(cast, "string") == 0) { /* String type */
527 ret = dwarf_tag(&type);
528 if (ret != DW_TAG_pointer_type &&
529 ret != DW_TAG_array_type) {
530 pr_warning("Failed to cast into string: "
531 "%s(%s) is not a pointer nor array.",
532 dwarf_diename(vr_die), dwarf_diename(&type));
533 return -EINVAL;
534 }
535 if (ret == DW_TAG_pointer_type) {
536 if (die_get_real_type(&type, &type) == NULL) {
537 pr_warning("Failed to get a type information.");
538 return -ENOENT;
539 }
540 while (*ref_ptr)
541 ref_ptr = &(*ref_ptr)->next;
542 /* Add new reference with offset +0 */
543 *ref_ptr = zalloc(sizeof(struct kprobe_trace_arg_ref));
544 if (*ref_ptr == NULL) {
545 pr_warning("Out of memory error\n");
546 return -ENOMEM;
547 }
548 }
549 if (die_compare_name(&type, "char") != 0 &&
550 die_compare_name(&type, "unsigned char") != 0) {
551 pr_warning("Failed to cast into string: "
552 "%s is not (unsigned) char *.",
553 dwarf_diename(vr_die));
554 return -EINVAL;
555 }
556 tvar->type = strdup(cast);
557 return (tvar->type == NULL) ? -ENOMEM : 0;
558 }
559
Masami Hiramatsu49849122010-04-12 13:17:15 -0400560 ret = die_get_byte_size(&type) * 8;
561 if (ret) {
562 /* Check the bitwidth */
563 if (ret > MAX_BASIC_TYPE_BITS) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400564 pr_info("%s exceeds max-bitwidth."
565 " Cut down to %d bits.\n",
566 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
Masami Hiramatsu49849122010-04-12 13:17:15 -0400567 ret = MAX_BASIC_TYPE_BITS;
568 }
569
570 ret = snprintf(buf, 16, "%c%d",
571 die_is_signed_type(&type) ? 's' : 'u', ret);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400572 if (ret < 0 || ret >= 16) {
573 if (ret >= 16)
574 ret = -E2BIG;
575 pr_warning("Failed to convert variable type: %s\n",
576 strerror(-ret));
577 return ret;
578 }
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400579 tvar->type = strdup(buf);
580 if (tvar->type == NULL)
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400581 return -ENOMEM;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400582 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400583 return 0;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400584}
585
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400586static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400587 struct perf_probe_arg_field *field,
Masami Hiramatsu49849122010-04-12 13:17:15 -0400588 struct kprobe_trace_arg_ref **ref_ptr,
589 Dwarf_Die *die_mem)
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400590{
591 struct kprobe_trace_arg_ref *ref = *ref_ptr;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400592 Dwarf_Die type;
593 Dwarf_Word offs;
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400594 int ret, tag;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400595
596 pr_debug("converting %s in %s\n", field->name, varname);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400597 if (die_get_real_type(vr_die, &type) == NULL) {
598 pr_warning("Failed to get the type of %s.\n", varname);
599 return -ENOENT;
600 }
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400601 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
602 tag = dwarf_tag(&type);
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400603
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400604 if (field->name[0] == '[' &&
605 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
606 if (field->next)
607 /* Save original type for next field */
608 memcpy(die_mem, &type, sizeof(*die_mem));
609 /* Get the type of this array */
610 if (die_get_real_type(&type, &type) == NULL) {
611 pr_warning("Failed to get the type of %s.\n", varname);
612 return -ENOENT;
613 }
614 pr_debug2("Array real type: (%x)\n",
615 (unsigned)dwarf_dieoffset(&type));
616 if (tag == DW_TAG_pointer_type) {
617 ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
618 if (ref == NULL)
619 return -ENOMEM;
620 if (*ref_ptr)
621 (*ref_ptr)->next = ref;
622 else
623 *ref_ptr = ref;
624 }
625 ref->offset += die_get_byte_size(&type) * field->index;
626 if (!field->next)
627 /* Save vr_die for converting types */
628 memcpy(die_mem, vr_die, sizeof(*die_mem));
629 goto next;
630 } else if (tag == DW_TAG_pointer_type) {
631 /* Check the pointer and dereference */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400632 if (!field->ref) {
633 pr_err("Semantic error: %s must be referred by '->'\n",
634 field->name);
635 return -EINVAL;
636 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400637 /* Get the type pointed by this pointer */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400638 if (die_get_real_type(&type, &type) == NULL) {
639 pr_warning("Failed to get the type of %s.\n", varname);
640 return -ENOENT;
641 }
Masami Hiramatsu12e5a7a2010-04-02 12:50:53 -0400642 /* Verify it is a data structure */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400643 if (dwarf_tag(&type) != DW_TAG_structure_type) {
644 pr_warning("%s is not a data structure.\n", varname);
645 return -EINVAL;
646 }
Masami Hiramatsu12e5a7a2010-04-02 12:50:53 -0400647
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400648 ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
649 if (ref == NULL)
650 return -ENOMEM;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400651 if (*ref_ptr)
652 (*ref_ptr)->next = ref;
653 else
654 *ref_ptr = ref;
655 } else {
Masami Hiramatsu12e5a7a2010-04-02 12:50:53 -0400656 /* Verify it is a data structure */
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400657 if (tag != DW_TAG_structure_type) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400658 pr_warning("%s is not a data structure.\n", varname);
659 return -EINVAL;
660 }
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400661 if (field->name[0] == '[') {
662 pr_err("Semantic error: %s is not a pointor nor array.",
663 varname);
664 return -EINVAL;
665 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400666 if (field->ref) {
667 pr_err("Semantic error: %s must be referred by '.'\n",
668 field->name);
669 return -EINVAL;
670 }
671 if (!ref) {
672 pr_warning("Structure on a register is not "
673 "supported yet.\n");
674 return -ENOTSUP;
675 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400676 }
677
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400678 if (die_find_member(&type, field->name, die_mem) == NULL) {
679 pr_warning("%s(tyep:%s) has no member %s.\n", varname,
680 dwarf_diename(&type), field->name);
681 return -EINVAL;
682 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400683
684 /* Get the offset of the field */
Masami Hiramatsude1439d2010-04-14 17:44:00 -0300685 ret = die_get_data_member_location(die_mem, &offs);
686 if (ret < 0) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400687 pr_warning("Failed to get the offset of %s.\n", field->name);
Masami Hiramatsude1439d2010-04-14 17:44:00 -0300688 return ret;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400689 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400690 ref->offset += (long)offs;
691
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400692next:
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400693 /* Converting next field */
694 if (field->next)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400695 return convert_variable_fields(die_mem, field->name,
Masami Hiramatsude1439d2010-04-14 17:44:00 -0300696 field->next, &ref, die_mem);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400697 else
698 return 0;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400699}
700
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400701/* Show a variables in kprobe event format */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400702static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400703{
Masami Hiramatsu49849122010-04-12 13:17:15 -0400704 Dwarf_Die die_mem;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400705 int ret;
706
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400707 pr_debug("Converting variable %s into trace event.\n",
708 dwarf_diename(vr_die));
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500709
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400710 ret = convert_variable_location(vr_die, pf);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400711 if (ret == 0 && pf->pvar->field) {
712 ret = convert_variable_fields(vr_die, pf->pvar->var,
713 pf->pvar->field, &pf->tvar->ref,
714 &die_mem);
Masami Hiramatsu49849122010-04-12 13:17:15 -0400715 vr_die = &die_mem;
716 }
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400717 if (ret == 0)
718 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500719 /* *expr will be cached in libdw. Don't free it. */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400720 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400721}
722
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400723/* Find a variable in a subprogram die */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400724static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400725{
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400726 Dwarf_Die vr_die, *scopes;
Masami Hiramatsu11a1ca32010-04-12 13:17:22 -0400727 char buf[32], *ptr;
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400728 int ret, nscopes;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400729
Masami Hiramatsu48481932010-04-12 13:16:53 -0400730 if (pf->pvar->name)
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400731 pf->tvar->name = strdup(pf->pvar->name);
Masami Hiramatsu48481932010-04-12 13:16:53 -0400732 else {
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400733 ret = synthesize_perf_probe_arg(pf->pvar, buf, 32);
734 if (ret < 0)
735 return ret;
Masami Hiramatsu11a1ca32010-04-12 13:17:22 -0400736 ptr = strchr(buf, ':'); /* Change type separator to _ */
737 if (ptr)
738 *ptr = '_';
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400739 pf->tvar->name = strdup(buf);
Masami Hiramatsu48481932010-04-12 13:16:53 -0400740 }
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400741 if (pf->tvar->name == NULL)
742 return -ENOMEM;
Masami Hiramatsu48481932010-04-12 13:16:53 -0400743
744 if (!is_c_varname(pf->pvar->var)) {
745 /* Copy raw parameters */
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400746 pf->tvar->value = strdup(pf->pvar->var);
747 if (pf->tvar->value == NULL)
748 return -ENOMEM;
749 else
750 return 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400751 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400752
753 pr_debug("Searching '%s' variable in context.\n",
754 pf->pvar->var);
755 /* Search child die for local variables and parameters. */
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400756 if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
757 ret = convert_variable(&vr_die, pf);
758 else {
759 /* Search upper class */
760 nscopes = dwarf_getscopes_die(sp_die, &scopes);
761 if (nscopes > 0) {
762 ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
763 0, NULL, 0, 0, &vr_die);
764 if (ret >= 0)
765 ret = convert_variable(&vr_die, pf);
766 else
767 ret = -ENOENT;
768 free(scopes);
769 } else
770 ret = -ENOENT;
771 }
772 if (ret < 0)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400773 pr_warning("Failed to find '%s' in this function.\n",
774 pf->pvar->var);
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400775 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400776}
777
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400778/* Show a probe point to output buffer */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400779static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400780{
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400781 struct kprobe_trace_event *tev;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500782 Dwarf_Addr eaddr;
783 Dwarf_Die die_mem;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500784 const char *name;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400785 int ret, i;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500786 Dwarf_Attribute fb_attr;
787 size_t nops;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400788
Masami Hiramatsuef4a3562010-04-21 15:56:40 -0400789 if (pf->ntevs == pf->max_tevs) {
790 pr_warning("Too many( > %d) probe point found.\n",
791 pf->max_tevs);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400792 return -ERANGE;
793 }
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400794 tev = &pf->tevs[pf->ntevs++];
795
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500796 /* If no real subprogram, find a real one */
797 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400798 sp_die = die_find_real_subprogram(&pf->cu_die,
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500799 pf->addr, &die_mem);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400800 if (!sp_die) {
801 pr_warning("Failed to find probe point in any "
802 "functions.\n");
803 return -ENOENT;
804 }
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500805 }
806
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400807 /* Copy the name of probe point */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500808 name = dwarf_diename(sp_die);
809 if (name) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400810 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
811 pr_warning("Failed to get entry pc of %s\n",
812 dwarf_diename(sp_die));
813 return -ENOENT;
814 }
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400815 tev->point.symbol = strdup(name);
816 if (tev->point.symbol == NULL)
817 return -ENOMEM;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400818 tev->point.offset = (unsigned long)(pf->addr - eaddr);
819 } else
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400820 /* This function has no name. */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400821 tev->point.offset = (unsigned long)pf->addr;
822
823 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
824 tev->point.offset);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400825
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500826 /* Get the frame base attribute/ops */
827 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
Masami Hiramatsud0cb4260f2010-03-15 13:02:35 -0400828 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
Masami Hiramatsua34a9852010-04-12 13:17:29 -0400829 if (ret <= 0 || nops == 0) {
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500830 pf->fb_ops = NULL;
Masami Hiramatsu7752f1b2010-05-10 13:12:07 -0400831#if _ELFUTILS_PREREQ(0, 142)
Masami Hiramatsua34a9852010-04-12 13:17:29 -0400832 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
833 pf->cfi != NULL) {
834 Dwarf_Frame *frame;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400835 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
836 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
837 pr_warning("Failed to get CFA on 0x%jx\n",
838 (uintmax_t)pf->addr);
839 return -ENOENT;
840 }
Masami Hiramatsu7752f1b2010-05-10 13:12:07 -0400841#endif
Masami Hiramatsua34a9852010-04-12 13:17:29 -0400842 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500843
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400844 /* Find each argument */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400845 tev->nargs = pf->pev->nargs;
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400846 tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
847 if (tev->args == NULL)
848 return -ENOMEM;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400849 for (i = 0; i < pf->pev->nargs; i++) {
850 pf->pvar = &pf->pev->args[i];
851 pf->tvar = &tev->args[i];
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400852 ret = find_variable(sp_die, pf);
853 if (ret != 0)
854 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400855 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500856
857 /* *pf->fb_ops will be cached in libdw. Don't free it. */
858 pf->fb_ops = NULL;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400859 return 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400860}
861
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400862/* Find probe point from its line number */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400863static int find_probe_point_by_line(struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400864{
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500865 Dwarf_Lines *lines;
866 Dwarf_Line *line;
867 size_t nlines, i;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500868 Dwarf_Addr addr;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500869 int lineno;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400870 int ret = 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400871
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400872 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
873 pr_warning("No source lines found in this CU.\n");
874 return -ENOENT;
875 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400876
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400877 for (i = 0; i < nlines && ret == 0; i++) {
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500878 line = dwarf_onesrcline(lines, i);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400879 if (dwarf_lineno(line, &lineno) != 0 ||
880 lineno != pf->lno)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400881 continue;
882
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500883 /* TODO: Get fileno from line, but how? */
884 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
885 continue;
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400886
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400887 if (dwarf_lineaddr(line, &addr) != 0) {
888 pr_warning("Failed to get the address of the line.\n");
889 return -ENOENT;
890 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500891 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
892 (int)i, lineno, (uintmax_t)addr);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400893 pf->addr = addr;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500894
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400895 ret = convert_probe_point(NULL, pf);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400896 /* Continuing, because target line might be inlined. */
897 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400898 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400899}
900
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500901/* Find lines which match lazy pattern */
902static int find_lazy_match_lines(struct list_head *head,
903 const char *fname, const char *pat)
904{
905 char *fbuf, *p1, *p2;
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300906 int fd, line, nlines = -1;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500907 struct stat st;
908
909 fd = open(fname, O_RDONLY);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400910 if (fd < 0) {
911 pr_warning("Failed to open %s: %s\n", fname, strerror(-fd));
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300912 return -errno;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400913 }
914
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300915 if (fstat(fd, &st) < 0) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400916 pr_warning("Failed to get the size of %s: %s\n",
917 fname, strerror(errno));
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300918 nlines = -errno;
919 goto out_close;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400920 }
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300921
922 nlines = -ENOMEM;
923 fbuf = malloc(st.st_size + 2);
924 if (fbuf == NULL)
925 goto out_close;
926 if (read(fd, fbuf, st.st_size) < 0) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400927 pr_warning("Failed to read %s: %s\n", fname, strerror(errno));
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300928 nlines = -errno;
929 goto out_free_fbuf;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400930 }
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500931 fbuf[st.st_size] = '\n'; /* Dummy line */
932 fbuf[st.st_size + 1] = '\0';
933 p1 = fbuf;
934 line = 1;
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300935 nlines = 0;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500936 while ((p2 = strchr(p1, '\n')) != NULL) {
937 *p2 = '\0';
938 if (strlazymatch(p1, pat)) {
939 line_list__add_line(head, line);
940 nlines++;
941 }
942 line++;
943 p1 = p2 + 1;
944 }
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300945out_free_fbuf:
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500946 free(fbuf);
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300947out_close:
948 close(fd);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500949 return nlines;
950}
951
952/* Find probe points from lazy pattern */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400953static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500954{
955 Dwarf_Lines *lines;
956 Dwarf_Line *line;
957 size_t nlines, i;
958 Dwarf_Addr addr;
959 Dwarf_Die die_mem;
960 int lineno;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400961 int ret = 0;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500962
963 if (list_empty(&pf->lcache)) {
964 /* Matching lazy line pattern */
965 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400966 pf->pev->point.lazy_line);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400967 if (ret == 0) {
968 pr_debug("No matched lines found in %s.\n", pf->fname);
969 return 0;
970 } else if (ret < 0)
971 return ret;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500972 }
973
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400974 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
975 pr_warning("No source lines found in this CU.\n");
976 return -ENOENT;
977 }
978
979 for (i = 0; i < nlines && ret >= 0; i++) {
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500980 line = dwarf_onesrcline(lines, i);
981
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400982 if (dwarf_lineno(line, &lineno) != 0 ||
983 !line_list__has_line(&pf->lcache, lineno))
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500984 continue;
985
986 /* TODO: Get fileno from line, but how? */
987 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
988 continue;
989
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400990 if (dwarf_lineaddr(line, &addr) != 0) {
991 pr_debug("Failed to get the address of line %d.\n",
992 lineno);
993 continue;
994 }
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500995 if (sp_die) {
996 /* Address filtering 1: does sp_die include addr? */
997 if (!dwarf_haspc(sp_die, addr))
998 continue;
999 /* Address filtering 2: No child include addr? */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -04001000 if (die_find_inlinefunc(sp_die, addr, &die_mem))
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001001 continue;
1002 }
1003
1004 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
1005 (int)i, lineno, (unsigned long long)addr);
1006 pf->addr = addr;
1007
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001008 ret = convert_probe_point(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001009 /* Continuing, because target line might be inlined. */
1010 }
1011 /* TODO: deallocate lines, but how? */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001012 return ret;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001013}
1014
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001015/* Callback parameter with return value */
1016struct dwarf_callback_param {
1017 void *data;
1018 int retval;
1019};
1020
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001021static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001022{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001023 struct dwarf_callback_param *param = data;
1024 struct probe_finder *pf = param->data;
Masami Hiramatsu4235b042010-03-16 18:06:12 -04001025 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001026 Dwarf_Addr addr;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001027
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001028 if (pp->lazy_line)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001029 param->retval = find_probe_point_lazy(in_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001030 else {
1031 /* Get probe address */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001032 if (dwarf_entrypc(in_die, &addr) != 0) {
1033 pr_warning("Failed to get entry pc of %s.\n",
1034 dwarf_diename(in_die));
1035 param->retval = -ENOENT;
1036 return DWARF_CB_ABORT;
1037 }
1038 pf->addr = addr;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001039 pf->addr += pp->offset;
1040 pr_debug("found inline addr: 0x%jx\n",
1041 (uintmax_t)pf->addr);
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001042
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001043 param->retval = convert_probe_point(in_die, pf);
Masami Hiramatsu5d1ee042010-04-21 15:56:32 -04001044 if (param->retval < 0)
1045 return DWARF_CB_ABORT;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001046 }
1047
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001048 return DWARF_CB_OK;
1049}
1050
1051/* Search function from function name */
1052static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1053{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001054 struct dwarf_callback_param *param = data;
1055 struct probe_finder *pf = param->data;
Masami Hiramatsu4235b042010-03-16 18:06:12 -04001056 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001057
1058 /* Check tag and diename */
1059 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
1060 die_compare_name(sp_die, pp->function) != 0)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001061 return DWARF_CB_OK;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001062
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001063 pf->fname = dwarf_decl_file(sp_die);
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001064 if (pp->line) { /* Function relative line */
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001065 dwarf_decl_line(sp_die, &pf->lno);
1066 pf->lno += pp->line;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001067 param->retval = find_probe_point_by_line(pf);
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001068 } else if (!dwarf_func_inline(sp_die)) {
1069 /* Real function */
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001070 if (pp->lazy_line)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001071 param->retval = find_probe_point_lazy(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001072 else {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001073 if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
1074 pr_warning("Failed to get entry pc of %s.\n",
1075 dwarf_diename(sp_die));
1076 param->retval = -ENOENT;
1077 return DWARF_CB_ABORT;
1078 }
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001079 pf->addr += pp->offset;
1080 /* TODO: Check the address in this function */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001081 param->retval = convert_probe_point(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001082 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001083 } else {
1084 struct dwarf_callback_param _param = {.data = (void *)pf,
1085 .retval = 0};
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001086 /* Inlined function: search instances */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001087 dwarf_func_inline_instances(sp_die, probe_point_inline_cb,
1088 &_param);
1089 param->retval = _param.retval;
1090 }
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001091
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001092 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001093}
1094
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001095static int find_probe_point_by_func(struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001096{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001097 struct dwarf_callback_param _param = {.data = (void *)pf,
1098 .retval = 0};
1099 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0);
1100 return _param.retval;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001101}
1102
Masami Hiramatsu4235b042010-03-16 18:06:12 -04001103/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
1104int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
Masami Hiramatsuef4a3562010-04-21 15:56:40 -04001105 struct kprobe_trace_event **tevs, int max_tevs)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001106{
Masami Hiramatsuef4a3562010-04-21 15:56:40 -04001107 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
Masami Hiramatsu4235b042010-03-16 18:06:12 -04001108 struct perf_probe_point *pp = &pev->point;
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001109 Dwarf_Off off, noff;
1110 size_t cuhl;
1111 Dwarf_Die *diep;
1112 Dwarf *dbg;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001113 int ret = 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001114
Masami Hiramatsuef4a3562010-04-21 15:56:40 -04001115 pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * max_tevs);
Masami Hiramatsue334016f12010-04-12 13:17:49 -04001116 if (pf.tevs == NULL)
1117 return -ENOMEM;
Masami Hiramatsu4235b042010-03-16 18:06:12 -04001118 *tevs = pf.tevs;
1119 pf.ntevs = 0;
1120
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001121 dbg = dwarf_begin(fd, DWARF_C_READ);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001122 if (!dbg) {
1123 pr_warning("No dwarf info found in the vmlinux - "
1124 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -03001125 free(pf.tevs);
1126 *tevs = NULL;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001127 return -EBADF;
1128 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001129
Masami Hiramatsu7752f1b2010-05-10 13:12:07 -04001130#if _ELFUTILS_PREREQ(0, 142)
Masami Hiramatsua34a9852010-04-12 13:17:29 -04001131 /* Get the call frame information from this dwarf */
1132 pf.cfi = dwarf_getcfi(dbg);
Masami Hiramatsu7752f1b2010-05-10 13:12:07 -04001133#endif
Masami Hiramatsua34a9852010-04-12 13:17:29 -04001134
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001135 off = 0;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001136 line_list__init(&pf.lcache);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001137 /* Loop on CUs (Compilation Unit) */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001138 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
1139 ret >= 0) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001140 /* Get the DIE(Debugging Information Entry) of this CU */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001141 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
1142 if (!diep)
1143 continue;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001144
1145 /* Check if target file is included. */
1146 if (pp->file)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001147 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001148 else
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001149 pf.fname = NULL;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001150
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001151 if (!pp->file || pf.fname) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001152 if (pp->function)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001153 ret = find_probe_point_by_func(&pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001154 else if (pp->lazy_line)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001155 ret = find_probe_point_lazy(NULL, &pf);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -04001156 else {
1157 pf.lno = pp->line;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001158 ret = find_probe_point_by_line(&pf);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -04001159 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001160 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001161 off = noff;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001162 }
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001163 line_list__free(&pf.lcache);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001164 dwarf_end(dbg);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001165
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001166 return (ret < 0) ? ret : pf.ntevs;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001167}
1168
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001169/* Reverse search */
1170int find_perf_probe_point(int fd, unsigned long addr,
1171 struct perf_probe_point *ppt)
1172{
1173 Dwarf_Die cudie, spdie, indie;
1174 Dwarf *dbg;
1175 Dwarf_Line *line;
1176 Dwarf_Addr laddr, eaddr;
1177 const char *tmp;
1178 int lineno, ret = 0;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001179 bool found = false;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001180
1181 dbg = dwarf_begin(fd, DWARF_C_READ);
1182 if (!dbg)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001183 return -EBADF;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001184
1185 /* Find cu die */
Masami Hiramatsu75ec5a22010-04-02 12:50:59 -04001186 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {
1187 ret = -EINVAL;
1188 goto end;
1189 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001190
1191 /* Find a corresponding line */
1192 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
1193 if (line) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001194 if (dwarf_lineaddr(line, &laddr) == 0 &&
1195 (Dwarf_Addr)addr == laddr &&
1196 dwarf_lineno(line, &lineno) == 0) {
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001197 tmp = dwarf_linesrc(line, NULL, NULL);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001198 if (tmp) {
1199 ppt->line = lineno;
Masami Hiramatsu02b95da2010-04-12 13:17:56 -04001200 ppt->file = strdup(tmp);
1201 if (ppt->file == NULL) {
1202 ret = -ENOMEM;
1203 goto end;
1204 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001205 found = true;
1206 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001207 }
1208 }
1209
1210 /* Find a corresponding function */
1211 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
1212 tmp = dwarf_diename(&spdie);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001213 if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0)
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001214 goto end;
1215
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001216 if (ppt->line) {
1217 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
1218 &indie)) {
1219 /* addr in an inline function */
1220 tmp = dwarf_diename(&indie);
1221 if (!tmp)
1222 goto end;
1223 ret = dwarf_decl_line(&indie, &lineno);
1224 } else {
1225 if (eaddr == addr) { /* Function entry */
1226 lineno = ppt->line;
1227 ret = 0;
1228 } else
1229 ret = dwarf_decl_line(&spdie, &lineno);
1230 }
1231 if (ret == 0) {
1232 /* Make a relative line number */
1233 ppt->line -= lineno;
1234 goto found;
1235 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001236 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001237 /* We don't have a line number, let's use offset */
1238 ppt->offset = addr - (unsigned long)eaddr;
1239found:
Masami Hiramatsu02b95da2010-04-12 13:17:56 -04001240 ppt->function = strdup(tmp);
1241 if (ppt->function == NULL) {
1242 ret = -ENOMEM;
1243 goto end;
1244 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001245 found = true;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001246 }
1247
1248end:
1249 dwarf_end(dbg);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001250 if (ret >= 0)
1251 ret = found ? 1 : 0;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001252 return ret;
1253}
1254
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001255/* Add a line and store the src path */
1256static int line_range_add_line(const char *src, unsigned int lineno,
1257 struct line_range *lr)
1258{
Chase Douglas9ed7e1b2010-06-14 15:26:30 -04001259 int ret;
1260
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001261 /* Copy real path */
1262 if (!lr->path) {
Chase Douglas9ed7e1b2010-06-14 15:26:30 -04001263 ret = get_real_path(src, &lr->path);
1264 if (ret != 0)
1265 return ret;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001266 }
1267 return line_list__add_line(&lr->line_list, lineno);
1268}
1269
1270/* Search function declaration lines */
1271static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
1272{
1273 struct dwarf_callback_param *param = data;
1274 struct line_finder *lf = param->data;
1275 const char *src;
1276 int lineno;
1277
1278 src = dwarf_decl_file(sp_die);
1279 if (src && strtailcmp(src, lf->fname) != 0)
1280 return DWARF_CB_OK;
1281
1282 if (dwarf_decl_line(sp_die, &lineno) != 0 ||
1283 (lf->lno_s > lineno || lf->lno_e < lineno))
1284 return DWARF_CB_OK;
1285
1286 param->retval = line_range_add_line(src, lineno, lf->lr);
Masami Hiramatsu5d1ee042010-04-21 15:56:32 -04001287 if (param->retval < 0)
1288 return DWARF_CB_ABORT;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001289 return DWARF_CB_OK;
1290}
1291
1292static int find_line_range_func_decl_lines(struct line_finder *lf)
1293{
1294 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1295 dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
1296 return param.retval;
1297}
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001298
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001299/* Find line range from its line number */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001300static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001301{
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001302 Dwarf_Lines *lines;
1303 Dwarf_Line *line;
1304 size_t nlines, i;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001305 Dwarf_Addr addr;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001306 int lineno, ret = 0;
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001307 const char *src;
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001308 Dwarf_Die die_mem;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001309
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001310 line_list__init(&lf->lr->line_list);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001311 if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
1312 pr_warning("No source lines found in this CU.\n");
1313 return -ENOENT;
1314 }
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001315
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001316 /* Search probable lines on lines list */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001317 for (i = 0; i < nlines; i++) {
1318 line = dwarf_onesrcline(lines, i);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001319 if (dwarf_lineno(line, &lineno) != 0 ||
1320 (lf->lno_s > lineno || lf->lno_e < lineno))
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001321 continue;
1322
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001323 if (sp_die) {
1324 /* Address filtering 1: does sp_die include addr? */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001325 if (dwarf_lineaddr(line, &addr) != 0 ||
1326 !dwarf_haspc(sp_die, addr))
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001327 continue;
1328
1329 /* Address filtering 2: No child include addr? */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -04001330 if (die_find_inlinefunc(sp_die, addr, &die_mem))
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001331 continue;
1332 }
1333
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001334 /* TODO: Get fileno from line, but how? */
1335 src = dwarf_linesrc(line, NULL, NULL);
1336 if (strtailcmp(src, lf->fname) != 0)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001337 continue;
1338
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001339 ret = line_range_add_line(src, lineno, lf->lr);
1340 if (ret < 0)
1341 return ret;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001342 }
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001343
1344 /*
1345 * Dwarf lines doesn't include function declarations. We have to
1346 * check functions list or given function.
1347 */
1348 if (sp_die) {
1349 src = dwarf_decl_file(sp_die);
1350 if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
1351 (lf->lno_s <= lineno && lf->lno_e >= lineno))
1352 ret = line_range_add_line(src, lineno, lf->lr);
1353 } else
1354 ret = find_line_range_func_decl_lines(lf);
1355
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001356 /* Update status */
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001357 if (ret >= 0)
1358 if (!list_empty(&lf->lr->line_list))
1359 ret = lf->found = 1;
1360 else
1361 ret = 0; /* Lines are not found */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001362 else {
1363 free(lf->lr->path);
1364 lf->lr->path = NULL;
1365 }
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001366 return ret;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001367}
1368
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001369static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1370{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001371 struct dwarf_callback_param *param = data;
1372
1373 param->retval = find_line_range_by_line(in_die, param->data);
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001374 return DWARF_CB_ABORT; /* No need to find other instances */
1375}
1376
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001377/* Search function from function name */
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001378static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001379{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001380 struct dwarf_callback_param *param = data;
1381 struct line_finder *lf = param->data;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001382 struct line_range *lr = lf->lr;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001383
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001384 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1385 die_compare_name(sp_die, lr->function) == 0) {
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001386 lf->fname = dwarf_decl_file(sp_die);
1387 dwarf_decl_line(sp_die, &lr->offset);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001388 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001389 lf->lno_s = lr->offset + lr->start;
Masami Hiramatsud3b63d72010-04-14 18:39:42 -04001390 if (lf->lno_s < 0) /* Overflow */
1391 lf->lno_s = INT_MAX;
1392 lf->lno_e = lr->offset + lr->end;
1393 if (lf->lno_e < 0) /* Overflow */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001394 lf->lno_e = INT_MAX;
Masami Hiramatsud3b63d72010-04-14 18:39:42 -04001395 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001396 lr->start = lf->lno_s;
1397 lr->end = lf->lno_e;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001398 if (dwarf_func_inline(sp_die)) {
1399 struct dwarf_callback_param _param;
1400 _param.data = (void *)lf;
1401 _param.retval = 0;
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001402 dwarf_func_inline_instances(sp_die,
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001403 line_range_inline_cb,
1404 &_param);
1405 param->retval = _param.retval;
1406 } else
1407 param->retval = find_line_range_by_line(sp_die, lf);
1408 return DWARF_CB_ABORT;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001409 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001410 return DWARF_CB_OK;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001411}
1412
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001413static int find_line_range_by_func(struct line_finder *lf)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001414{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001415 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1416 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, &param, 0);
1417 return param.retval;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001418}
1419
1420int find_line_range(int fd, struct line_range *lr)
1421{
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001422 struct line_finder lf = {.lr = lr, .found = 0};
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001423 int ret = 0;
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001424 Dwarf_Off off = 0, noff;
1425 size_t cuhl;
1426 Dwarf_Die *diep;
1427 Dwarf *dbg;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001428
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001429 dbg = dwarf_begin(fd, DWARF_C_READ);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001430 if (!dbg) {
1431 pr_warning("No dwarf info found in the vmlinux - "
1432 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1433 return -EBADF;
1434 }
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001435
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001436 /* Loop on CUs (Compilation Unit) */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001437 while (!lf.found && ret >= 0) {
1438 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001439 break;
1440
1441 /* Get the DIE(Debugging Information Entry) of this CU */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001442 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
1443 if (!diep)
1444 continue;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001445
1446 /* Check if target file is included. */
1447 if (lr->file)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001448 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001449 else
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001450 lf.fname = 0;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001451
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001452 if (!lr->file || lf.fname) {
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001453 if (lr->function)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001454 ret = find_line_range_by_func(&lf);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001455 else {
1456 lf.lno_s = lr->start;
Masami Hiramatsud3b63d72010-04-14 18:39:42 -04001457 lf.lno_e = lr->end;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001458 ret = find_line_range_by_line(NULL, &lf);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001459 }
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001460 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001461 off = noff;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001462 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001463 pr_debug("path: %lx\n", (unsigned long)lr->path);
1464 dwarf_end(dbg);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001465
1466 return (ret < 0) ? ret : lf.found;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001467}
1468