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 <dwarf-regs.h>
34
35 #include <linux/bitops.h>
36 #include "event.h"
37 #include "debug.h"
38 #include "util.h"
39 #include "symbol.h"
40 #include "probe-finder.h"
41
42 /* Kprobe tracer basic type is up to u64 */
43 #define MAX_BASIC_TYPE_BITS 64
44
45 /* Line number list operations */
46
47 /* Add a line to line number list */
line_list__add_line(struct list_head * head,int line)48 static int line_list__add_line(struct list_head *head, int line)
49 {
50 struct line_node *ln;
51 struct list_head *p;
52
53 /* Reverse search, because new line will be the last one */
54 list_for_each_entry_reverse(ln, head, list) {
55 if (ln->line < line) {
56 p = &ln->list;
57 goto found;
58 } else if (ln->line == line) /* Already exist */
59 return 1;
60 }
61 /* List is empty, or the smallest entry */
62 p = head;
63 found:
64 pr_debug("line list: add a line %u\n", line);
65 ln = zalloc(sizeof(struct line_node));
66 if (ln == NULL)
67 return -ENOMEM;
68 ln->line = line;
69 INIT_LIST_HEAD(&ln->list);
70 list_add(&ln->list, p);
71 return 0;
72 }
73
74 /* Check if the line in line number list */
line_list__has_line(struct list_head * head,int line)75 static int line_list__has_line(struct list_head *head, int line)
76 {
77 struct line_node *ln;
78
79 /* Reverse search, because new line will be the last one */
80 list_for_each_entry(ln, head, list)
81 if (ln->line == line)
82 return 1;
83
84 return 0;
85 }
86
87 /* Init line number list */
line_list__init(struct list_head * head)88 static void line_list__init(struct list_head *head)
89 {
90 INIT_LIST_HEAD(head);
91 }
92
93 /* Free line number list */
line_list__free(struct list_head * head)94 static void line_list__free(struct list_head *head)
95 {
96 struct line_node *ln;
97 while (!list_empty(head)) {
98 ln = list_first_entry(head, struct line_node, list);
99 list_del(&ln->list);
100 free(ln);
101 }
102 }
103
104 /* Dwarf FL wrappers */
105 static char *debuginfo_path; /* Currently dummy */
106
107 static const Dwfl_Callbacks offline_callbacks = {
108 .find_debuginfo = dwfl_standard_find_debuginfo,
109 .debuginfo_path = &debuginfo_path,
110
111 .section_address = dwfl_offline_section_address,
112
113 /* We use this table for core files too. */
114 .find_elf = dwfl_build_id_find_elf,
115 };
116
117 /* Get a Dwarf from offline image */
debuginfo__init_offline_dwarf(struct debuginfo * self,const char * path)118 static int debuginfo__init_offline_dwarf(struct debuginfo *self,
119 const char *path)
120 {
121 int fd;
122
123 fd = open(path, O_RDONLY);
124 if (fd < 0)
125 return fd;
126
127 self->dwfl = dwfl_begin(&offline_callbacks);
128 if (!self->dwfl)
129 goto error;
130
131 self->mod = dwfl_report_offline(self->dwfl, "", "", fd);
132 if (!self->mod)
133 goto error;
134
135 self->dbg = dwfl_module_getdwarf(self->mod, &self->bias);
136 if (!self->dbg)
137 goto error;
138
139 return 0;
140 error:
141 if (self->dwfl)
142 dwfl_end(self->dwfl);
143 else
144 close(fd);
145 memset(self, 0, sizeof(*self));
146
147 return -ENOENT;
148 }
149
150 #if _ELFUTILS_PREREQ(0, 148)
151 /* This method is buggy if elfutils is older than 0.148 */
__linux_kernel_find_elf(Dwfl_Module * mod,void ** userdata,const char * module_name,Dwarf_Addr base,char ** file_name,Elf ** elfp)152 static int __linux_kernel_find_elf(Dwfl_Module *mod,
153 void **userdata,
154 const char *module_name,
155 Dwarf_Addr base,
156 char **file_name, Elf **elfp)
157 {
158 int fd;
159 const char *path = kernel_get_module_path(module_name);
160
161 pr_debug2("Use file %s for %s\n", path, module_name);
162 if (path) {
163 fd = open(path, O_RDONLY);
164 if (fd >= 0) {
165 *file_name = strdup(path);
166 return fd;
167 }
168 }
169 /* If failed, try to call standard method */
170 return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
171 file_name, elfp);
172 }
173
174 static const Dwfl_Callbacks kernel_callbacks = {
175 .find_debuginfo = dwfl_standard_find_debuginfo,
176 .debuginfo_path = &debuginfo_path,
177
178 .find_elf = __linux_kernel_find_elf,
179 .section_address = dwfl_linux_kernel_module_section_address,
180 };
181
182 /* Get a Dwarf from live kernel image */
debuginfo__init_online_kernel_dwarf(struct debuginfo * self,Dwarf_Addr addr)183 static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
184 Dwarf_Addr addr)
185 {
186 self->dwfl = dwfl_begin(&kernel_callbacks);
187 if (!self->dwfl)
188 return -EINVAL;
189
190 /* Load the kernel dwarves: Don't care the result here */
191 dwfl_linux_kernel_report_kernel(self->dwfl);
192 dwfl_linux_kernel_report_modules(self->dwfl);
193
194 self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias);
195 /* Here, check whether we could get a real dwarf */
196 if (!self->dbg) {
197 pr_debug("Failed to find kernel dwarf at %lx\n",
198 (unsigned long)addr);
199 dwfl_end(self->dwfl);
200 memset(self, 0, sizeof(*self));
201 return -ENOENT;
202 }
203
204 return 0;
205 }
206 #endif
207
debuginfo__new(const char * path)208 struct debuginfo *debuginfo__new(const char *path)
209 {
210 struct debuginfo *self = zalloc(sizeof(struct debuginfo));
211 if (!self)
212 return NULL;
213
214 if (debuginfo__init_offline_dwarf(self, path) < 0) {
215 free(self);
216 self = NULL;
217 }
218
219 return self;
220 }
221
debuginfo__new_online_kernel(unsigned long addr)222 struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
223 {
224 struct debuginfo *self = zalloc(sizeof(struct debuginfo));
225 if (!self)
226 return NULL;
227
228 if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) {
229 free(self);
230 self = NULL;
231 }
232
233 return self;
234 }
235
debuginfo__delete(struct debuginfo * self)236 void debuginfo__delete(struct debuginfo *self)
237 {
238 if (self) {
239 if (self->dwfl)
240 dwfl_end(self->dwfl);
241 free(self);
242 }
243 }
244
245 /*
246 * Probe finder related functions
247 */
248
alloc_trace_arg_ref(long offs)249 static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
250 {
251 struct probe_trace_arg_ref *ref;
252 ref = zalloc(sizeof(struct probe_trace_arg_ref));
253 if (ref != NULL)
254 ref->offset = offs;
255 return ref;
256 }
257
258 /*
259 * Convert a location into trace_arg.
260 * If tvar == NULL, this just checks variable can be converted.
261 */
convert_variable_location(Dwarf_Die * vr_die,Dwarf_Addr addr,Dwarf_Op * fb_ops,struct probe_trace_arg * tvar)262 static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
263 Dwarf_Op *fb_ops,
264 struct probe_trace_arg *tvar)
265 {
266 Dwarf_Attribute attr;
267 Dwarf_Op *op;
268 size_t nops;
269 unsigned int regn;
270 Dwarf_Word offs = 0;
271 bool ref = false;
272 const char *regs;
273 int ret;
274
275 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
276 goto static_var;
277
278 /* TODO: handle more than 1 exprs */
279 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
280 dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
281 nops == 0) {
282 /* TODO: Support const_value */
283 return -ENOENT;
284 }
285
286 if (op->atom == DW_OP_addr) {
287 static_var:
288 if (!tvar)
289 return 0;
290 /* Static variables on memory (not stack), make @varname */
291 ret = strlen(dwarf_diename(vr_die));
292 tvar->value = zalloc(ret + 2);
293 if (tvar->value == NULL)
294 return -ENOMEM;
295 snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
296 tvar->ref = alloc_trace_arg_ref((long)offs);
297 if (tvar->ref == NULL)
298 return -ENOMEM;
299 return 0;
300 }
301
302 /* If this is based on frame buffer, set the offset */
303 if (op->atom == DW_OP_fbreg) {
304 if (fb_ops == NULL)
305 return -ENOTSUP;
306 ref = true;
307 offs = op->number;
308 op = &fb_ops[0];
309 }
310
311 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
312 regn = op->atom - DW_OP_breg0;
313 offs += op->number;
314 ref = true;
315 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
316 regn = op->atom - DW_OP_reg0;
317 } else if (op->atom == DW_OP_bregx) {
318 regn = op->number;
319 offs += op->number2;
320 ref = true;
321 } else if (op->atom == DW_OP_regx) {
322 regn = op->number;
323 } else {
324 pr_debug("DW_OP %x is not supported.\n", op->atom);
325 return -ENOTSUP;
326 }
327
328 if (!tvar)
329 return 0;
330
331 regs = get_arch_regstr(regn);
332 if (!regs) {
333 /* This should be a bug in DWARF or this tool */
334 pr_warning("Mapping for the register number %u "
335 "missing on this architecture.\n", regn);
336 return -ERANGE;
337 }
338
339 tvar->value = strdup(regs);
340 if (tvar->value == NULL)
341 return -ENOMEM;
342
343 if (ref) {
344 tvar->ref = alloc_trace_arg_ref((long)offs);
345 if (tvar->ref == NULL)
346 return -ENOMEM;
347 }
348 return 0;
349 }
350
351 #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long))
352
convert_variable_type(Dwarf_Die * vr_die,struct probe_trace_arg * tvar,const char * cast)353 static int convert_variable_type(Dwarf_Die *vr_die,
354 struct probe_trace_arg *tvar,
355 const char *cast)
356 {
357 struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
358 Dwarf_Die type;
359 char buf[16];
360 int bsize, boffs, total;
361 int ret;
362
363 /* TODO: check all types */
364 if (cast && strcmp(cast, "string") != 0) {
365 /* Non string type is OK */
366 tvar->type = strdup(cast);
367 return (tvar->type == NULL) ? -ENOMEM : 0;
368 }
369
370 bsize = dwarf_bitsize(vr_die);
371 if (bsize > 0) {
372 /* This is a bitfield */
373 boffs = dwarf_bitoffset(vr_die);
374 total = dwarf_bytesize(vr_die);
375 if (boffs < 0 || total < 0)
376 return -ENOENT;
377 ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs,
378 BYTES_TO_BITS(total));
379 goto formatted;
380 }
381
382 if (die_get_real_type(vr_die, &type) == NULL) {
383 pr_warning("Failed to get a type information of %s.\n",
384 dwarf_diename(vr_die));
385 return -ENOENT;
386 }
387
388 pr_debug("%s type is %s.\n",
389 dwarf_diename(vr_die), dwarf_diename(&type));
390
391 if (cast && strcmp(cast, "string") == 0) { /* String type */
392 ret = dwarf_tag(&type);
393 if (ret != DW_TAG_pointer_type &&
394 ret != DW_TAG_array_type) {
395 pr_warning("Failed to cast into string: "
396 "%s(%s) is not a pointer nor array.\n",
397 dwarf_diename(vr_die), dwarf_diename(&type));
398 return -EINVAL;
399 }
400 if (die_get_real_type(&type, &type) == NULL) {
401 pr_warning("Failed to get a type"
402 " information.\n");
403 return -ENOENT;
404 }
405 if (ret == DW_TAG_pointer_type) {
406 while (*ref_ptr)
407 ref_ptr = &(*ref_ptr)->next;
408 /* Add new reference with offset +0 */
409 *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
410 if (*ref_ptr == NULL) {
411 pr_warning("Out of memory error\n");
412 return -ENOMEM;
413 }
414 }
415 if (!die_compare_name(&type, "char") &&
416 !die_compare_name(&type, "unsigned char")) {
417 pr_warning("Failed to cast into string: "
418 "%s is not (unsigned) char *.\n",
419 dwarf_diename(vr_die));
420 return -EINVAL;
421 }
422 tvar->type = strdup(cast);
423 return (tvar->type == NULL) ? -ENOMEM : 0;
424 }
425
426 ret = dwarf_bytesize(&type);
427 if (ret <= 0)
428 /* No size ... try to use default type */
429 return 0;
430 ret = BYTES_TO_BITS(ret);
431
432 /* Check the bitwidth */
433 if (ret > MAX_BASIC_TYPE_BITS) {
434 pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n",
435 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
436 ret = MAX_BASIC_TYPE_BITS;
437 }
438 ret = snprintf(buf, 16, "%c%d",
439 die_is_signed_type(&type) ? 's' : 'u', ret);
440
441 formatted:
442 if (ret < 0 || ret >= 16) {
443 if (ret >= 16)
444 ret = -E2BIG;
445 pr_warning("Failed to convert variable type: %s\n",
446 strerror(-ret));
447 return ret;
448 }
449 tvar->type = strdup(buf);
450 if (tvar->type == NULL)
451 return -ENOMEM;
452 return 0;
453 }
454
convert_variable_fields(Dwarf_Die * vr_die,const char * varname,struct perf_probe_arg_field * field,struct probe_trace_arg_ref ** ref_ptr,Dwarf_Die * die_mem)455 static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
456 struct perf_probe_arg_field *field,
457 struct probe_trace_arg_ref **ref_ptr,
458 Dwarf_Die *die_mem)
459 {
460 struct probe_trace_arg_ref *ref = *ref_ptr;
461 Dwarf_Die type;
462 Dwarf_Word offs;
463 int ret, tag;
464
465 pr_debug("converting %s in %s\n", field->name, varname);
466 if (die_get_real_type(vr_die, &type) == NULL) {
467 pr_warning("Failed to get the type of %s.\n", varname);
468 return -ENOENT;
469 }
470 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
471 tag = dwarf_tag(&type);
472
473 if (field->name[0] == '[' &&
474 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
475 if (field->next)
476 /* Save original type for next field */
477 memcpy(die_mem, &type, sizeof(*die_mem));
478 /* Get the type of this array */
479 if (die_get_real_type(&type, &type) == NULL) {
480 pr_warning("Failed to get the type of %s.\n", varname);
481 return -ENOENT;
482 }
483 pr_debug2("Array real type: (%x)\n",
484 (unsigned)dwarf_dieoffset(&type));
485 if (tag == DW_TAG_pointer_type) {
486 ref = zalloc(sizeof(struct probe_trace_arg_ref));
487 if (ref == NULL)
488 return -ENOMEM;
489 if (*ref_ptr)
490 (*ref_ptr)->next = ref;
491 else
492 *ref_ptr = ref;
493 }
494 ref->offset += dwarf_bytesize(&type) * field->index;
495 if (!field->next)
496 /* Save vr_die for converting types */
497 memcpy(die_mem, vr_die, sizeof(*die_mem));
498 goto next;
499 } else if (tag == DW_TAG_pointer_type) {
500 /* Check the pointer and dereference */
501 if (!field->ref) {
502 pr_err("Semantic error: %s must be referred by '->'\n",
503 field->name);
504 return -EINVAL;
505 }
506 /* Get the type pointed by this pointer */
507 if (die_get_real_type(&type, &type) == NULL) {
508 pr_warning("Failed to get the type of %s.\n", varname);
509 return -ENOENT;
510 }
511 /* Verify it is a data structure */
512 tag = dwarf_tag(&type);
513 if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
514 pr_warning("%s is not a data structure nor an union.\n",
515 varname);
516 return -EINVAL;
517 }
518
519 ref = zalloc(sizeof(struct probe_trace_arg_ref));
520 if (ref == NULL)
521 return -ENOMEM;
522 if (*ref_ptr)
523 (*ref_ptr)->next = ref;
524 else
525 *ref_ptr = ref;
526 } else {
527 /* Verify it is a data structure */
528 if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
529 pr_warning("%s is not a data structure nor an union.\n",
530 varname);
531 return -EINVAL;
532 }
533 if (field->name[0] == '[') {
534 pr_err("Semantic error: %s is not a pointor"
535 " nor array.\n", varname);
536 return -EINVAL;
537 }
538 if (field->ref) {
539 pr_err("Semantic error: %s must be referred by '.'\n",
540 field->name);
541 return -EINVAL;
542 }
543 if (!ref) {
544 pr_warning("Structure on a register is not "
545 "supported yet.\n");
546 return -ENOTSUP;
547 }
548 }
549
550 if (die_find_member(&type, field->name, die_mem) == NULL) {
551 pr_warning("%s(tyep:%s) has no member %s.\n", varname,
552 dwarf_diename(&type), field->name);
553 return -EINVAL;
554 }
555
556 /* Get the offset of the field */
557 if (tag == DW_TAG_union_type) {
558 offs = 0;
559 } else {
560 ret = die_get_data_member_location(die_mem, &offs);
561 if (ret < 0) {
562 pr_warning("Failed to get the offset of %s.\n",
563 field->name);
564 return ret;
565 }
566 }
567 ref->offset += (long)offs;
568
569 next:
570 /* Converting next field */
571 if (field->next)
572 return convert_variable_fields(die_mem, field->name,
573 field->next, &ref, die_mem);
574 else
575 return 0;
576 }
577
578 /* Show a variables in kprobe event format */
convert_variable(Dwarf_Die * vr_die,struct probe_finder * pf)579 static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
580 {
581 Dwarf_Die die_mem;
582 int ret;
583
584 pr_debug("Converting variable %s into trace event.\n",
585 dwarf_diename(vr_die));
586
587 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
588 pf->tvar);
589 if (ret == -ENOENT)
590 pr_err("Failed to find the location of %s at this address.\n"
591 " Perhaps, it has been optimized out.\n", pf->pvar->var);
592 else if (ret == -ENOTSUP)
593 pr_err("Sorry, we don't support this variable location yet.\n");
594 else if (pf->pvar->field) {
595 ret = convert_variable_fields(vr_die, pf->pvar->var,
596 pf->pvar->field, &pf->tvar->ref,
597 &die_mem);
598 vr_die = &die_mem;
599 }
600 if (ret == 0)
601 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
602 /* *expr will be cached in libdw. Don't free it. */
603 return ret;
604 }
605
606 /* Find a variable in a scope DIE */
find_variable(Dwarf_Die * sc_die,struct probe_finder * pf)607 static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
608 {
609 Dwarf_Die vr_die;
610 char buf[32], *ptr;
611 int ret = 0;
612
613 if (!is_c_varname(pf->pvar->var)) {
614 /* Copy raw parameters */
615 pf->tvar->value = strdup(pf->pvar->var);
616 if (pf->tvar->value == NULL)
617 return -ENOMEM;
618 if (pf->pvar->type) {
619 pf->tvar->type = strdup(pf->pvar->type);
620 if (pf->tvar->type == NULL)
621 return -ENOMEM;
622 }
623 if (pf->pvar->name) {
624 pf->tvar->name = strdup(pf->pvar->name);
625 if (pf->tvar->name == NULL)
626 return -ENOMEM;
627 } else
628 pf->tvar->name = NULL;
629 return 0;
630 }
631
632 if (pf->pvar->name)
633 pf->tvar->name = strdup(pf->pvar->name);
634 else {
635 ret = synthesize_perf_probe_arg(pf->pvar, buf, 32);
636 if (ret < 0)
637 return ret;
638 ptr = strchr(buf, ':'); /* Change type separator to _ */
639 if (ptr)
640 *ptr = '_';
641 pf->tvar->name = strdup(buf);
642 }
643 if (pf->tvar->name == NULL)
644 return -ENOMEM;
645
646 pr_debug("Searching '%s' variable in context.\n", pf->pvar->var);
647 /* Search child die for local variables and parameters. */
648 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
649 /* Search again in global variables */
650 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
651 ret = -ENOENT;
652 }
653 if (ret >= 0)
654 ret = convert_variable(&vr_die, pf);
655
656 if (ret < 0)
657 pr_warning("Failed to find '%s' in this function.\n",
658 pf->pvar->var);
659 return ret;
660 }
661
662 /* Convert subprogram DIE to trace point */
convert_to_trace_point(Dwarf_Die * sp_die,Dwfl_Module * mod,Dwarf_Addr paddr,bool retprobe,struct probe_trace_point * tp)663 static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
664 Dwarf_Addr paddr, bool retprobe,
665 struct probe_trace_point *tp)
666 {
667 Dwarf_Addr eaddr, highaddr;
668 GElf_Sym sym;
669 const char *symbol;
670
671 /* Verify the address is correct */
672 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
673 pr_warning("Failed to get entry address of %s\n",
674 dwarf_diename(sp_die));
675 return -ENOENT;
676 }
677 if (dwarf_highpc(sp_die, &highaddr) != 0) {
678 pr_warning("Failed to get end address of %s\n",
679 dwarf_diename(sp_die));
680 return -ENOENT;
681 }
682 if (paddr > highaddr) {
683 pr_warning("Offset specified is greater than size of %s\n",
684 dwarf_diename(sp_die));
685 return -EINVAL;
686 }
687
688 /* Get an appropriate symbol from symtab */
689 symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
690 if (!symbol) {
691 pr_warning("Failed to find symbol at 0x%lx\n",
692 (unsigned long)paddr);
693 return -ENOENT;
694 }
695 tp->offset = (unsigned long)(paddr - sym.st_value);
696 tp->symbol = strdup(symbol);
697 if (!tp->symbol)
698 return -ENOMEM;
699
700 /* Return probe must be on the head of a subprogram */
701 if (retprobe) {
702 if (eaddr != paddr) {
703 pr_warning("Return probe must be on the head of"
704 " a real function.\n");
705 return -EINVAL;
706 }
707 tp->retprobe = true;
708 }
709
710 return 0;
711 }
712
713 /* Call probe_finder callback with scope DIE */
call_probe_finder(Dwarf_Die * sc_die,struct probe_finder * pf)714 static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
715 {
716 Dwarf_Attribute fb_attr;
717 size_t nops;
718 int ret;
719
720 if (!sc_die) {
721 pr_err("Caller must pass a scope DIE. Program error.\n");
722 return -EINVAL;
723 }
724
725 /* If not a real subprogram, find a real one */
726 if (!die_is_func_def(sc_die)) {
727 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
728 pr_warning("Failed to find probe point in any "
729 "functions.\n");
730 return -ENOENT;
731 }
732 } else
733 memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die));
734
735 /* Get the frame base attribute/ops from subprogram */
736 dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr);
737 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
738 if (ret <= 0 || nops == 0) {
739 pf->fb_ops = NULL;
740 #if _ELFUTILS_PREREQ(0, 142)
741 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
742 pf->cfi != NULL) {
743 Dwarf_Frame *frame;
744 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
745 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
746 pr_warning("Failed to get call frame on 0x%jx\n",
747 (uintmax_t)pf->addr);
748 return -ENOENT;
749 }
750 #endif
751 }
752
753 /* Call finder's callback handler */
754 ret = pf->callback(sc_die, pf);
755
756 /* *pf->fb_ops will be cached in libdw. Don't free it. */
757 pf->fb_ops = NULL;
758
759 return ret;
760 }
761
762 struct find_scope_param {
763 const char *function;
764 const char *file;
765 int line;
766 int diff;
767 Dwarf_Die *die_mem;
768 bool found;
769 };
770
find_best_scope_cb(Dwarf_Die * fn_die,void * data)771 static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
772 {
773 struct find_scope_param *fsp = data;
774 const char *file;
775 int lno;
776
777 /* Skip if declared file name does not match */
778 if (fsp->file) {
779 file = dwarf_decl_file(fn_die);
780 if (!file || strcmp(fsp->file, file) != 0)
781 return 0;
782 }
783 /* If the function name is given, that's what user expects */
784 if (fsp->function) {
785 if (die_compare_name(fn_die, fsp->function)) {
786 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
787 fsp->found = true;
788 return 1;
789 }
790 } else {
791 /* With the line number, find the nearest declared DIE */
792 dwarf_decl_line(fn_die, &lno);
793 if (lno < fsp->line && fsp->diff > fsp->line - lno) {
794 /* Keep a candidate and continue */
795 fsp->diff = fsp->line - lno;
796 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
797 fsp->found = true;
798 }
799 }
800 return 0;
801 }
802
803 /* Find an appropriate scope fits to given conditions */
find_best_scope(struct probe_finder * pf,Dwarf_Die * die_mem)804 static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
805 {
806 struct find_scope_param fsp = {
807 .function = pf->pev->point.function,
808 .file = pf->fname,
809 .line = pf->lno,
810 .diff = INT_MAX,
811 .die_mem = die_mem,
812 .found = false,
813 };
814
815 cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp);
816
817 return fsp.found ? die_mem : NULL;
818 }
819
probe_point_line_walker(const char * fname,int lineno,Dwarf_Addr addr,void * data)820 static int probe_point_line_walker(const char *fname, int lineno,
821 Dwarf_Addr addr, void *data)
822 {
823 struct probe_finder *pf = data;
824 Dwarf_Die *sc_die, die_mem;
825 int ret;
826
827 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
828 return 0;
829
830 pf->addr = addr;
831 sc_die = find_best_scope(pf, &die_mem);
832 if (!sc_die) {
833 pr_warning("Failed to find scope of probe point.\n");
834 return -ENOENT;
835 }
836
837 ret = call_probe_finder(sc_die, pf);
838
839 /* Continue if no error, because the line will be in inline function */
840 return ret < 0 ? ret : 0;
841 }
842
843 /* Find probe point from its line number */
find_probe_point_by_line(struct probe_finder * pf)844 static int find_probe_point_by_line(struct probe_finder *pf)
845 {
846 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
847 }
848
849 /* Find lines which match lazy pattern */
find_lazy_match_lines(struct list_head * head,const char * fname,const char * pat)850 static int find_lazy_match_lines(struct list_head *head,
851 const char *fname, const char *pat)
852 {
853 FILE *fp;
854 char *line = NULL;
855 size_t line_len;
856 ssize_t len;
857 int count = 0, linenum = 1;
858
859 fp = fopen(fname, "r");
860 if (!fp) {
861 pr_warning("Failed to open %s: %s\n", fname, strerror(errno));
862 return -errno;
863 }
864
865 while ((len = getline(&line, &line_len, fp)) > 0) {
866
867 if (line[len - 1] == '\n')
868 line[len - 1] = '\0';
869
870 if (strlazymatch(line, pat)) {
871 line_list__add_line(head, linenum);
872 count++;
873 }
874 linenum++;
875 }
876
877 if (ferror(fp))
878 count = -errno;
879 free(line);
880 fclose(fp);
881
882 if (count == 0)
883 pr_debug("No matched lines found in %s.\n", fname);
884 return count;
885 }
886
probe_point_lazy_walker(const char * fname,int lineno,Dwarf_Addr addr,void * data)887 static int probe_point_lazy_walker(const char *fname, int lineno,
888 Dwarf_Addr addr, void *data)
889 {
890 struct probe_finder *pf = data;
891 Dwarf_Die *sc_die, die_mem;
892 int ret;
893
894 if (!line_list__has_line(&pf->lcache, lineno) ||
895 strtailcmp(fname, pf->fname) != 0)
896 return 0;
897
898 pr_debug("Probe line found: line:%d addr:0x%llx\n",
899 lineno, (unsigned long long)addr);
900 pf->addr = addr;
901 pf->lno = lineno;
902 sc_die = find_best_scope(pf, &die_mem);
903 if (!sc_die) {
904 pr_warning("Failed to find scope of probe point.\n");
905 return -ENOENT;
906 }
907
908 ret = call_probe_finder(sc_die, pf);
909
910 /*
911 * Continue if no error, because the lazy pattern will match
912 * to other lines
913 */
914 return ret < 0 ? ret : 0;
915 }
916
917 /* Find probe points from lazy pattern */
find_probe_point_lazy(Dwarf_Die * sp_die,struct probe_finder * pf)918 static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
919 {
920 int ret = 0;
921
922 if (list_empty(&pf->lcache)) {
923 /* Matching lazy line pattern */
924 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
925 pf->pev->point.lazy_line);
926 if (ret <= 0)
927 return ret;
928 }
929
930 return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
931 }
932
probe_point_inline_cb(Dwarf_Die * in_die,void * data)933 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
934 {
935 struct probe_finder *pf = data;
936 struct perf_probe_point *pp = &pf->pev->point;
937 Dwarf_Addr addr;
938 int ret;
939
940 if (pp->lazy_line)
941 ret = find_probe_point_lazy(in_die, pf);
942 else {
943 /* Get probe address */
944 if (dwarf_entrypc(in_die, &addr) != 0) {
945 pr_warning("Failed to get entry address of %s.\n",
946 dwarf_diename(in_die));
947 return -ENOENT;
948 }
949 pf->addr = addr;
950 pf->addr += pp->offset;
951 pr_debug("found inline addr: 0x%jx\n",
952 (uintmax_t)pf->addr);
953
954 ret = call_probe_finder(in_die, pf);
955 }
956
957 return ret;
958 }
959
960 /* Callback parameter with return value for libdw */
961 struct dwarf_callback_param {
962 void *data;
963 int retval;
964 };
965
966 /* Search function from function name */
probe_point_search_cb(Dwarf_Die * sp_die,void * data)967 static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
968 {
969 struct dwarf_callback_param *param = data;
970 struct probe_finder *pf = param->data;
971 struct perf_probe_point *pp = &pf->pev->point;
972
973 /* Check tag and diename */
974 if (!die_is_func_def(sp_die) ||
975 !die_compare_name(sp_die, pp->function))
976 return DWARF_CB_OK;
977
978 /* Check declared file */
979 if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die)))
980 return DWARF_CB_OK;
981
982 pf->fname = dwarf_decl_file(sp_die);
983 if (pp->line) { /* Function relative line */
984 dwarf_decl_line(sp_die, &pf->lno);
985 pf->lno += pp->line;
986 param->retval = find_probe_point_by_line(pf);
987 } else if (!dwarf_func_inline(sp_die)) {
988 /* Real function */
989 if (pp->lazy_line)
990 param->retval = find_probe_point_lazy(sp_die, pf);
991 else {
992 if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
993 pr_warning("Failed to get entry address of "
994 "%s.\n", dwarf_diename(sp_die));
995 param->retval = -ENOENT;
996 return DWARF_CB_ABORT;
997 }
998 pf->addr += pp->offset;
999 /* TODO: Check the address in this function */
1000 param->retval = call_probe_finder(sp_die, pf);
1001 }
1002 } else
1003 /* Inlined function: search instances */
1004 param->retval = die_walk_instances(sp_die,
1005 probe_point_inline_cb, (void *)pf);
1006
1007 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
1008 }
1009
find_probe_point_by_func(struct probe_finder * pf)1010 static int find_probe_point_by_func(struct probe_finder *pf)
1011 {
1012 struct dwarf_callback_param _param = {.data = (void *)pf,
1013 .retval = 0};
1014 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0);
1015 return _param.retval;
1016 }
1017
1018 struct pubname_callback_param {
1019 char *function;
1020 char *file;
1021 Dwarf_Die *cu_die;
1022 Dwarf_Die *sp_die;
1023 int found;
1024 };
1025
pubname_search_cb(Dwarf * dbg,Dwarf_Global * gl,void * data)1026 static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
1027 {
1028 struct pubname_callback_param *param = data;
1029
1030 if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) {
1031 if (dwarf_tag(param->sp_die) != DW_TAG_subprogram)
1032 return DWARF_CB_OK;
1033
1034 if (die_compare_name(param->sp_die, param->function)) {
1035 if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die))
1036 return DWARF_CB_OK;
1037
1038 if (param->file &&
1039 strtailcmp(param->file, dwarf_decl_file(param->sp_die)))
1040 return DWARF_CB_OK;
1041
1042 param->found = 1;
1043 return DWARF_CB_ABORT;
1044 }
1045 }
1046
1047 return DWARF_CB_OK;
1048 }
1049
1050 /* Find probe points from debuginfo */
debuginfo__find_probes(struct debuginfo * self,struct probe_finder * pf)1051 static int debuginfo__find_probes(struct debuginfo *self,
1052 struct probe_finder *pf)
1053 {
1054 struct perf_probe_point *pp = &pf->pev->point;
1055 Dwarf_Off off, noff;
1056 size_t cuhl;
1057 Dwarf_Die *diep;
1058 int ret = 0;
1059
1060 #if _ELFUTILS_PREREQ(0, 142)
1061 /* Get the call frame information from this dwarf */
1062 pf->cfi = dwarf_getcfi(self->dbg);
1063 #endif
1064
1065 off = 0;
1066 line_list__init(&pf->lcache);
1067
1068 /* Fastpath: lookup by function name from .debug_pubnames section */
1069 if (pp->function) {
1070 struct pubname_callback_param pubname_param = {
1071 .function = pp->function,
1072 .file = pp->file,
1073 .cu_die = &pf->cu_die,
1074 .sp_die = &pf->sp_die,
1075 .found = 0,
1076 };
1077 struct dwarf_callback_param probe_param = {
1078 .data = pf,
1079 };
1080
1081 dwarf_getpubnames(self->dbg, pubname_search_cb,
1082 &pubname_param, 0);
1083 if (pubname_param.found) {
1084 ret = probe_point_search_cb(&pf->sp_die, &probe_param);
1085 if (ret)
1086 goto found;
1087 }
1088 }
1089
1090 /* Loop on CUs (Compilation Unit) */
1091 while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1092 /* Get the DIE(Debugging Information Entry) of this CU */
1093 diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die);
1094 if (!diep)
1095 continue;
1096
1097 /* Check if target file is included. */
1098 if (pp->file)
1099 pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
1100 else
1101 pf->fname = NULL;
1102
1103 if (!pp->file || pf->fname) {
1104 if (pp->function)
1105 ret = find_probe_point_by_func(pf);
1106 else if (pp->lazy_line)
1107 ret = find_probe_point_lazy(NULL, pf);
1108 else {
1109 pf->lno = pp->line;
1110 ret = find_probe_point_by_line(pf);
1111 }
1112 if (ret < 0)
1113 break;
1114 }
1115 off = noff;
1116 }
1117
1118 found:
1119 line_list__free(&pf->lcache);
1120
1121 return ret;
1122 }
1123
1124 /* Add a found probe point into trace event list */
add_probe_trace_event(Dwarf_Die * sc_die,struct probe_finder * pf)1125 static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1126 {
1127 struct trace_event_finder *tf =
1128 container_of(pf, struct trace_event_finder, pf);
1129 struct probe_trace_event *tev;
1130 int ret, i;
1131
1132 /* Check number of tevs */
1133 if (tf->ntevs == tf->max_tevs) {
1134 pr_warning("Too many( > %d) probe point found.\n",
1135 tf->max_tevs);
1136 return -ERANGE;
1137 }
1138 tev = &tf->tevs[tf->ntevs++];
1139
1140 /* Trace point should be converted from subprogram DIE */
1141 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
1142 pf->pev->point.retprobe, &tev->point);
1143 if (ret < 0)
1144 return ret;
1145
1146 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1147 tev->point.offset);
1148
1149 /* Find each argument */
1150 tev->nargs = pf->pev->nargs;
1151 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1152 if (tev->args == NULL)
1153 return -ENOMEM;
1154 for (i = 0; i < pf->pev->nargs; i++) {
1155 pf->pvar = &pf->pev->args[i];
1156 pf->tvar = &tev->args[i];
1157 /* Variable should be found from scope DIE */
1158 ret = find_variable(sc_die, pf);
1159 if (ret != 0)
1160 return ret;
1161 }
1162
1163 return 0;
1164 }
1165
1166 /* Find probe_trace_events specified by perf_probe_event from debuginfo */
debuginfo__find_trace_events(struct debuginfo * self,struct perf_probe_event * pev,struct probe_trace_event ** tevs,int max_tevs)1167 int debuginfo__find_trace_events(struct debuginfo *self,
1168 struct perf_probe_event *pev,
1169 struct probe_trace_event **tevs, int max_tevs)
1170 {
1171 struct trace_event_finder tf = {
1172 .pf = {.pev = pev, .callback = add_probe_trace_event},
1173 .mod = self->mod, .max_tevs = max_tevs};
1174 int ret;
1175
1176 /* Allocate result tevs array */
1177 *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
1178 if (*tevs == NULL)
1179 return -ENOMEM;
1180
1181 tf.tevs = *tevs;
1182 tf.ntevs = 0;
1183
1184 ret = debuginfo__find_probes(self, &tf.pf);
1185 if (ret < 0) {
1186 free(*tevs);
1187 *tevs = NULL;
1188 return ret;
1189 }
1190
1191 return (ret < 0) ? ret : tf.ntevs;
1192 }
1193
1194 #define MAX_VAR_LEN 64
1195
1196 /* Collect available variables in this scope */
collect_variables_cb(Dwarf_Die * die_mem,void * data)1197 static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1198 {
1199 struct available_var_finder *af = data;
1200 struct variable_list *vl;
1201 char buf[MAX_VAR_LEN];
1202 int tag, ret;
1203
1204 vl = &af->vls[af->nvls - 1];
1205
1206 tag = dwarf_tag(die_mem);
1207 if (tag == DW_TAG_formal_parameter ||
1208 tag == DW_TAG_variable) {
1209 ret = convert_variable_location(die_mem, af->pf.addr,
1210 af->pf.fb_ops, NULL);
1211 if (ret == 0) {
1212 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
1213 pr_debug2("Add new var: %s\n", buf);
1214 if (ret > 0)
1215 strlist__add(vl->vars, buf);
1216 }
1217 }
1218
1219 if (af->child && dwarf_haspc(die_mem, af->pf.addr))
1220 return DIE_FIND_CB_CONTINUE;
1221 else
1222 return DIE_FIND_CB_SIBLING;
1223 }
1224
1225 /* Add a found vars into available variables list */
add_available_vars(Dwarf_Die * sc_die,struct probe_finder * pf)1226 static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
1227 {
1228 struct available_var_finder *af =
1229 container_of(pf, struct available_var_finder, pf);
1230 struct variable_list *vl;
1231 Dwarf_Die die_mem;
1232 int ret;
1233
1234 /* Check number of tevs */
1235 if (af->nvls == af->max_vls) {
1236 pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
1237 return -ERANGE;
1238 }
1239 vl = &af->vls[af->nvls++];
1240
1241 /* Trace point should be converted from subprogram DIE */
1242 ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr,
1243 pf->pev->point.retprobe, &vl->point);
1244 if (ret < 0)
1245 return ret;
1246
1247 pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
1248 vl->point.offset);
1249
1250 /* Find local variables */
1251 vl->vars = strlist__new(true, NULL);
1252 if (vl->vars == NULL)
1253 return -ENOMEM;
1254 af->child = true;
1255 die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem);
1256
1257 /* Find external variables */
1258 if (!af->externs)
1259 goto out;
1260 /* Don't need to search child DIE for externs. */
1261 af->child = false;
1262 die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem);
1263
1264 out:
1265 if (strlist__empty(vl->vars)) {
1266 strlist__delete(vl->vars);
1267 vl->vars = NULL;
1268 }
1269
1270 return ret;
1271 }
1272
1273 /* Find available variables at given probe point */
debuginfo__find_available_vars_at(struct debuginfo * self,struct perf_probe_event * pev,struct variable_list ** vls,int max_vls,bool externs)1274 int debuginfo__find_available_vars_at(struct debuginfo *self,
1275 struct perf_probe_event *pev,
1276 struct variable_list **vls,
1277 int max_vls, bool externs)
1278 {
1279 struct available_var_finder af = {
1280 .pf = {.pev = pev, .callback = add_available_vars},
1281 .mod = self->mod,
1282 .max_vls = max_vls, .externs = externs};
1283 int ret;
1284
1285 /* Allocate result vls array */
1286 *vls = zalloc(sizeof(struct variable_list) * max_vls);
1287 if (*vls == NULL)
1288 return -ENOMEM;
1289
1290 af.vls = *vls;
1291 af.nvls = 0;
1292
1293 ret = debuginfo__find_probes(self, &af.pf);
1294 if (ret < 0) {
1295 /* Free vlist for error */
1296 while (af.nvls--) {
1297 if (af.vls[af.nvls].point.symbol)
1298 free(af.vls[af.nvls].point.symbol);
1299 if (af.vls[af.nvls].vars)
1300 strlist__delete(af.vls[af.nvls].vars);
1301 }
1302 free(af.vls);
1303 *vls = NULL;
1304 return ret;
1305 }
1306
1307 return (ret < 0) ? ret : af.nvls;
1308 }
1309
1310 /* Reverse search */
debuginfo__find_probe_point(struct debuginfo * self,unsigned long addr,struct perf_probe_point * ppt)1311 int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1312 struct perf_probe_point *ppt)
1313 {
1314 Dwarf_Die cudie, spdie, indie;
1315 Dwarf_Addr _addr = 0, baseaddr = 0;
1316 const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp;
1317 int baseline = 0, lineno = 0, ret = 0;
1318
1319 /* Adjust address with bias */
1320 addr += self->bias;
1321
1322 /* Find cu die */
1323 if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) {
1324 pr_warning("Failed to find debug information for address %lx\n",
1325 addr);
1326 ret = -EINVAL;
1327 goto end;
1328 }
1329
1330 /* Find a corresponding line (filename and lineno) */
1331 cu_find_lineinfo(&cudie, addr, &fname, &lineno);
1332 /* Don't care whether it failed or not */
1333
1334 /* Find a corresponding function (name, baseline and baseaddr) */
1335 if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) {
1336 /* Get function entry information */
1337 func = basefunc = dwarf_diename(&spdie);
1338 if (!func ||
1339 dwarf_entrypc(&spdie, &baseaddr) != 0 ||
1340 dwarf_decl_line(&spdie, &baseline) != 0) {
1341 lineno = 0;
1342 goto post;
1343 }
1344
1345 fname = dwarf_decl_file(&spdie);
1346 if (addr == (unsigned long)baseaddr) {
1347 /* Function entry - Relative line number is 0 */
1348 lineno = baseline;
1349 goto post;
1350 }
1351
1352 /* Track down the inline functions step by step */
1353 while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr,
1354 &indie)) {
1355 /* There is an inline function */
1356 if (dwarf_entrypc(&indie, &_addr) == 0 &&
1357 _addr == addr) {
1358 /*
1359 * addr is at an inline function entry.
1360 * In this case, lineno should be the call-site
1361 * line number. (overwrite lineinfo)
1362 */
1363 lineno = die_get_call_lineno(&indie);
1364 fname = die_get_call_file(&indie);
1365 break;
1366 } else {
1367 /*
1368 * addr is in an inline function body.
1369 * Since lineno points one of the lines
1370 * of the inline function, baseline should
1371 * be the entry line of the inline function.
1372 */
1373 tmp = dwarf_diename(&indie);
1374 if (!tmp ||
1375 dwarf_decl_line(&indie, &baseline) != 0)
1376 break;
1377 func = tmp;
1378 spdie = indie;
1379 }
1380 }
1381 /* Verify the lineno and baseline are in a same file */
1382 tmp = dwarf_decl_file(&spdie);
1383 if (!tmp || strcmp(tmp, fname) != 0)
1384 lineno = 0;
1385 }
1386
1387 post:
1388 /* Make a relative line number or an offset */
1389 if (lineno)
1390 ppt->line = lineno - baseline;
1391 else if (basefunc) {
1392 ppt->offset = addr - (unsigned long)baseaddr;
1393 func = basefunc;
1394 }
1395
1396 /* Duplicate strings */
1397 if (func) {
1398 ppt->function = strdup(func);
1399 if (ppt->function == NULL) {
1400 ret = -ENOMEM;
1401 goto end;
1402 }
1403 }
1404 if (fname) {
1405 ppt->file = strdup(fname);
1406 if (ppt->file == NULL) {
1407 if (ppt->function) {
1408 free(ppt->function);
1409 ppt->function = NULL;
1410 }
1411 ret = -ENOMEM;
1412 goto end;
1413 }
1414 }
1415 end:
1416 if (ret == 0 && (fname || func))
1417 ret = 1; /* Found a point */
1418 return ret;
1419 }
1420
1421 /* Add a line and store the src path */
line_range_add_line(const char * src,unsigned int lineno,struct line_range * lr)1422 static int line_range_add_line(const char *src, unsigned int lineno,
1423 struct line_range *lr)
1424 {
1425 /* Copy source path */
1426 if (!lr->path) {
1427 lr->path = strdup(src);
1428 if (lr->path == NULL)
1429 return -ENOMEM;
1430 }
1431 return line_list__add_line(&lr->line_list, lineno);
1432 }
1433
line_range_walk_cb(const char * fname,int lineno,Dwarf_Addr addr __maybe_unused,void * data)1434 static int line_range_walk_cb(const char *fname, int lineno,
1435 Dwarf_Addr addr __maybe_unused,
1436 void *data)
1437 {
1438 struct line_finder *lf = data;
1439
1440 if ((strtailcmp(fname, lf->fname) != 0) ||
1441 (lf->lno_s > lineno || lf->lno_e < lineno))
1442 return 0;
1443
1444 if (line_range_add_line(fname, lineno, lf->lr) < 0)
1445 return -EINVAL;
1446
1447 return 0;
1448 }
1449
1450 /* Find line range from its line number */
find_line_range_by_line(Dwarf_Die * sp_die,struct line_finder * lf)1451 static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1452 {
1453 int ret;
1454
1455 ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
1456
1457 /* Update status */
1458 if (ret >= 0)
1459 if (!list_empty(&lf->lr->line_list))
1460 ret = lf->found = 1;
1461 else
1462 ret = 0; /* Lines are not found */
1463 else {
1464 free(lf->lr->path);
1465 lf->lr->path = NULL;
1466 }
1467 return ret;
1468 }
1469
line_range_inline_cb(Dwarf_Die * in_die,void * data)1470 static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1471 {
1472 find_line_range_by_line(in_die, data);
1473
1474 /*
1475 * We have to check all instances of inlined function, because
1476 * some execution paths can be optimized out depends on the
1477 * function argument of instances
1478 */
1479 return 0;
1480 }
1481
1482 /* Search function definition from function name */
line_range_search_cb(Dwarf_Die * sp_die,void * data)1483 static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1484 {
1485 struct dwarf_callback_param *param = data;
1486 struct line_finder *lf = param->data;
1487 struct line_range *lr = lf->lr;
1488
1489 /* Check declared file */
1490 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
1491 return DWARF_CB_OK;
1492
1493 if (die_is_func_def(sp_die) &&
1494 die_compare_name(sp_die, lr->function)) {
1495 lf->fname = dwarf_decl_file(sp_die);
1496 dwarf_decl_line(sp_die, &lr->offset);
1497 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
1498 lf->lno_s = lr->offset + lr->start;
1499 if (lf->lno_s < 0) /* Overflow */
1500 lf->lno_s = INT_MAX;
1501 lf->lno_e = lr->offset + lr->end;
1502 if (lf->lno_e < 0) /* Overflow */
1503 lf->lno_e = INT_MAX;
1504 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
1505 lr->start = lf->lno_s;
1506 lr->end = lf->lno_e;
1507 if (dwarf_func_inline(sp_die))
1508 param->retval = die_walk_instances(sp_die,
1509 line_range_inline_cb, lf);
1510 else
1511 param->retval = find_line_range_by_line(sp_die, lf);
1512 return DWARF_CB_ABORT;
1513 }
1514 return DWARF_CB_OK;
1515 }
1516
find_line_range_by_func(struct line_finder * lf)1517 static int find_line_range_by_func(struct line_finder *lf)
1518 {
1519 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1520 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0);
1521 return param.retval;
1522 }
1523
debuginfo__find_line_range(struct debuginfo * self,struct line_range * lr)1524 int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr)
1525 {
1526 struct line_finder lf = {.lr = lr, .found = 0};
1527 int ret = 0;
1528 Dwarf_Off off = 0, noff;
1529 size_t cuhl;
1530 Dwarf_Die *diep;
1531 const char *comp_dir;
1532
1533 /* Fastpath: lookup by function name from .debug_pubnames section */
1534 if (lr->function) {
1535 struct pubname_callback_param pubname_param = {
1536 .function = lr->function, .file = lr->file,
1537 .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0};
1538 struct dwarf_callback_param line_range_param = {
1539 .data = (void *)&lf, .retval = 0};
1540
1541 dwarf_getpubnames(self->dbg, pubname_search_cb,
1542 &pubname_param, 0);
1543 if (pubname_param.found) {
1544 line_range_search_cb(&lf.sp_die, &line_range_param);
1545 if (lf.found)
1546 goto found;
1547 }
1548 }
1549
1550 /* Loop on CUs (Compilation Unit) */
1551 while (!lf.found && ret >= 0) {
1552 if (dwarf_nextcu(self->dbg, off, &noff, &cuhl,
1553 NULL, NULL, NULL) != 0)
1554 break;
1555
1556 /* Get the DIE(Debugging Information Entry) of this CU */
1557 diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die);
1558 if (!diep)
1559 continue;
1560
1561 /* Check if target file is included. */
1562 if (lr->file)
1563 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
1564 else
1565 lf.fname = 0;
1566
1567 if (!lr->file || lf.fname) {
1568 if (lr->function)
1569 ret = find_line_range_by_func(&lf);
1570 else {
1571 lf.lno_s = lr->start;
1572 lf.lno_e = lr->end;
1573 ret = find_line_range_by_line(NULL, &lf);
1574 }
1575 }
1576 off = noff;
1577 }
1578
1579 found:
1580 /* Store comp_dir */
1581 if (lf.found) {
1582 comp_dir = cu_get_comp_dir(&lf.cu_die);
1583 if (comp_dir) {
1584 lr->comp_dir = strdup(comp_dir);
1585 if (!lr->comp_dir)
1586 ret = -ENOMEM;
1587 }
1588 }
1589
1590 pr_debug("path: %s\n", lr->path);
1591 return (ret < 0) ? ret : lf.found;
1592 }
1593
1594