perf probe: Add data structure member access support
[linux-2.6.git] / tools / perf / util / probe-finder.c
1 /*
2  * probe-finder.c : C expression to kprobe event converter
3  *
4  * Written by Masami Hiramatsu <mhiramat@redhat.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  */
21
22 #include <sys/utsname.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <getopt.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <ctype.h>
34
35 #include "string.h"
36 #include "event.h"
37 #include "debug.h"
38 #include "util.h"
39 #include "probe-finder.h"
40
41
42 /*
43  * Generic dwarf analysis helpers
44  */
45
46 #define X86_32_MAX_REGS 8
47 const char *x86_32_regs_table[X86_32_MAX_REGS] = {
48         "%ax",
49         "%cx",
50         "%dx",
51         "%bx",
52         "$stack",       /* Stack address instead of %sp */
53         "%bp",
54         "%si",
55         "%di",
56 };
57
58 #define X86_64_MAX_REGS 16
59 const char *x86_64_regs_table[X86_64_MAX_REGS] = {
60         "%ax",
61         "%dx",
62         "%cx",
63         "%bx",
64         "%si",
65         "%di",
66         "%bp",
67         "%sp",
68         "%r8",
69         "%r9",
70         "%r10",
71         "%r11",
72         "%r12",
73         "%r13",
74         "%r14",
75         "%r15",
76 };
77
78 /* TODO: switching by dwarf address size */
79 #ifdef __x86_64__
80 #define ARCH_MAX_REGS X86_64_MAX_REGS
81 #define arch_regs_table x86_64_regs_table
82 #else
83 #define ARCH_MAX_REGS X86_32_MAX_REGS
84 #define arch_regs_table x86_32_regs_table
85 #endif
86
87 /* Return architecture dependent register string (for kprobe-tracer) */
88 static const char *get_arch_regstr(unsigned int n)
89 {
90         return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
91 }
92
93 /*
94  * Compare the tail of two strings.
95  * Return 0 if whole of either string is same as another's tail part.
96  */
97 static int strtailcmp(const char *s1, const char *s2)
98 {
99         int i1 = strlen(s1);
100         int i2 = strlen(s2);
101         while (--i1 >= 0 && --i2 >= 0) {
102                 if (s1[i1] != s2[i2])
103                         return s1[i1] - s2[i2];
104         }
105         return 0;
106 }
107
108 /* Line number list operations */
109
110 /* Add a line to line number list */
111 static void line_list__add_line(struct list_head *head, unsigned int line)
112 {
113         struct line_node *ln;
114         struct list_head *p;
115
116         /* Reverse search, because new line will be the last one */
117         list_for_each_entry_reverse(ln, head, list) {
118                 if (ln->line < line) {
119                         p = &ln->list;
120                         goto found;
121                 } else if (ln->line == line)    /* Already exist */
122                         return ;
123         }
124         /* List is empty, or the smallest entry */
125         p = head;
126 found:
127         pr_debug("line list: add a line %u\n", line);
128         ln = xzalloc(sizeof(struct line_node));
129         ln->line = line;
130         INIT_LIST_HEAD(&ln->list);
131         list_add(&ln->list, p);
132 }
133
134 /* Check if the line in line number list */
135 static int line_list__has_line(struct list_head *head, unsigned int line)
136 {
137         struct line_node *ln;
138
139         /* Reverse search, because new line will be the last one */
140         list_for_each_entry(ln, head, list)
141                 if (ln->line == line)
142                         return 1;
143
144         return 0;
145 }
146
147 /* Init line number list */
148 static void line_list__init(struct list_head *head)
149 {
150         INIT_LIST_HEAD(head);
151 }
152
153 /* Free line number list */
154 static void line_list__free(struct list_head *head)
155 {
156         struct line_node *ln;
157         while (!list_empty(head)) {
158                 ln = list_first_entry(head, struct line_node, list);
159                 list_del(&ln->list);
160                 free(ln);
161         }
162 }
163
164 /* Dwarf wrappers */
165
166 /* Find the realpath of the target file. */
167 static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
168 {
169         Dwarf_Files *files;
170         size_t nfiles, i;
171         const char *src = NULL;
172         int ret;
173
174         if (!fname)
175                 return NULL;
176
177         ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
178         if (ret != 0)
179                 return NULL;
180
181         for (i = 0; i < nfiles; i++) {
182                 src = dwarf_filesrc(files, i, NULL, NULL);
183                 if (strtailcmp(src, fname) == 0)
184                         break;
185         }
186         return src;
187 }
188
189 /* Compare diename and tname */
190 static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
191 {
192         const char *name;
193         name = dwarf_diename(dw_die);
194         DIE_IF(name == NULL);
195         return strcmp(tname, name);
196 }
197
198 /* Get entry pc(or low pc, 1st entry of ranges)  of the die */
199 static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
200 {
201         Dwarf_Addr epc;
202         int ret;
203
204         ret = dwarf_entrypc(dw_die, &epc);
205         DIE_IF(ret == -1);
206         return epc;
207 }
208
209 /* Get type die, but skip qualifiers and typedef */
210 static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
211 {
212         Dwarf_Attribute attr;
213         int tag;
214
215         do {
216                 if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
217                     dwarf_formref_die(&attr, die_mem) == NULL)
218                         return NULL;
219
220                 tag = dwarf_tag(die_mem);
221                 vr_die = die_mem;
222         } while (tag == DW_TAG_const_type ||
223                  tag == DW_TAG_restrict_type ||
224                  tag == DW_TAG_volatile_type ||
225                  tag == DW_TAG_shared_type ||
226                  tag == DW_TAG_typedef);
227
228         return die_mem;
229 }
230
231 /* Return values for die_find callbacks */
232 enum {
233         DIE_FIND_CB_FOUND = 0,          /* End of Search */
234         DIE_FIND_CB_CHILD = 1,          /* Search only children */
235         DIE_FIND_CB_SIBLING = 2,        /* Search only siblings */
236         DIE_FIND_CB_CONTINUE = 3,       /* Search children and siblings */
237 };
238
239 /* Search a child die */
240 static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
241                                  int (*callback)(Dwarf_Die *, void *),
242                                  void *data, Dwarf_Die *die_mem)
243 {
244         Dwarf_Die child_die;
245         int ret;
246
247         ret = dwarf_child(rt_die, die_mem);
248         if (ret != 0)
249                 return NULL;
250
251         do {
252                 ret = callback(die_mem, data);
253                 if (ret == DIE_FIND_CB_FOUND)
254                         return die_mem;
255
256                 if ((ret & DIE_FIND_CB_CHILD) &&
257                     die_find_child(die_mem, callback, data, &child_die)) {
258                         memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
259                         return die_mem;
260                 }
261         } while ((ret & DIE_FIND_CB_SIBLING) &&
262                  dwarf_siblingof(die_mem, die_mem) == 0);
263
264         return NULL;
265 }
266
267 struct __addr_die_search_param {
268         Dwarf_Addr      addr;
269         Dwarf_Die       *die_mem;
270 };
271
272 static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
273 {
274         struct __addr_die_search_param *ad = data;
275
276         if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
277             dwarf_haspc(fn_die, ad->addr)) {
278                 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
279                 return DWARF_CB_ABORT;
280         }
281         return DWARF_CB_OK;
282 }
283
284 /* Search a real subprogram including this line, */
285 static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
286                                            Dwarf_Die *die_mem)
287 {
288         struct __addr_die_search_param ad;
289         ad.addr = addr;
290         ad.die_mem = die_mem;
291         /* dwarf_getscopes can't find subprogram. */
292         if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
293                 return NULL;
294         else
295                 return die_mem;
296 }
297
298 /* die_find callback for inline function search */
299 static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
300 {
301         Dwarf_Addr *addr = data;
302
303         if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
304             dwarf_haspc(die_mem, *addr))
305                 return DIE_FIND_CB_FOUND;
306
307         return DIE_FIND_CB_CONTINUE;
308 }
309
310 /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
311 static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
312                                       Dwarf_Die *die_mem)
313 {
314         return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
315 }
316
317 static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
318 {
319         const char *name = data;
320         int tag;
321
322         tag = dwarf_tag(die_mem);
323         if ((tag == DW_TAG_formal_parameter ||
324              tag == DW_TAG_variable) &&
325             (die_compare_name(die_mem, name) == 0))
326                 return DIE_FIND_CB_FOUND;
327
328         return DIE_FIND_CB_CONTINUE;
329 }
330
331 /* Find a variable called 'name' */
332 static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
333                                     Dwarf_Die *die_mem)
334 {
335         return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
336                               die_mem);
337 }
338
339 static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
340 {
341         const char *name = data;
342
343         if ((dwarf_tag(die_mem) == DW_TAG_member) &&
344             (die_compare_name(die_mem, name) == 0))
345                 return DIE_FIND_CB_FOUND;
346
347         return DIE_FIND_CB_SIBLING;
348 }
349
350 /* Find a member called 'name' */
351 static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
352                                   Dwarf_Die *die_mem)
353 {
354         return die_find_child(st_die, __die_find_member_cb, (void *)name,
355                               die_mem);
356 }
357
358 /*
359  * Probe finder related functions
360  */
361
362 /* Show a location */
363 static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
364 {
365         unsigned int regn;
366         Dwarf_Word offs = 0;
367         bool ref = false;
368         const char *regs;
369         struct kprobe_trace_arg *tvar = pf->tvar;
370
371         /* TODO: support CFA */
372         /* If this is based on frame buffer, set the offset */
373         if (op->atom == DW_OP_fbreg) {
374                 if (pf->fb_ops == NULL)
375                         die("The attribute of frame base is not supported.\n");
376                 ref = true;
377                 offs = op->number;
378                 op = &pf->fb_ops[0];
379         }
380
381         if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
382                 regn = op->atom - DW_OP_breg0;
383                 offs += op->number;
384                 ref = true;
385         } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
386                 regn = op->atom - DW_OP_reg0;
387         } else if (op->atom == DW_OP_bregx) {
388                 regn = op->number;
389                 offs += op->number2;
390                 ref = true;
391         } else if (op->atom == DW_OP_regx) {
392                 regn = op->number;
393         } else
394                 die("DW_OP %d is not supported.", op->atom);
395
396         regs = get_arch_regstr(regn);
397         if (!regs)
398                 die("%u exceeds max register number.", regn);
399
400         tvar->value = xstrdup(regs);
401         if (ref) {
402                 tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
403                 tvar->ref->offset = (long)offs;
404         }
405 }
406
407 static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
408                                     struct perf_probe_arg_field *field,
409                                     struct kprobe_trace_arg_ref **ref_ptr)
410 {
411         struct kprobe_trace_arg_ref *ref = *ref_ptr;
412         Dwarf_Attribute attr;
413         Dwarf_Die member;
414         Dwarf_Die type;
415         Dwarf_Word offs;
416
417         pr_debug("converting %s in %s\n", field->name, varname);
418         if (die_get_real_type(vr_die, &type) == NULL)
419                 die("Failed to get a type information of %s.", varname);
420
421         /* Check the pointer and dereference */
422         if (dwarf_tag(&type) == DW_TAG_pointer_type) {
423                 if (!field->ref)
424                         die("Semantic error: %s must be referred by '->'",
425                             field->name);
426                 /* Get the type pointed by this pointer */
427                 if (die_get_real_type(&type, &type) == NULL)
428                         die("Failed to get a type information of %s.", varname);
429
430                 ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
431                 if (*ref_ptr)
432                         (*ref_ptr)->next = ref;
433                 else
434                         *ref_ptr = ref;
435         } else {
436                 if (field->ref)
437                         die("Semantic error: %s must be referred by '.'",
438                             field->name);
439                 if (!ref)
440                         die("Structure on a register is not supported yet.");
441         }
442
443         /* Verify it is a data structure  */
444         if (dwarf_tag(&type) != DW_TAG_structure_type)
445                 die("%s is not a data structure.", varname);
446
447         if (die_find_member(&type, field->name, &member) == NULL)
448                 die("%s(tyep:%s) has no member %s.", varname,
449                     dwarf_diename(&type), field->name);
450
451         /* Get the offset of the field */
452         if (dwarf_attr(&member, DW_AT_data_member_location, &attr) == NULL ||
453             dwarf_formudata(&attr, &offs) != 0)
454                 die("Failed to get the offset of %s.", field->name);
455         ref->offset += (long)offs;
456
457         /* Converting next field */
458         if (field->next)
459                 convert_variable_fields(&member, field->name, field->next,
460                                         &ref);
461 }
462
463 /* Show a variables in kprobe event format */
464 static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
465 {
466         Dwarf_Attribute attr;
467         Dwarf_Op *expr;
468         size_t nexpr;
469         int ret;
470
471         if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
472                 goto error;
473         /* TODO: handle more than 1 exprs */
474         ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
475         if (ret <= 0 || nexpr == 0)
476                 goto error;
477
478         convert_location(expr, pf);
479
480         if (pf->pvar->field)
481                 convert_variable_fields(vr_die, pf->pvar->name,
482                                         pf->pvar->field, &pf->tvar->ref);
483         /* *expr will be cached in libdw. Don't free it. */
484         return ;
485 error:
486         /* TODO: Support const_value */
487         die("Failed to find the location of %s at this address.\n"
488             " Perhaps, it has been optimized out.", pf->pvar->name);
489 }
490
491 /* Find a variable in a subprogram die */
492 static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
493 {
494         Dwarf_Die vr_die;
495         char buf[128];
496
497         /* TODO: Support struct members and arrays */
498         if (!is_c_varname(pf->pvar->name)) {
499                 /* Copy raw parameters */
500                 pf->tvar->value = xstrdup(pf->pvar->name);
501         } else {
502                 synthesize_perf_probe_arg(pf->pvar, buf, 128);
503                 pf->tvar->name = xstrdup(buf);
504                 pr_debug("Searching '%s' variable in context.\n",
505                          pf->pvar->name);
506                 /* Search child die for local variables and parameters. */
507                 if (!die_find_variable(sp_die, pf->pvar->name, &vr_die))
508                         die("Failed to find '%s' in this function.",
509                             pf->pvar->name);
510                 convert_variable(&vr_die, pf);
511         }
512 }
513
514 /* Show a probe point to output buffer */
515 static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
516 {
517         struct kprobe_trace_event *tev;
518         Dwarf_Addr eaddr;
519         Dwarf_Die die_mem;
520         const char *name;
521         int ret, i;
522         Dwarf_Attribute fb_attr;
523         size_t nops;
524
525         if (pf->ntevs == MAX_PROBES)
526                 die("Too many( > %d) probe point found.\n", MAX_PROBES);
527         tev = &pf->tevs[pf->ntevs++];
528
529         /* If no real subprogram, find a real one */
530         if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
531                 sp_die = die_find_real_subprogram(&pf->cu_die,
532                                                  pf->addr, &die_mem);
533                 if (!sp_die)
534                         die("Probe point is not found in subprograms.");
535         }
536
537         /* Copy the name of probe point */
538         name = dwarf_diename(sp_die);
539         if (name) {
540                 dwarf_entrypc(sp_die, &eaddr);
541                 tev->point.symbol = xstrdup(name);
542                 tev->point.offset = (unsigned long)(pf->addr - eaddr);
543         } else
544                 /* This function has no name. */
545                 tev->point.offset = (unsigned long)pf->addr;
546
547         pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
548                  tev->point.offset);
549
550         /* Get the frame base attribute/ops */
551         dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
552         ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
553         if (ret <= 0 || nops == 0)
554                 pf->fb_ops = NULL;
555
556         /* Find each argument */
557         /* TODO: use dwarf_cfi_addrframe */
558         tev->nargs = pf->pev->nargs;
559         tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
560         for (i = 0; i < pf->pev->nargs; i++) {
561                 pf->pvar = &pf->pev->args[i];
562                 pf->tvar = &tev->args[i];
563                 find_variable(sp_die, pf);
564         }
565
566         /* *pf->fb_ops will be cached in libdw. Don't free it. */
567         pf->fb_ops = NULL;
568 }
569
570 /* Find probe point from its line number */
571 static void find_probe_point_by_line(struct probe_finder *pf)
572 {
573         Dwarf_Lines *lines;
574         Dwarf_Line *line;
575         size_t nlines, i;
576         Dwarf_Addr addr;
577         int lineno;
578         int ret;
579
580         ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
581         DIE_IF(ret != 0);
582
583         for (i = 0; i < nlines; i++) {
584                 line = dwarf_onesrcline(lines, i);
585                 dwarf_lineno(line, &lineno);
586                 if (lineno != pf->lno)
587                         continue;
588
589                 /* TODO: Get fileno from line, but how? */
590                 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
591                         continue;
592
593                 ret = dwarf_lineaddr(line, &addr);
594                 DIE_IF(ret != 0);
595                 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
596                          (int)i, lineno, (uintmax_t)addr);
597                 pf->addr = addr;
598
599                 convert_probe_point(NULL, pf);
600                 /* Continuing, because target line might be inlined. */
601         }
602 }
603
604 /* Find lines which match lazy pattern */
605 static int find_lazy_match_lines(struct list_head *head,
606                                  const char *fname, const char *pat)
607 {
608         char *fbuf, *p1, *p2;
609         int fd, line, nlines = 0;
610         struct stat st;
611
612         fd = open(fname, O_RDONLY);
613         if (fd < 0)
614                 die("failed to open %s", fname);
615         DIE_IF(fstat(fd, &st) < 0);
616         fbuf = xmalloc(st.st_size + 2);
617         DIE_IF(read(fd, fbuf, st.st_size) < 0);
618         close(fd);
619         fbuf[st.st_size] = '\n';        /* Dummy line */
620         fbuf[st.st_size + 1] = '\0';
621         p1 = fbuf;
622         line = 1;
623         while ((p2 = strchr(p1, '\n')) != NULL) {
624                 *p2 = '\0';
625                 if (strlazymatch(p1, pat)) {
626                         line_list__add_line(head, line);
627                         nlines++;
628                 }
629                 line++;
630                 p1 = p2 + 1;
631         }
632         free(fbuf);
633         return nlines;
634 }
635
636 /* Find probe points from lazy pattern  */
637 static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
638 {
639         Dwarf_Lines *lines;
640         Dwarf_Line *line;
641         size_t nlines, i;
642         Dwarf_Addr addr;
643         Dwarf_Die die_mem;
644         int lineno;
645         int ret;
646
647         if (list_empty(&pf->lcache)) {
648                 /* Matching lazy line pattern */
649                 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
650                                             pf->pev->point.lazy_line);
651                 if (ret <= 0)
652                         die("No matched lines found in %s.", pf->fname);
653         }
654
655         ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
656         DIE_IF(ret != 0);
657         for (i = 0; i < nlines; i++) {
658                 line = dwarf_onesrcline(lines, i);
659
660                 dwarf_lineno(line, &lineno);
661                 if (!line_list__has_line(&pf->lcache, lineno))
662                         continue;
663
664                 /* TODO: Get fileno from line, but how? */
665                 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
666                         continue;
667
668                 ret = dwarf_lineaddr(line, &addr);
669                 DIE_IF(ret != 0);
670                 if (sp_die) {
671                         /* Address filtering 1: does sp_die include addr? */
672                         if (!dwarf_haspc(sp_die, addr))
673                                 continue;
674                         /* Address filtering 2: No child include addr? */
675                         if (die_find_inlinefunc(sp_die, addr, &die_mem))
676                                 continue;
677                 }
678
679                 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
680                          (int)i, lineno, (unsigned long long)addr);
681                 pf->addr = addr;
682
683                 convert_probe_point(sp_die, pf);
684                 /* Continuing, because target line might be inlined. */
685         }
686         /* TODO: deallocate lines, but how? */
687 }
688
689 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
690 {
691         struct probe_finder *pf = (struct probe_finder *)data;
692         struct perf_probe_point *pp = &pf->pev->point;
693
694         if (pp->lazy_line)
695                 find_probe_point_lazy(in_die, pf);
696         else {
697                 /* Get probe address */
698                 pf->addr = die_get_entrypc(in_die);
699                 pf->addr += pp->offset;
700                 pr_debug("found inline addr: 0x%jx\n",
701                          (uintmax_t)pf->addr);
702
703                 convert_probe_point(in_die, pf);
704         }
705
706         return DWARF_CB_OK;
707 }
708
709 /* Search function from function name */
710 static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
711 {
712         struct probe_finder *pf = (struct probe_finder *)data;
713         struct perf_probe_point *pp = &pf->pev->point;
714
715         /* Check tag and diename */
716         if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
717             die_compare_name(sp_die, pp->function) != 0)
718                 return 0;
719
720         pf->fname = dwarf_decl_file(sp_die);
721         if (pp->line) { /* Function relative line */
722                 dwarf_decl_line(sp_die, &pf->lno);
723                 pf->lno += pp->line;
724                 find_probe_point_by_line(pf);
725         } else if (!dwarf_func_inline(sp_die)) {
726                 /* Real function */
727                 if (pp->lazy_line)
728                         find_probe_point_lazy(sp_die, pf);
729                 else {
730                         pf->addr = die_get_entrypc(sp_die);
731                         pf->addr += pp->offset;
732                         /* TODO: Check the address in this function */
733                         convert_probe_point(sp_die, pf);
734                 }
735         } else
736                 /* Inlined function: search instances */
737                 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
738
739         return 1; /* Exit; no same symbol in this CU. */
740 }
741
742 static void find_probe_point_by_func(struct probe_finder *pf)
743 {
744         dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
745 }
746
747 /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
748 int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
749                              struct kprobe_trace_event **tevs)
750 {
751         struct probe_finder pf = {.pev = pev};
752         struct perf_probe_point *pp = &pev->point;
753         Dwarf_Off off, noff;
754         size_t cuhl;
755         Dwarf_Die *diep;
756         Dwarf *dbg;
757
758         pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES);
759         *tevs = pf.tevs;
760         pf.ntevs = 0;
761
762         dbg = dwarf_begin(fd, DWARF_C_READ);
763         if (!dbg)
764                 return -ENOENT;
765
766         off = 0;
767         line_list__init(&pf.lcache);
768         /* Loop on CUs (Compilation Unit) */
769         while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
770                 /* Get the DIE(Debugging Information Entry) of this CU */
771                 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
772                 if (!diep)
773                         continue;
774
775                 /* Check if target file is included. */
776                 if (pp->file)
777                         pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
778                 else
779                         pf.fname = NULL;
780
781                 if (!pp->file || pf.fname) {
782                         if (pp->function)
783                                 find_probe_point_by_func(&pf);
784                         else if (pp->lazy_line)
785                                 find_probe_point_lazy(NULL, &pf);
786                         else {
787                                 pf.lno = pp->line;
788                                 find_probe_point_by_line(&pf);
789                         }
790                 }
791                 off = noff;
792         }
793         line_list__free(&pf.lcache);
794         dwarf_end(dbg);
795
796         return pf.ntevs;
797 }
798
799 /* Reverse search */
800 int find_perf_probe_point(int fd, unsigned long addr,
801                           struct perf_probe_point *ppt)
802 {
803         Dwarf_Die cudie, spdie, indie;
804         Dwarf *dbg;
805         Dwarf_Line *line;
806         Dwarf_Addr laddr, eaddr;
807         const char *tmp;
808         int lineno, ret = 0;
809
810         dbg = dwarf_begin(fd, DWARF_C_READ);
811         if (!dbg)
812                 return -ENOENT;
813
814         /* Find cu die */
815         if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie))
816                 return -EINVAL;
817
818         /* Find a corresponding line */
819         line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
820         if (line) {
821                 dwarf_lineaddr(line, &laddr);
822                 if ((Dwarf_Addr)addr == laddr) {
823                         dwarf_lineno(line, &lineno);
824                         ppt->line = lineno;
825
826                         tmp = dwarf_linesrc(line, NULL, NULL);
827                         DIE_IF(!tmp);
828                         ppt->file = xstrdup(tmp);
829                         ret = 1;
830                 }
831         }
832
833         /* Find a corresponding function */
834         if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
835                 tmp = dwarf_diename(&spdie);
836                 if (!tmp)
837                         goto end;
838
839                 dwarf_entrypc(&spdie, &eaddr);
840                 if (!lineno) {
841                         /* We don't have a line number, let's use offset */
842                         ppt->function = xstrdup(tmp);
843                         ppt->offset = addr - (unsigned long)eaddr;
844                         ret = 1;
845                         goto end;
846                 }
847                 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) {
848                         /* addr in an inline function */
849                         tmp = dwarf_diename(&indie);
850                         if (!tmp)
851                                 goto end;
852                         dwarf_decl_line(&indie, &lineno);
853                 } else {
854                         if (eaddr == addr)      /* No offset: function entry */
855                                 lineno = ppt->line;
856                         else
857                                 dwarf_decl_line(&spdie, &lineno);
858                 }
859                 ppt->function = xstrdup(tmp);
860                 ppt->line -= lineno;    /* Make a relative line number */
861         }
862
863 end:
864         dwarf_end(dbg);
865         return ret;
866 }
867
868
869 /* Find line range from its line number */
870 static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
871 {
872         Dwarf_Lines *lines;
873         Dwarf_Line *line;
874         size_t nlines, i;
875         Dwarf_Addr addr;
876         int lineno;
877         int ret;
878         const char *src;
879         Dwarf_Die die_mem;
880
881         line_list__init(&lf->lr->line_list);
882         ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
883         DIE_IF(ret != 0);
884
885         for (i = 0; i < nlines; i++) {
886                 line = dwarf_onesrcline(lines, i);
887                 ret = dwarf_lineno(line, &lineno);
888                 DIE_IF(ret != 0);
889                 if (lf->lno_s > lineno || lf->lno_e < lineno)
890                         continue;
891
892                 if (sp_die) {
893                         /* Address filtering 1: does sp_die include addr? */
894                         ret = dwarf_lineaddr(line, &addr);
895                         DIE_IF(ret != 0);
896                         if (!dwarf_haspc(sp_die, addr))
897                                 continue;
898
899                         /* Address filtering 2: No child include addr? */
900                         if (die_find_inlinefunc(sp_die, addr, &die_mem))
901                                 continue;
902                 }
903
904                 /* TODO: Get fileno from line, but how? */
905                 src = dwarf_linesrc(line, NULL, NULL);
906                 if (strtailcmp(src, lf->fname) != 0)
907                         continue;
908
909                 /* Copy real path */
910                 if (!lf->lr->path)
911                         lf->lr->path = xstrdup(src);
912                 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
913         }
914         /* Update status */
915         if (!list_empty(&lf->lr->line_list))
916                 lf->found = 1;
917         else {
918                 free(lf->lr->path);
919                 lf->lr->path = NULL;
920         }
921 }
922
923 static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
924 {
925         find_line_range_by_line(in_die, (struct line_finder *)data);
926         return DWARF_CB_ABORT;  /* No need to find other instances */
927 }
928
929 /* Search function from function name */
930 static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
931 {
932         struct line_finder *lf = (struct line_finder *)data;
933         struct line_range *lr = lf->lr;
934
935         if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
936             die_compare_name(sp_die, lr->function) == 0) {
937                 lf->fname = dwarf_decl_file(sp_die);
938                 dwarf_decl_line(sp_die, &lr->offset);
939                 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
940                 lf->lno_s = lr->offset + lr->start;
941                 if (!lr->end)
942                         lf->lno_e = INT_MAX;
943                 else
944                         lf->lno_e = lr->offset + lr->end;
945                 lr->start = lf->lno_s;
946                 lr->end = lf->lno_e;
947                 if (dwarf_func_inline(sp_die))
948                         dwarf_func_inline_instances(sp_die,
949                                                     line_range_inline_cb, lf);
950                 else
951                         find_line_range_by_line(sp_die, lf);
952                 return 1;
953         }
954         return 0;
955 }
956
957 static void find_line_range_by_func(struct line_finder *lf)
958 {
959         dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
960 }
961
962 int find_line_range(int fd, struct line_range *lr)
963 {
964         struct line_finder lf = {.lr = lr, .found = 0};
965         int ret;
966         Dwarf_Off off = 0, noff;
967         size_t cuhl;
968         Dwarf_Die *diep;
969         Dwarf *dbg;
970
971         dbg = dwarf_begin(fd, DWARF_C_READ);
972         if (!dbg)
973                 return -ENOENT;
974
975         /* Loop on CUs (Compilation Unit) */
976         while (!lf.found) {
977                 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
978                 if (ret != 0)
979                         break;
980
981                 /* Get the DIE(Debugging Information Entry) of this CU */
982                 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
983                 if (!diep)
984                         continue;
985
986                 /* Check if target file is included. */
987                 if (lr->file)
988                         lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
989                 else
990                         lf.fname = 0;
991
992                 if (!lr->file || lf.fname) {
993                         if (lr->function)
994                                 find_line_range_by_func(&lf);
995                         else {
996                                 lf.lno_s = lr->start;
997                                 if (!lr->end)
998                                         lf.lno_e = INT_MAX;
999                                 else
1000                                         lf.lno_e = lr->end;
1001                                 find_line_range_by_line(NULL, &lf);
1002                         }
1003                 }
1004                 off = noff;
1005         }
1006         pr_debug("path: %lx\n", (unsigned long)lr->path);
1007         dwarf_end(dbg);
1008         return lf.found;
1009 }
1010