blob: c6fe80ebb262bca1ce6c6d296d51f29e4c82aa37 [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 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"
Chase Douglas9ed7e1b2010-06-14 15:26:30 -040039#include "symbol.h"
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040040#include "probe-finder.h"
41
Masami Hiramatsu49849122010-04-12 13:17:15 -040042/* Kprobe tracer basic type is up to u64 */
43#define MAX_BASIC_TYPE_BITS 64
44
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040045/*
46 * Compare the tail of two strings.
47 * Return 0 if whole of either string is same as another's tail part.
48 */
49static int strtailcmp(const char *s1, const char *s2)
50{
51 int i1 = strlen(s1);
52 int i2 = strlen(s2);
Juha Leppanend56728b2009-12-07 12:00:40 -050053 while (--i1 >= 0 && --i2 >= 0) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040054 if (s1[i1] != s2[i2])
55 return s1[i1] - s2[i2];
56 }
57 return 0;
58}
59
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -050060/* Line number list operations */
61
62/* Add a line to line number list */
Masami Hiramatsud3b63d72010-04-14 18:39:42 -040063static int line_list__add_line(struct list_head *head, int line)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -050064{
65 struct line_node *ln;
66 struct list_head *p;
67
68 /* Reverse search, because new line will be the last one */
69 list_for_each_entry_reverse(ln, head, list) {
70 if (ln->line < line) {
71 p = &ln->list;
72 goto found;
73 } else if (ln->line == line) /* Already exist */
Masami Hiramatsue334016f12010-04-12 13:17:49 -040074 return 1;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -050075 }
76 /* List is empty, or the smallest entry */
77 p = head;
78found:
79 pr_debug("line list: add a line %u\n", line);
Masami Hiramatsue334016f12010-04-12 13:17:49 -040080 ln = zalloc(sizeof(struct line_node));
81 if (ln == NULL)
82 return -ENOMEM;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -050083 ln->line = line;
84 INIT_LIST_HEAD(&ln->list);
85 list_add(&ln->list, p);
Masami Hiramatsue334016f12010-04-12 13:17:49 -040086 return 0;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -050087}
88
89/* Check if the line in line number list */
Masami Hiramatsud3b63d72010-04-14 18:39:42 -040090static int line_list__has_line(struct list_head *head, int line)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -050091{
92 struct line_node *ln;
93
94 /* Reverse search, because new line will be the last one */
95 list_for_each_entry(ln, head, list)
96 if (ln->line == line)
97 return 1;
98
99 return 0;
100}
101
102/* Init line number list */
103static void line_list__init(struct list_head *head)
104{
105 INIT_LIST_HEAD(head);
106}
107
108/* Free line number list */
109static void line_list__free(struct list_head *head)
110{
111 struct line_node *ln;
112 while (!list_empty(head)) {
113 ln = list_first_entry(head, struct line_node, list);
114 list_del(&ln->list);
115 free(ln);
116 }
117}
118
119/* Dwarf wrappers */
120
121/* Find the realpath of the target file. */
122static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400123{
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500124 Dwarf_Files *files;
125 size_t nfiles, i;
Arnaldo Carvalho de Meloaccd3cc2010-03-05 12:51:04 -0300126 const char *src = NULL;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400127 int ret;
128
129 if (!fname)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500130 return NULL;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500131
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500132 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500133 if (ret != 0)
134 return NULL;
135
136 for (i = 0; i < nfiles; i++) {
137 src = dwarf_filesrc(files, i, NULL, NULL);
138 if (strtailcmp(src, fname) == 0)
139 break;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500140 }
Masami Hiramatsuc9e38582010-04-02 12:50:45 -0400141 if (i == nfiles)
142 return NULL;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500143 return src;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -0500144}
145
Masami Hiramatsu6a330a32010-07-09 18:29:11 +0900146/* Get DW_AT_comp_dir (should be NULL with older gcc) */
147static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
148{
149 Dwarf_Attribute attr;
150 if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
151 return NULL;
152 return dwarf_formstring(&attr);
153}
154
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400155/* Compare diename and tname */
156static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
157{
158 const char *name;
159 name = dwarf_diename(dw_die);
Masami Hiramatsu82175632010-07-09 18:29:17 +0900160 return name ? (strcmp(tname, name) == 0) : false;
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400161}
162
Masami Hiramatsu4046b8b2010-10-21 19:13:02 +0900163/* Get type die */
164static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
165{
166 Dwarf_Attribute attr;
167
168 if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
169 dwarf_formref_die(&attr, die_mem))
170 return die_mem;
171 else
172 return NULL;
173}
174
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400175/* Get type die, but skip qualifiers and typedef */
176static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
177{
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400178 int tag;
179
180 do {
Masami Hiramatsu4046b8b2010-10-21 19:13:02 +0900181 vr_die = die_get_type(vr_die, die_mem);
182 if (!vr_die)
183 break;
184 tag = dwarf_tag(vr_die);
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400185 } while (tag == DW_TAG_const_type ||
186 tag == DW_TAG_restrict_type ||
187 tag == DW_TAG_volatile_type ||
188 tag == DW_TAG_shared_type ||
189 tag == DW_TAG_typedef);
190
Masami Hiramatsu4046b8b2010-10-21 19:13:02 +0900191 return vr_die;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400192}
193
Masami Hiramatsu49849122010-04-12 13:17:15 -0400194static bool die_is_signed_type(Dwarf_Die *tp_die)
195{
196 Dwarf_Attribute attr;
197 Dwarf_Word ret;
198
199 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL ||
200 dwarf_formudata(&attr, &ret) != 0)
201 return false;
202
203 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
204 ret == DW_ATE_signed_fixed);
205}
206
207static int die_get_byte_size(Dwarf_Die *tp_die)
208{
209 Dwarf_Attribute attr;
210 Dwarf_Word ret;
211
212 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL ||
213 dwarf_formudata(&attr, &ret) != 0)
214 return 0;
215
216 return (int)ret;
217}
218
Masami Hiramatsude1439d2010-04-14 17:44:00 -0300219/* Get data_member_location offset */
220static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
221{
222 Dwarf_Attribute attr;
223 Dwarf_Op *expr;
224 size_t nexpr;
225 int ret;
226
227 if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
228 return -ENOENT;
229
230 if (dwarf_formudata(&attr, offs) != 0) {
231 /* DW_AT_data_member_location should be DW_OP_plus_uconst */
232 ret = dwarf_getlocation(&attr, &expr, &nexpr);
233 if (ret < 0 || nexpr == 0)
234 return -ENOENT;
235
236 if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
237 pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
238 expr[0].atom, nexpr);
239 return -ENOTSUP;
240 }
241 *offs = (Dwarf_Word)expr[0].number;
242 }
243 return 0;
244}
245
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400246/* Return values for die_find callbacks */
247enum {
248 DIE_FIND_CB_FOUND = 0, /* End of Search */
249 DIE_FIND_CB_CHILD = 1, /* Search only children */
250 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
251 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
252};
253
254/* Search a child die */
255static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
256 int (*callback)(Dwarf_Die *, void *),
257 void *data, Dwarf_Die *die_mem)
258{
259 Dwarf_Die child_die;
260 int ret;
261
262 ret = dwarf_child(rt_die, die_mem);
263 if (ret != 0)
264 return NULL;
265
266 do {
267 ret = callback(die_mem, data);
268 if (ret == DIE_FIND_CB_FOUND)
269 return die_mem;
270
271 if ((ret & DIE_FIND_CB_CHILD) &&
272 die_find_child(die_mem, callback, data, &child_die)) {
273 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
274 return die_mem;
275 }
276 } while ((ret & DIE_FIND_CB_SIBLING) &&
277 dwarf_siblingof(die_mem, die_mem) == 0);
278
279 return NULL;
280}
281
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500282struct __addr_die_search_param {
283 Dwarf_Addr addr;
284 Dwarf_Die *die_mem;
285};
286
287static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
288{
289 struct __addr_die_search_param *ad = data;
290
291 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
292 dwarf_haspc(fn_die, ad->addr)) {
293 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
294 return DWARF_CB_ABORT;
295 }
296 return DWARF_CB_OK;
297}
298
299/* Search a real subprogram including this line, */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400300static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
301 Dwarf_Die *die_mem)
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500302{
303 struct __addr_die_search_param ad;
304 ad.addr = addr;
305 ad.die_mem = die_mem;
306 /* dwarf_getscopes can't find subprogram. */
307 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
308 return NULL;
309 else
310 return die_mem;
311}
312
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400313/* die_find callback for inline function search */
314static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
315{
316 Dwarf_Addr *addr = data;
317
318 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
319 dwarf_haspc(die_mem, *addr))
320 return DIE_FIND_CB_FOUND;
321
322 return DIE_FIND_CB_CONTINUE;
323}
324
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500325/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400326static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
327 Dwarf_Die *die_mem)
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500328{
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400329 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
Masami Hiramatsu161a26b2010-02-25 08:35:57 -0500330}
331
Masami Hiramatsu378eeaa2010-10-21 19:13:09 +0900332struct __find_variable_param {
333 const char *name;
334 Dwarf_Addr addr;
335};
336
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400337static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400338{
Masami Hiramatsu378eeaa2010-10-21 19:13:09 +0900339 struct __find_variable_param *fvp = data;
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400340 int tag;
341
342 tag = dwarf_tag(die_mem);
343 if ((tag == DW_TAG_formal_parameter ||
344 tag == DW_TAG_variable) &&
Masami Hiramatsu378eeaa2010-10-21 19:13:09 +0900345 die_compare_name(die_mem, fvp->name))
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400346 return DIE_FIND_CB_FOUND;
347
Masami Hiramatsu378eeaa2010-10-21 19:13:09 +0900348 if (dwarf_haspc(die_mem, fvp->addr))
349 return DIE_FIND_CB_CONTINUE;
350 else
351 return DIE_FIND_CB_SIBLING;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400352}
353
Masami Hiramatsu378eeaa2010-10-21 19:13:09 +0900354/* Find a variable called 'name' at given address */
355static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
356 Dwarf_Addr addr, Dwarf_Die *die_mem)
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500357{
Masami Hiramatsu378eeaa2010-10-21 19:13:09 +0900358 struct __find_variable_param fvp = { .name = name, .addr = addr};
359
360 return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
Masami Hiramatsu016f2622010-03-16 18:05:58 -0400361 die_mem);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400362}
363
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400364static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
365{
366 const char *name = data;
367
368 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
Masami Hiramatsu82175632010-07-09 18:29:17 +0900369 die_compare_name(die_mem, name))
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400370 return DIE_FIND_CB_FOUND;
371
372 return DIE_FIND_CB_SIBLING;
373}
374
375/* Find a member called 'name' */
376static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
377 Dwarf_Die *die_mem)
378{
379 return die_find_child(st_die, __die_find_member_cb, (void *)name,
380 die_mem);
381}
382
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400383/*
384 * Probe finder related functions
385 */
386
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530387static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400388{
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530389 struct probe_trace_arg_ref *ref;
390 ref = zalloc(sizeof(struct probe_trace_arg_ref));
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400391 if (ref != NULL)
392 ref->offset = offs;
393 return ref;
394}
395
396/* Show a location */
397static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
398{
399 Dwarf_Attribute attr;
400 Dwarf_Op *op;
401 size_t nops;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500402 unsigned int regn;
403 Dwarf_Word offs = 0;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400404 bool ref = false;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400405 const char *regs;
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530406 struct probe_trace_arg *tvar = pf->tvar;
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400407 int ret;
408
Masami Hiramatsu632941c2010-10-21 19:13:16 +0900409 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
410 goto static_var;
411
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400412 /* TODO: handle more than 1 exprs */
413 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
414 dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
415 nops == 0) {
416 /* TODO: Support const_value */
417 pr_err("Failed to find the location of %s at this address.\n"
418 " Perhaps, it has been optimized out.\n", pf->pvar->var);
419 return -ENOENT;
420 }
421
422 if (op->atom == DW_OP_addr) {
Masami Hiramatsu632941c2010-10-21 19:13:16 +0900423static_var:
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400424 /* Static variables on memory (not stack), make @varname */
425 ret = strlen(dwarf_diename(vr_die));
426 tvar->value = zalloc(ret + 2);
427 if (tvar->value == NULL)
428 return -ENOMEM;
429 snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
430 tvar->ref = alloc_trace_arg_ref((long)offs);
431 if (tvar->ref == NULL)
432 return -ENOMEM;
433 return 0;
434 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400435
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400436 /* If this is based on frame buffer, set the offset */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500437 if (op->atom == DW_OP_fbreg) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400438 if (pf->fb_ops == NULL) {
439 pr_warning("The attribute of frame base is not "
440 "supported.\n");
441 return -ENOTSUP;
442 }
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400443 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500444 offs = op->number;
445 op = &pf->fb_ops[0];
446 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400447
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500448 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
449 regn = op->atom - DW_OP_breg0;
450 offs += op->number;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400451 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500452 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
453 regn = op->atom - DW_OP_reg0;
454 } else if (op->atom == DW_OP_bregx) {
455 regn = op->number;
456 offs += op->number2;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400457 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500458 } else if (op->atom == DW_OP_regx) {
459 regn = op->number;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400460 } else {
461 pr_warning("DW_OP %x is not supported.\n", op->atom);
462 return -ENOTSUP;
463 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400464
465 regs = get_arch_regstr(regn);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400466 if (!regs) {
Ian Munsiecd932c52010-04-20 16:58:32 +1000467 pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400468 return -ERANGE;
469 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400470
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400471 tvar->value = strdup(regs);
472 if (tvar->value == NULL)
473 return -ENOMEM;
474
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400475 if (ref) {
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400476 tvar->ref = alloc_trace_arg_ref((long)offs);
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400477 if (tvar->ref == NULL)
478 return -ENOMEM;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400479 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400480 return 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400481}
482
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400483static int convert_variable_type(Dwarf_Die *vr_die,
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530484 struct probe_trace_arg *tvar,
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400485 const char *cast)
Masami Hiramatsu49849122010-04-12 13:17:15 -0400486{
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530487 struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400488 Dwarf_Die type;
489 char buf[16];
490 int ret;
491
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400492 /* TODO: check all types */
493 if (cast && strcmp(cast, "string") != 0) {
494 /* Non string type is OK */
495 tvar->type = strdup(cast);
496 return (tvar->type == NULL) ? -ENOMEM : 0;
497 }
498
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400499 if (die_get_real_type(vr_die, &type) == NULL) {
500 pr_warning("Failed to get a type information of %s.\n",
501 dwarf_diename(vr_die));
502 return -ENOENT;
503 }
Masami Hiramatsu49849122010-04-12 13:17:15 -0400504
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400505 pr_debug("%s type is %s.\n",
506 dwarf_diename(vr_die), dwarf_diename(&type));
507
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400508 if (cast && strcmp(cast, "string") == 0) { /* String type */
509 ret = dwarf_tag(&type);
510 if (ret != DW_TAG_pointer_type &&
511 ret != DW_TAG_array_type) {
512 pr_warning("Failed to cast into string: "
513 "%s(%s) is not a pointer nor array.",
514 dwarf_diename(vr_die), dwarf_diename(&type));
515 return -EINVAL;
516 }
517 if (ret == DW_TAG_pointer_type) {
518 if (die_get_real_type(&type, &type) == NULL) {
519 pr_warning("Failed to get a type information.");
520 return -ENOENT;
521 }
522 while (*ref_ptr)
523 ref_ptr = &(*ref_ptr)->next;
524 /* Add new reference with offset +0 */
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530525 *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400526 if (*ref_ptr == NULL) {
527 pr_warning("Out of memory error\n");
528 return -ENOMEM;
529 }
530 }
Masami Hiramatsu82175632010-07-09 18:29:17 +0900531 if (!die_compare_name(&type, "char") &&
532 !die_compare_name(&type, "unsigned char")) {
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400533 pr_warning("Failed to cast into string: "
534 "%s is not (unsigned) char *.",
535 dwarf_diename(vr_die));
536 return -EINVAL;
537 }
538 tvar->type = strdup(cast);
539 return (tvar->type == NULL) ? -ENOMEM : 0;
540 }
541
Masami Hiramatsu49849122010-04-12 13:17:15 -0400542 ret = die_get_byte_size(&type) * 8;
543 if (ret) {
544 /* Check the bitwidth */
545 if (ret > MAX_BASIC_TYPE_BITS) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400546 pr_info("%s exceeds max-bitwidth."
547 " Cut down to %d bits.\n",
548 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
Masami Hiramatsu49849122010-04-12 13:17:15 -0400549 ret = MAX_BASIC_TYPE_BITS;
550 }
551
552 ret = snprintf(buf, 16, "%c%d",
553 die_is_signed_type(&type) ? 's' : 'u', ret);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400554 if (ret < 0 || ret >= 16) {
555 if (ret >= 16)
556 ret = -E2BIG;
557 pr_warning("Failed to convert variable type: %s\n",
558 strerror(-ret));
559 return ret;
560 }
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400561 tvar->type = strdup(buf);
562 if (tvar->type == NULL)
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400563 return -ENOMEM;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400564 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400565 return 0;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400566}
567
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400568static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400569 struct perf_probe_arg_field *field,
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530570 struct probe_trace_arg_ref **ref_ptr,
Masami Hiramatsu49849122010-04-12 13:17:15 -0400571 Dwarf_Die *die_mem)
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400572{
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530573 struct probe_trace_arg_ref *ref = *ref_ptr;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400574 Dwarf_Die type;
575 Dwarf_Word offs;
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400576 int ret, tag;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400577
578 pr_debug("converting %s in %s\n", field->name, varname);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400579 if (die_get_real_type(vr_die, &type) == NULL) {
580 pr_warning("Failed to get the type of %s.\n", varname);
581 return -ENOENT;
582 }
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400583 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
584 tag = dwarf_tag(&type);
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400585
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400586 if (field->name[0] == '[' &&
587 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
588 if (field->next)
589 /* Save original type for next field */
590 memcpy(die_mem, &type, sizeof(*die_mem));
591 /* Get the type of this array */
592 if (die_get_real_type(&type, &type) == NULL) {
593 pr_warning("Failed to get the type of %s.\n", varname);
594 return -ENOENT;
595 }
596 pr_debug2("Array real type: (%x)\n",
597 (unsigned)dwarf_dieoffset(&type));
598 if (tag == DW_TAG_pointer_type) {
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530599 ref = zalloc(sizeof(struct probe_trace_arg_ref));
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400600 if (ref == NULL)
601 return -ENOMEM;
602 if (*ref_ptr)
603 (*ref_ptr)->next = ref;
604 else
605 *ref_ptr = ref;
606 }
607 ref->offset += die_get_byte_size(&type) * field->index;
608 if (!field->next)
609 /* Save vr_die for converting types */
610 memcpy(die_mem, vr_die, sizeof(*die_mem));
611 goto next;
612 } else if (tag == DW_TAG_pointer_type) {
613 /* Check the pointer and dereference */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400614 if (!field->ref) {
615 pr_err("Semantic error: %s must be referred by '->'\n",
616 field->name);
617 return -EINVAL;
618 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400619 /* Get the type pointed by this pointer */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400620 if (die_get_real_type(&type, &type) == NULL) {
621 pr_warning("Failed to get the type of %s.\n", varname);
622 return -ENOENT;
623 }
Masami Hiramatsu12e5a7a2010-04-02 12:50:53 -0400624 /* Verify it is a data structure */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400625 if (dwarf_tag(&type) != DW_TAG_structure_type) {
626 pr_warning("%s is not a data structure.\n", varname);
627 return -EINVAL;
628 }
Masami Hiramatsu12e5a7a2010-04-02 12:50:53 -0400629
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530630 ref = zalloc(sizeof(struct probe_trace_arg_ref));
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400631 if (ref == NULL)
632 return -ENOMEM;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400633 if (*ref_ptr)
634 (*ref_ptr)->next = ref;
635 else
636 *ref_ptr = ref;
637 } else {
Masami Hiramatsu12e5a7a2010-04-02 12:50:53 -0400638 /* Verify it is a data structure */
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400639 if (tag != DW_TAG_structure_type) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400640 pr_warning("%s is not a data structure.\n", varname);
641 return -EINVAL;
642 }
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400643 if (field->name[0] == '[') {
644 pr_err("Semantic error: %s is not a pointor nor array.",
645 varname);
646 return -EINVAL;
647 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400648 if (field->ref) {
649 pr_err("Semantic error: %s must be referred by '.'\n",
650 field->name);
651 return -EINVAL;
652 }
653 if (!ref) {
654 pr_warning("Structure on a register is not "
655 "supported yet.\n");
656 return -ENOTSUP;
657 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400658 }
659
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400660 if (die_find_member(&type, field->name, die_mem) == NULL) {
661 pr_warning("%s(tyep:%s) has no member %s.\n", varname,
662 dwarf_diename(&type), field->name);
663 return -EINVAL;
664 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400665
666 /* Get the offset of the field */
Masami Hiramatsude1439d2010-04-14 17:44:00 -0300667 ret = die_get_data_member_location(die_mem, &offs);
668 if (ret < 0) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400669 pr_warning("Failed to get the offset of %s.\n", field->name);
Masami Hiramatsude1439d2010-04-14 17:44:00 -0300670 return ret;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400671 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400672 ref->offset += (long)offs;
673
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400674next:
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400675 /* Converting next field */
676 if (field->next)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400677 return convert_variable_fields(die_mem, field->name,
Masami Hiramatsude1439d2010-04-14 17:44:00 -0300678 field->next, &ref, die_mem);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400679 else
680 return 0;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400681}
682
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400683/* Show a variables in kprobe event format */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400684static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400685{
Masami Hiramatsu49849122010-04-12 13:17:15 -0400686 Dwarf_Die die_mem;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400687 int ret;
688
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400689 pr_debug("Converting variable %s into trace event.\n",
690 dwarf_diename(vr_die));
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500691
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400692 ret = convert_variable_location(vr_die, pf);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400693 if (ret == 0 && pf->pvar->field) {
694 ret = convert_variable_fields(vr_die, pf->pvar->var,
695 pf->pvar->field, &pf->tvar->ref,
696 &die_mem);
Masami Hiramatsu49849122010-04-12 13:17:15 -0400697 vr_die = &die_mem;
698 }
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400699 if (ret == 0)
700 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500701 /* *expr will be cached in libdw. Don't free it. */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400702 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400703}
704
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400705/* Find a variable in a subprogram die */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400706static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400707{
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400708 Dwarf_Die vr_die, *scopes;
Masami Hiramatsu11a1ca32010-04-12 13:17:22 -0400709 char buf[32], *ptr;
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400710 int ret, nscopes;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400711
Masami Hiramatsu367e94c2010-08-27 20:38:59 +0900712 if (!is_c_varname(pf->pvar->var)) {
713 /* Copy raw parameters */
714 pf->tvar->value = strdup(pf->pvar->var);
715 if (pf->tvar->value == NULL)
716 return -ENOMEM;
717 if (pf->pvar->type) {
718 pf->tvar->type = strdup(pf->pvar->type);
719 if (pf->tvar->type == NULL)
720 return -ENOMEM;
721 }
722 if (pf->pvar->name) {
723 pf->tvar->name = strdup(pf->pvar->name);
724 if (pf->tvar->name == NULL)
725 return -ENOMEM;
726 } else
727 pf->tvar->name = NULL;
728 return 0;
729 }
730
Masami Hiramatsu48481932010-04-12 13:16:53 -0400731 if (pf->pvar->name)
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400732 pf->tvar->name = strdup(pf->pvar->name);
Masami Hiramatsu48481932010-04-12 13:16:53 -0400733 else {
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400734 ret = synthesize_perf_probe_arg(pf->pvar, buf, 32);
735 if (ret < 0)
736 return ret;
Masami Hiramatsu11a1ca32010-04-12 13:17:22 -0400737 ptr = strchr(buf, ':'); /* Change type separator to _ */
738 if (ptr)
739 *ptr = '_';
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400740 pf->tvar->name = strdup(buf);
Masami Hiramatsu48481932010-04-12 13:16:53 -0400741 }
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400742 if (pf->tvar->name == NULL)
743 return -ENOMEM;
Masami Hiramatsu48481932010-04-12 13:16:53 -0400744
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400745 pr_debug("Searching '%s' variable in context.\n",
746 pf->pvar->var);
747 /* Search child die for local variables and parameters. */
Masami Hiramatsu378eeaa2010-10-21 19:13:09 +0900748 if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400749 ret = convert_variable(&vr_die, pf);
750 else {
751 /* Search upper class */
752 nscopes = dwarf_getscopes_die(sp_die, &scopes);
Masami Hiramatsu632941c2010-10-21 19:13:16 +0900753 while (nscopes-- > 1) {
754 pr_debug("Searching variables in %s\n",
755 dwarf_diename(&scopes[nscopes]));
756 /* We should check this scope, so give dummy address */
757 if (die_find_variable_at(&scopes[nscopes],
758 pf->pvar->var, 0,
759 &vr_die)) {
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400760 ret = convert_variable(&vr_die, pf);
Masami Hiramatsu632941c2010-10-21 19:13:16 +0900761 goto found;
762 }
763 }
764 if (scopes)
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400765 free(scopes);
Masami Hiramatsu632941c2010-10-21 19:13:16 +0900766 ret = -ENOENT;
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400767 }
Masami Hiramatsu632941c2010-10-21 19:13:16 +0900768found:
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400769 if (ret < 0)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400770 pr_warning("Failed to find '%s' in this function.\n",
771 pf->pvar->var);
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400772 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400773}
774
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400775/* Show a probe point to output buffer */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400776static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400777{
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530778 struct probe_trace_event *tev;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500779 Dwarf_Addr eaddr;
780 Dwarf_Die die_mem;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500781 const char *name;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400782 int ret, i;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500783 Dwarf_Attribute fb_attr;
784 size_t nops;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400785
Masami Hiramatsuef4a3562010-04-21 15:56:40 -0400786 if (pf->ntevs == pf->max_tevs) {
787 pr_warning("Too many( > %d) probe point found.\n",
788 pf->max_tevs);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400789 return -ERANGE;
790 }
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400791 tev = &pf->tevs[pf->ntevs++];
792
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500793 /* If no real subprogram, find a real one */
794 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -0400795 sp_die = die_find_real_subprogram(&pf->cu_die,
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500796 pf->addr, &die_mem);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400797 if (!sp_die) {
798 pr_warning("Failed to find probe point in any "
799 "functions.\n");
800 return -ENOENT;
801 }
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500802 }
803
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400804 /* Copy the name of probe point */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500805 name = dwarf_diename(sp_die);
806 if (name) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400807 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
808 pr_warning("Failed to get entry pc of %s\n",
809 dwarf_diename(sp_die));
810 return -ENOENT;
811 }
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400812 tev->point.symbol = strdup(name);
813 if (tev->point.symbol == NULL)
814 return -ENOMEM;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400815 tev->point.offset = (unsigned long)(pf->addr - eaddr);
816 } else
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400817 /* This function has no name. */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400818 tev->point.offset = (unsigned long)pf->addr;
819
Masami Hiramatsu04ddd042010-08-27 20:38:53 +0900820 /* Return probe must be on the head of a subprogram */
821 if (pf->pev->point.retprobe) {
822 if (tev->point.offset != 0) {
823 pr_warning("Return probe must be on the head of"
824 " a real function\n");
825 return -EINVAL;
826 }
827 tev->point.retprobe = true;
828 }
829
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400830 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
831 tev->point.offset);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400832
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500833 /* Get the frame base attribute/ops */
834 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
Masami Hiramatsud0cb4262010-03-15 13:02:35 -0400835 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
Masami Hiramatsua34a9852010-04-12 13:17:29 -0400836 if (ret <= 0 || nops == 0) {
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500837 pf->fb_ops = NULL;
Masami Hiramatsu7752f1b2010-05-10 13:12:07 -0400838#if _ELFUTILS_PREREQ(0, 142)
Masami Hiramatsua34a9852010-04-12 13:17:29 -0400839 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
840 pf->cfi != NULL) {
841 Dwarf_Frame *frame;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400842 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
843 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
844 pr_warning("Failed to get CFA on 0x%jx\n",
845 (uintmax_t)pf->addr);
846 return -ENOENT;
847 }
Masami Hiramatsu7752f1b2010-05-10 13:12:07 -0400848#endif
Masami Hiramatsua34a9852010-04-12 13:17:29 -0400849 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500850
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400851 /* Find each argument */
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400852 tev->nargs = pf->pev->nargs;
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530853 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400854 if (tev->args == NULL)
855 return -ENOMEM;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400856 for (i = 0; i < pf->pev->nargs; i++) {
857 pf->pvar = &pf->pev->args[i];
858 pf->tvar = &tev->args[i];
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400859 ret = find_variable(sp_die, pf);
860 if (ret != 0)
861 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400862 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500863
864 /* *pf->fb_ops will be cached in libdw. Don't free it. */
865 pf->fb_ops = NULL;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400866 return 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400867}
868
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400869/* Find probe point from its line number */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400870static int find_probe_point_by_line(struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400871{
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500872 Dwarf_Lines *lines;
873 Dwarf_Line *line;
874 size_t nlines, i;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500875 Dwarf_Addr addr;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500876 int lineno;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400877 int ret = 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400878
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400879 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
880 pr_warning("No source lines found in this CU.\n");
881 return -ENOENT;
882 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400883
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400884 for (i = 0; i < nlines && ret == 0; i++) {
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500885 line = dwarf_onesrcline(lines, i);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400886 if (dwarf_lineno(line, &lineno) != 0 ||
887 lineno != pf->lno)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400888 continue;
889
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500890 /* TODO: Get fileno from line, but how? */
891 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
892 continue;
Masami Hiramatsub0ef0732009-10-27 16:43:19 -0400893
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400894 if (dwarf_lineaddr(line, &addr) != 0) {
895 pr_warning("Failed to get the address of the line.\n");
896 return -ENOENT;
897 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500898 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
899 (int)i, lineno, (uintmax_t)addr);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400900 pf->addr = addr;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500901
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400902 ret = convert_probe_point(NULL, pf);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400903 /* Continuing, because target line might be inlined. */
904 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400905 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400906}
907
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500908/* Find lines which match lazy pattern */
909static int find_lazy_match_lines(struct list_head *head,
910 const char *fname, const char *pat)
911{
912 char *fbuf, *p1, *p2;
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300913 int fd, line, nlines = -1;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500914 struct stat st;
915
916 fd = open(fname, O_RDONLY);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400917 if (fd < 0) {
918 pr_warning("Failed to open %s: %s\n", fname, strerror(-fd));
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300919 return -errno;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400920 }
921
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300922 if (fstat(fd, &st) < 0) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400923 pr_warning("Failed to get the size of %s: %s\n",
924 fname, strerror(errno));
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300925 nlines = -errno;
926 goto out_close;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400927 }
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300928
929 nlines = -ENOMEM;
930 fbuf = malloc(st.st_size + 2);
931 if (fbuf == NULL)
932 goto out_close;
933 if (read(fd, fbuf, st.st_size) < 0) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400934 pr_warning("Failed to read %s: %s\n", fname, strerror(errno));
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300935 nlines = -errno;
936 goto out_free_fbuf;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400937 }
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500938 fbuf[st.st_size] = '\n'; /* Dummy line */
939 fbuf[st.st_size + 1] = '\0';
940 p1 = fbuf;
941 line = 1;
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300942 nlines = 0;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500943 while ((p2 = strchr(p1, '\n')) != NULL) {
944 *p2 = '\0';
945 if (strlazymatch(p1, pat)) {
946 line_list__add_line(head, line);
947 nlines++;
948 }
949 line++;
950 p1 = p2 + 1;
951 }
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300952out_free_fbuf:
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500953 free(fbuf);
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300954out_close:
955 close(fd);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500956 return nlines;
957}
958
959/* Find probe points from lazy pattern */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400960static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500961{
962 Dwarf_Lines *lines;
963 Dwarf_Line *line;
964 size_t nlines, i;
965 Dwarf_Addr addr;
966 Dwarf_Die die_mem;
967 int lineno;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400968 int ret = 0;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500969
970 if (list_empty(&pf->lcache)) {
971 /* Matching lazy line pattern */
972 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400973 pf->pev->point.lazy_line);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400974 if (ret == 0) {
975 pr_debug("No matched lines found in %s.\n", pf->fname);
976 return 0;
977 } else if (ret < 0)
978 return ret;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500979 }
980
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400981 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
982 pr_warning("No source lines found in this CU.\n");
983 return -ENOENT;
984 }
985
986 for (i = 0; i < nlines && ret >= 0; i++) {
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500987 line = dwarf_onesrcline(lines, i);
988
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400989 if (dwarf_lineno(line, &lineno) != 0 ||
990 !line_list__has_line(&pf->lcache, lineno))
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500991 continue;
992
993 /* TODO: Get fileno from line, but how? */
994 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
995 continue;
996
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400997 if (dwarf_lineaddr(line, &addr) != 0) {
998 pr_debug("Failed to get the address of line %d.\n",
999 lineno);
1000 continue;
1001 }
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001002 if (sp_die) {
1003 /* Address filtering 1: does sp_die include addr? */
1004 if (!dwarf_haspc(sp_die, addr))
1005 continue;
1006 /* Address filtering 2: No child include addr? */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -04001007 if (die_find_inlinefunc(sp_die, addr, &die_mem))
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001008 continue;
1009 }
1010
1011 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
1012 (int)i, lineno, (unsigned long long)addr);
1013 pf->addr = addr;
1014
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001015 ret = convert_probe_point(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001016 /* Continuing, because target line might be inlined. */
1017 }
1018 /* TODO: deallocate lines, but how? */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001019 return ret;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001020}
1021
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001022/* Callback parameter with return value */
1023struct dwarf_callback_param {
1024 void *data;
1025 int retval;
1026};
1027
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001028static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001029{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001030 struct dwarf_callback_param *param = data;
1031 struct probe_finder *pf = param->data;
Masami Hiramatsu4235b042010-03-16 18:06:12 -04001032 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001033 Dwarf_Addr addr;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001034
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001035 if (pp->lazy_line)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001036 param->retval = find_probe_point_lazy(in_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001037 else {
1038 /* Get probe address */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001039 if (dwarf_entrypc(in_die, &addr) != 0) {
1040 pr_warning("Failed to get entry pc of %s.\n",
1041 dwarf_diename(in_die));
1042 param->retval = -ENOENT;
1043 return DWARF_CB_ABORT;
1044 }
1045 pf->addr = addr;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001046 pf->addr += pp->offset;
1047 pr_debug("found inline addr: 0x%jx\n",
1048 (uintmax_t)pf->addr);
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001049
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001050 param->retval = convert_probe_point(in_die, pf);
Masami Hiramatsu5d1ee042010-04-21 15:56:32 -04001051 if (param->retval < 0)
1052 return DWARF_CB_ABORT;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001053 }
1054
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001055 return DWARF_CB_OK;
1056}
1057
1058/* Search function from function name */
1059static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1060{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001061 struct dwarf_callback_param *param = data;
1062 struct probe_finder *pf = param->data;
Masami Hiramatsu4235b042010-03-16 18:06:12 -04001063 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001064
1065 /* Check tag and diename */
1066 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
Masami Hiramatsu82175632010-07-09 18:29:17 +09001067 !die_compare_name(sp_die, pp->function))
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001068 return DWARF_CB_OK;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001069
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001070 pf->fname = dwarf_decl_file(sp_die);
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001071 if (pp->line) { /* Function relative line */
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001072 dwarf_decl_line(sp_die, &pf->lno);
1073 pf->lno += pp->line;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001074 param->retval = find_probe_point_by_line(pf);
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001075 } else if (!dwarf_func_inline(sp_die)) {
1076 /* Real function */
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001077 if (pp->lazy_line)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001078 param->retval = find_probe_point_lazy(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001079 else {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001080 if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
1081 pr_warning("Failed to get entry pc of %s.\n",
1082 dwarf_diename(sp_die));
1083 param->retval = -ENOENT;
1084 return DWARF_CB_ABORT;
1085 }
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001086 pf->addr += pp->offset;
1087 /* TODO: Check the address in this function */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001088 param->retval = convert_probe_point(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001089 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001090 } else {
1091 struct dwarf_callback_param _param = {.data = (void *)pf,
1092 .retval = 0};
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001093 /* Inlined function: search instances */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001094 dwarf_func_inline_instances(sp_die, probe_point_inline_cb,
1095 &_param);
1096 param->retval = _param.retval;
1097 }
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001098
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001099 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001100}
1101
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001102static int find_probe_point_by_func(struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001103{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001104 struct dwarf_callback_param _param = {.data = (void *)pf,
1105 .retval = 0};
1106 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0);
1107 return _param.retval;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001108}
1109
Srikar Dronamraju0e608362010-07-29 19:43:51 +05301110/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1111int find_probe_trace_events(int fd, struct perf_probe_event *pev,
1112 struct probe_trace_event **tevs, int max_tevs)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001113{
Masami Hiramatsuef4a3562010-04-21 15:56:40 -04001114 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
Masami Hiramatsu4235b042010-03-16 18:06:12 -04001115 struct perf_probe_point *pp = &pev->point;
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001116 Dwarf_Off off, noff;
1117 size_t cuhl;
1118 Dwarf_Die *diep;
1119 Dwarf *dbg;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001120 int ret = 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001121
Srikar Dronamraju0e608362010-07-29 19:43:51 +05301122 pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
Masami Hiramatsue334016f12010-04-12 13:17:49 -04001123 if (pf.tevs == NULL)
1124 return -ENOMEM;
Masami Hiramatsu4235b042010-03-16 18:06:12 -04001125 *tevs = pf.tevs;
1126 pf.ntevs = 0;
1127
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001128 dbg = dwarf_begin(fd, DWARF_C_READ);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001129 if (!dbg) {
1130 pr_warning("No dwarf info found in the vmlinux - "
1131 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -03001132 free(pf.tevs);
1133 *tevs = NULL;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001134 return -EBADF;
1135 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001136
Masami Hiramatsu7752f1b2010-05-10 13:12:07 -04001137#if _ELFUTILS_PREREQ(0, 142)
Masami Hiramatsua34a9852010-04-12 13:17:29 -04001138 /* Get the call frame information from this dwarf */
1139 pf.cfi = dwarf_getcfi(dbg);
Masami Hiramatsu7752f1b2010-05-10 13:12:07 -04001140#endif
Masami Hiramatsua34a9852010-04-12 13:17:29 -04001141
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001142 off = 0;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001143 line_list__init(&pf.lcache);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001144 /* Loop on CUs (Compilation Unit) */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001145 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
1146 ret >= 0) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001147 /* Get the DIE(Debugging Information Entry) of this CU */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001148 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
1149 if (!diep)
1150 continue;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001151
1152 /* Check if target file is included. */
1153 if (pp->file)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001154 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001155 else
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001156 pf.fname = NULL;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001157
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001158 if (!pp->file || pf.fname) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001159 if (pp->function)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001160 ret = find_probe_point_by_func(&pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001161 else if (pp->lazy_line)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001162 ret = find_probe_point_lazy(NULL, &pf);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -04001163 else {
1164 pf.lno = pp->line;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001165 ret = find_probe_point_by_line(&pf);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -04001166 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001167 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001168 off = noff;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001169 }
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001170 line_list__free(&pf.lcache);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001171 dwarf_end(dbg);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001172
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001173 return (ret < 0) ? ret : pf.ntevs;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001174}
1175
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001176/* Reverse search */
1177int find_perf_probe_point(int fd, unsigned long addr,
1178 struct perf_probe_point *ppt)
1179{
1180 Dwarf_Die cudie, spdie, indie;
1181 Dwarf *dbg;
1182 Dwarf_Line *line;
1183 Dwarf_Addr laddr, eaddr;
1184 const char *tmp;
1185 int lineno, ret = 0;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001186 bool found = false;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001187
1188 dbg = dwarf_begin(fd, DWARF_C_READ);
1189 if (!dbg)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001190 return -EBADF;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001191
1192 /* Find cu die */
Masami Hiramatsu75ec5a22010-04-02 12:50:59 -04001193 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {
1194 ret = -EINVAL;
1195 goto end;
1196 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001197
1198 /* Find a corresponding line */
1199 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
1200 if (line) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001201 if (dwarf_lineaddr(line, &laddr) == 0 &&
1202 (Dwarf_Addr)addr == laddr &&
1203 dwarf_lineno(line, &lineno) == 0) {
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001204 tmp = dwarf_linesrc(line, NULL, NULL);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001205 if (tmp) {
1206 ppt->line = lineno;
Masami Hiramatsu02b95da2010-04-12 13:17:56 -04001207 ppt->file = strdup(tmp);
1208 if (ppt->file == NULL) {
1209 ret = -ENOMEM;
1210 goto end;
1211 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001212 found = true;
1213 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001214 }
1215 }
1216
1217 /* Find a corresponding function */
1218 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
1219 tmp = dwarf_diename(&spdie);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001220 if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0)
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001221 goto end;
1222
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001223 if (ppt->line) {
1224 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
1225 &indie)) {
1226 /* addr in an inline function */
1227 tmp = dwarf_diename(&indie);
1228 if (!tmp)
1229 goto end;
1230 ret = dwarf_decl_line(&indie, &lineno);
1231 } else {
1232 if (eaddr == addr) { /* Function entry */
1233 lineno = ppt->line;
1234 ret = 0;
1235 } else
1236 ret = dwarf_decl_line(&spdie, &lineno);
1237 }
1238 if (ret == 0) {
1239 /* Make a relative line number */
1240 ppt->line -= lineno;
1241 goto found;
1242 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001243 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001244 /* We don't have a line number, let's use offset */
1245 ppt->offset = addr - (unsigned long)eaddr;
1246found:
Masami Hiramatsu02b95da2010-04-12 13:17:56 -04001247 ppt->function = strdup(tmp);
1248 if (ppt->function == NULL) {
1249 ret = -ENOMEM;
1250 goto end;
1251 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001252 found = true;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001253 }
1254
1255end:
1256 dwarf_end(dbg);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001257 if (ret >= 0)
1258 ret = found ? 1 : 0;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001259 return ret;
1260}
1261
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001262/* Add a line and store the src path */
1263static int line_range_add_line(const char *src, unsigned int lineno,
1264 struct line_range *lr)
1265{
Masami Hiramatsu7cf0b792010-07-09 18:28:59 +09001266 /* Copy source path */
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001267 if (!lr->path) {
Masami Hiramatsu7cf0b792010-07-09 18:28:59 +09001268 lr->path = strdup(src);
1269 if (lr->path == NULL)
1270 return -ENOMEM;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001271 }
1272 return line_list__add_line(&lr->line_list, lineno);
1273}
1274
1275/* Search function declaration lines */
1276static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
1277{
1278 struct dwarf_callback_param *param = data;
1279 struct line_finder *lf = param->data;
1280 const char *src;
1281 int lineno;
1282
1283 src = dwarf_decl_file(sp_die);
1284 if (src && strtailcmp(src, lf->fname) != 0)
1285 return DWARF_CB_OK;
1286
1287 if (dwarf_decl_line(sp_die, &lineno) != 0 ||
1288 (lf->lno_s > lineno || lf->lno_e < lineno))
1289 return DWARF_CB_OK;
1290
1291 param->retval = line_range_add_line(src, lineno, lf->lr);
Masami Hiramatsu5d1ee042010-04-21 15:56:32 -04001292 if (param->retval < 0)
1293 return DWARF_CB_ABORT;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001294 return DWARF_CB_OK;
1295}
1296
1297static int find_line_range_func_decl_lines(struct line_finder *lf)
1298{
1299 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1300 dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
1301 return param.retval;
1302}
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001303
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001304/* Find line range from its line number */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001305static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001306{
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001307 Dwarf_Lines *lines;
1308 Dwarf_Line *line;
1309 size_t nlines, i;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001310 Dwarf_Addr addr;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001311 int lineno, ret = 0;
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001312 const char *src;
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001313 Dwarf_Die die_mem;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001314
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001315 line_list__init(&lf->lr->line_list);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001316 if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
1317 pr_warning("No source lines found in this CU.\n");
1318 return -ENOENT;
1319 }
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001320
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001321 /* Search probable lines on lines list */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001322 for (i = 0; i < nlines; i++) {
1323 line = dwarf_onesrcline(lines, i);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001324 if (dwarf_lineno(line, &lineno) != 0 ||
1325 (lf->lno_s > lineno || lf->lno_e < lineno))
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001326 continue;
1327
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001328 if (sp_die) {
1329 /* Address filtering 1: does sp_die include addr? */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001330 if (dwarf_lineaddr(line, &addr) != 0 ||
1331 !dwarf_haspc(sp_die, addr))
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001332 continue;
1333
1334 /* Address filtering 2: No child include addr? */
Masami Hiramatsu95a3e4c2010-03-16 18:05:51 -04001335 if (die_find_inlinefunc(sp_die, addr, &die_mem))
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001336 continue;
1337 }
1338
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001339 /* TODO: Get fileno from line, but how? */
1340 src = dwarf_linesrc(line, NULL, NULL);
1341 if (strtailcmp(src, lf->fname) != 0)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001342 continue;
1343
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001344 ret = line_range_add_line(src, lineno, lf->lr);
1345 if (ret < 0)
1346 return ret;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001347 }
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001348
1349 /*
1350 * Dwarf lines doesn't include function declarations. We have to
1351 * check functions list or given function.
1352 */
1353 if (sp_die) {
1354 src = dwarf_decl_file(sp_die);
1355 if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
1356 (lf->lno_s <= lineno && lf->lno_e >= lineno))
1357 ret = line_range_add_line(src, lineno, lf->lr);
1358 } else
1359 ret = find_line_range_func_decl_lines(lf);
1360
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001361 /* Update status */
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001362 if (ret >= 0)
1363 if (!list_empty(&lf->lr->line_list))
1364 ret = lf->found = 1;
1365 else
1366 ret = 0; /* Lines are not found */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001367 else {
1368 free(lf->lr->path);
1369 lf->lr->path = NULL;
1370 }
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001371 return ret;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001372}
1373
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001374static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1375{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001376 struct dwarf_callback_param *param = data;
1377
1378 param->retval = find_line_range_by_line(in_die, param->data);
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001379 return DWARF_CB_ABORT; /* No need to find other instances */
1380}
1381
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001382/* Search function from function name */
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001383static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001384{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001385 struct dwarf_callback_param *param = data;
1386 struct line_finder *lf = param->data;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001387 struct line_range *lr = lf->lr;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001388
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001389 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
Masami Hiramatsu82175632010-07-09 18:29:17 +09001390 die_compare_name(sp_die, lr->function)) {
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001391 lf->fname = dwarf_decl_file(sp_die);
1392 dwarf_decl_line(sp_die, &lr->offset);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001393 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001394 lf->lno_s = lr->offset + lr->start;
Masami Hiramatsud3b63d72010-04-14 18:39:42 -04001395 if (lf->lno_s < 0) /* Overflow */
1396 lf->lno_s = INT_MAX;
1397 lf->lno_e = lr->offset + lr->end;
1398 if (lf->lno_e < 0) /* Overflow */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001399 lf->lno_e = INT_MAX;
Masami Hiramatsud3b63d72010-04-14 18:39:42 -04001400 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001401 lr->start = lf->lno_s;
1402 lr->end = lf->lno_e;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001403 if (dwarf_func_inline(sp_die)) {
1404 struct dwarf_callback_param _param;
1405 _param.data = (void *)lf;
1406 _param.retval = 0;
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001407 dwarf_func_inline_instances(sp_die,
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001408 line_range_inline_cb,
1409 &_param);
1410 param->retval = _param.retval;
1411 } else
1412 param->retval = find_line_range_by_line(sp_die, lf);
1413 return DWARF_CB_ABORT;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001414 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001415 return DWARF_CB_OK;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001416}
1417
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001418static int find_line_range_by_func(struct line_finder *lf)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001419{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001420 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1421 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, &param, 0);
1422 return param.retval;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001423}
1424
1425int find_line_range(int fd, struct line_range *lr)
1426{
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001427 struct line_finder lf = {.lr = lr, .found = 0};
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001428 int ret = 0;
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001429 Dwarf_Off off = 0, noff;
1430 size_t cuhl;
1431 Dwarf_Die *diep;
1432 Dwarf *dbg;
Masami Hiramatsu6a330a32010-07-09 18:29:11 +09001433 const char *comp_dir;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001434
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001435 dbg = dwarf_begin(fd, DWARF_C_READ);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001436 if (!dbg) {
1437 pr_warning("No dwarf info found in the vmlinux - "
1438 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1439 return -EBADF;
1440 }
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001441
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001442 /* Loop on CUs (Compilation Unit) */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001443 while (!lf.found && ret >= 0) {
1444 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001445 break;
1446
1447 /* Get the DIE(Debugging Information Entry) of this CU */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001448 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
1449 if (!diep)
1450 continue;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001451
1452 /* Check if target file is included. */
1453 if (lr->file)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001454 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001455 else
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001456 lf.fname = 0;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001457
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001458 if (!lr->file || lf.fname) {
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001459 if (lr->function)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001460 ret = find_line_range_by_func(&lf);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001461 else {
1462 lf.lno_s = lr->start;
Masami Hiramatsud3b63d72010-04-14 18:39:42 -04001463 lf.lno_e = lr->end;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001464 ret = find_line_range_by_line(NULL, &lf);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001465 }
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001466 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001467 off = noff;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001468 }
Masami Hiramatsu6a330a32010-07-09 18:29:11 +09001469
1470 /* Store comp_dir */
1471 if (lf.found) {
1472 comp_dir = cu_get_comp_dir(&lf.cu_die);
1473 if (comp_dir) {
1474 lr->comp_dir = strdup(comp_dir);
1475 if (!lr->comp_dir)
1476 ret = -ENOMEM;
1477 }
1478 }
1479
Masami Hiramatsu7cf0b792010-07-09 18:28:59 +09001480 pr_debug("path: %s\n", lr->path);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001481 dwarf_end(dbg);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001482
1483 return (ret < 0) ? ret : lf.found;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001484}
1485