xref: /linux/tools/perf/util/probe-finder.c (revision 8b1935e6a36b0967efc593d67ed3aebbfbc1f5b1)
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 "event.h"
36 #include "debug.h"
37 #include "util.h"
38 #include "probe-finder.h"
39 
40 
41 /* Dwarf_Die Linkage to parent Die */
42 struct die_link {
43 	struct die_link *parent;	/* Parent die */
44 	Dwarf_Die die;			/* Current die */
45 };
46 
47 static Dwarf_Debug __dw_debug;
48 static Dwarf_Error __dw_error;
49 
50 /*
51  * Generic dwarf analysis helpers
52  */
53 
54 #define X86_32_MAX_REGS 8
55 const char *x86_32_regs_table[X86_32_MAX_REGS] = {
56 	"%ax",
57 	"%cx",
58 	"%dx",
59 	"%bx",
60 	"$stack",	/* Stack address instead of %sp */
61 	"%bp",
62 	"%si",
63 	"%di",
64 };
65 
66 #define X86_64_MAX_REGS 16
67 const char *x86_64_regs_table[X86_64_MAX_REGS] = {
68 	"%ax",
69 	"%dx",
70 	"%cx",
71 	"%bx",
72 	"%si",
73 	"%di",
74 	"%bp",
75 	"%sp",
76 	"%r8",
77 	"%r9",
78 	"%r10",
79 	"%r11",
80 	"%r12",
81 	"%r13",
82 	"%r14",
83 	"%r15",
84 };
85 
86 /* TODO: switching by dwarf address size */
87 #ifdef __x86_64__
88 #define ARCH_MAX_REGS X86_64_MAX_REGS
89 #define arch_regs_table x86_64_regs_table
90 #else
91 #define ARCH_MAX_REGS X86_32_MAX_REGS
92 #define arch_regs_table x86_32_regs_table
93 #endif
94 
95 /* Return architecture dependent register string (for kprobe-tracer) */
96 static const char *get_arch_regstr(unsigned int n)
97 {
98 	return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
99 }
100 
101 /*
102  * Compare the tail of two strings.
103  * Return 0 if whole of either string is same as another's tail part.
104  */
105 static int strtailcmp(const char *s1, const char *s2)
106 {
107 	int i1 = strlen(s1);
108 	int i2 = strlen(s2);
109 	while (--i1 >= 0 && --i2 >= 0) {
110 		if (s1[i1] != s2[i2])
111 			return s1[i1] - s2[i2];
112 	}
113 	return 0;
114 }
115 
116 /* Find the fileno of the target file. */
117 static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
118 {
119 	Dwarf_Signed cnt, i;
120 	Dwarf_Unsigned found = 0;
121 	char **srcs;
122 	int ret;
123 
124 	if (!fname)
125 		return 0;
126 
127 	ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
128 	if (ret == DW_DLV_OK) {
129 		for (i = 0; i < cnt && !found; i++) {
130 			if (strtailcmp(srcs[i], fname) == 0)
131 				found = i + 1;
132 			dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
133 		}
134 		for (; i < cnt; i++)
135 			dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
136 		dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
137 	}
138 	if (found)
139 		pr_debug("found fno: %d\n", (int)found);
140 	return found;
141 }
142 
143 static int cu_get_filename(Dwarf_Die cu_die, Dwarf_Unsigned fno, char **buf)
144 {
145 	Dwarf_Signed cnt, i;
146 	char **srcs;
147 	int ret = 0;
148 
149 	if (!buf || !fno)
150 		return -EINVAL;
151 
152 	ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
153 	if (ret == DW_DLV_OK) {
154 		if ((Dwarf_Unsigned)cnt > fno - 1) {
155 			*buf = strdup(srcs[fno - 1]);
156 			ret = 0;
157 			pr_debug("found filename: %s\n", *buf);
158 		} else
159 			ret = -ENOENT;
160 		for (i = 0; i < cnt; i++)
161 			dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
162 		dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
163 	} else
164 		ret = -EINVAL;
165 	return ret;
166 }
167 
168 /* Compare diename and tname */
169 static int die_compare_name(Dwarf_Die dw_die, const char *tname)
170 {
171 	char *name;
172 	int ret;
173 	ret = dwarf_diename(dw_die, &name, &__dw_error);
174 	DIE_IF(ret == DW_DLV_ERROR);
175 	if (ret == DW_DLV_OK) {
176 		ret = strcmp(tname, name);
177 		dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
178 	} else
179 		ret = -1;
180 	return ret;
181 }
182 
183 /* Check the address is in the subprogram(function). */
184 static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr,
185 				 Dwarf_Signed *offs)
186 {
187 	Dwarf_Addr lopc, hipc;
188 	int ret;
189 
190 	/* TODO: check ranges */
191 	ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
192 	DIE_IF(ret == DW_DLV_ERROR);
193 	if (ret == DW_DLV_NO_ENTRY)
194 		return 0;
195 	ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
196 	DIE_IF(ret != DW_DLV_OK);
197 	if (lopc <= addr && addr < hipc) {
198 		*offs = addr - lopc;
199 		return 1;
200 	} else
201 		return 0;
202 }
203 
204 /* Check the die is inlined function */
205 static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
206 {
207 	/* TODO: check strictly */
208 	Dwarf_Bool inl;
209 	int ret;
210 
211 	ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error);
212 	DIE_IF(ret == DW_DLV_ERROR);
213 	return inl;
214 }
215 
216 /* Get the offset of abstruct_origin */
217 static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
218 {
219 	Dwarf_Attribute attr;
220 	Dwarf_Off cu_offs;
221 	int ret;
222 
223 	ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error);
224 	DIE_IF(ret != DW_DLV_OK);
225 	ret = dwarf_formref(attr, &cu_offs, &__dw_error);
226 	DIE_IF(ret != DW_DLV_OK);
227 	dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
228 	return cu_offs;
229 }
230 
231 /* Get entry pc(or low pc, 1st entry of ranges)  of the die */
232 static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
233 {
234 	Dwarf_Attribute attr;
235 	Dwarf_Addr addr;
236 	Dwarf_Off offs;
237 	Dwarf_Ranges *ranges;
238 	Dwarf_Signed cnt;
239 	int ret;
240 
241 	/* Try to get entry pc */
242 	ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error);
243 	DIE_IF(ret == DW_DLV_ERROR);
244 	if (ret == DW_DLV_OK) {
245 		ret = dwarf_formaddr(attr, &addr, &__dw_error);
246 		DIE_IF(ret != DW_DLV_OK);
247 		dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
248 		return addr;
249 	}
250 
251 	/* Try to get low pc */
252 	ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
253 	DIE_IF(ret == DW_DLV_ERROR);
254 	if (ret == DW_DLV_OK)
255 		return addr;
256 
257 	/* Try to get ranges */
258 	ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
259 	DIE_IF(ret != DW_DLV_OK);
260 	ret = dwarf_formref(attr, &offs, &__dw_error);
261 	DIE_IF(ret != DW_DLV_OK);
262 	ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
263 				&__dw_error);
264 	DIE_IF(ret != DW_DLV_OK);
265 	addr = ranges[0].dwr_addr1;
266 	dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
267 	return addr;
268 }
269 
270 /*
271  * Search a Die from Die tree.
272  * Note: cur_link->die should be deallocated in this function.
273  */
274 static int __search_die_tree(struct die_link *cur_link,
275 			     int (*die_cb)(struct die_link *, void *),
276 			     void *data)
277 {
278 	Dwarf_Die new_die;
279 	struct die_link new_link;
280 	int ret;
281 
282 	if (!die_cb)
283 		return 0;
284 
285 	/* Check current die */
286 	while (!(ret = die_cb(cur_link, data))) {
287 		/* Check child die */
288 		ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
289 		DIE_IF(ret == DW_DLV_ERROR);
290 		if (ret == DW_DLV_OK) {
291 			new_link.parent = cur_link;
292 			new_link.die = new_die;
293 			ret = __search_die_tree(&new_link, die_cb, data);
294 			if (ret)
295 				break;
296 		}
297 
298 		/* Move to next sibling */
299 		ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
300 				      &__dw_error);
301 		DIE_IF(ret == DW_DLV_ERROR);
302 		dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
303 		cur_link->die = new_die;
304 		if (ret == DW_DLV_NO_ENTRY)
305 			return 0;
306 	}
307 	dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
308 	return ret;
309 }
310 
311 /* Search a die in its children's die tree */
312 static int search_die_from_children(Dwarf_Die parent_die,
313 				    int (*die_cb)(struct die_link *, void *),
314 				    void *data)
315 {
316 	struct die_link new_link;
317 	int ret;
318 
319 	new_link.parent = NULL;
320 	ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
321 	DIE_IF(ret == DW_DLV_ERROR);
322 	if (ret == DW_DLV_OK)
323 		return __search_die_tree(&new_link, die_cb, data);
324 	else
325 		return 0;
326 }
327 
328 /* Find a locdesc corresponding to the address */
329 static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
330 			    Dwarf_Addr addr)
331 {
332 	Dwarf_Signed lcnt;
333 	Dwarf_Locdesc **llbuf;
334 	int ret, i;
335 
336 	ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
337 	DIE_IF(ret != DW_DLV_OK);
338 	ret = DW_DLV_NO_ENTRY;
339 	for (i = 0; i < lcnt; ++i) {
340 		if (llbuf[i]->ld_lopc <= addr &&
341 		    llbuf[i]->ld_hipc > addr) {
342 			memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
343 			desc->ld_s =
344 				malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
345 			DIE_IF(desc->ld_s == NULL);
346 			memcpy(desc->ld_s, llbuf[i]->ld_s,
347 				sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
348 			ret = DW_DLV_OK;
349 			break;
350 		}
351 		dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
352 		dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
353 	}
354 	/* Releasing loop */
355 	for (; i < lcnt; ++i) {
356 		dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
357 		dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
358 	}
359 	dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
360 	return ret;
361 }
362 
363 /* Get decl_file attribute value (file number) */
364 static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die)
365 {
366 	Dwarf_Attribute attr;
367 	Dwarf_Unsigned fno;
368 	int ret;
369 
370 	ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error);
371 	DIE_IF(ret != DW_DLV_OK);
372 	dwarf_formudata(attr, &fno, &__dw_error);
373 	DIE_IF(ret != DW_DLV_OK);
374 	dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
375 	return fno;
376 }
377 
378 /* Get decl_line attribute value (line number) */
379 static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
380 {
381 	Dwarf_Attribute attr;
382 	Dwarf_Unsigned lno;
383 	int ret;
384 
385 	ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error);
386 	DIE_IF(ret != DW_DLV_OK);
387 	dwarf_formudata(attr, &lno, &__dw_error);
388 	DIE_IF(ret != DW_DLV_OK);
389 	dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
390 	return lno;
391 }
392 
393 /*
394  * Probe finder related functions
395  */
396 
397 /* Show a location */
398 static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
399 {
400 	Dwarf_Small op;
401 	Dwarf_Unsigned regn;
402 	Dwarf_Signed offs;
403 	int deref = 0, ret;
404 	const char *regs;
405 
406 	op = loc->lr_atom;
407 
408 	/* If this is based on frame buffer, set the offset */
409 	if (op == DW_OP_fbreg) {
410 		deref = 1;
411 		offs = (Dwarf_Signed)loc->lr_number;
412 		op = pf->fbloc.ld_s[0].lr_atom;
413 		loc = &pf->fbloc.ld_s[0];
414 	} else
415 		offs = 0;
416 
417 	if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
418 		regn = op - DW_OP_breg0;
419 		offs += (Dwarf_Signed)loc->lr_number;
420 		deref = 1;
421 	} else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
422 		regn = op - DW_OP_reg0;
423 	} else if (op == DW_OP_bregx) {
424 		regn = loc->lr_number;
425 		offs += (Dwarf_Signed)loc->lr_number2;
426 		deref = 1;
427 	} else if (op == DW_OP_regx) {
428 		regn = loc->lr_number;
429 	} else
430 		die("Dwarf_OP %d is not supported.", op);
431 
432 	regs = get_arch_regstr(regn);
433 	if (!regs)
434 		die("%lld exceeds max register number.", regn);
435 
436 	if (deref)
437 		ret = snprintf(pf->buf, pf->len,
438 				 " %s=%+lld(%s)", pf->var, offs, regs);
439 	else
440 		ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
441 	DIE_IF(ret < 0);
442 	DIE_IF(ret >= pf->len);
443 }
444 
445 /* Show a variables in kprobe event format */
446 static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
447 {
448 	Dwarf_Attribute attr;
449 	Dwarf_Locdesc ld;
450 	int ret;
451 
452 	ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error);
453 	if (ret != DW_DLV_OK)
454 		goto error;
455 	ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base));
456 	if (ret != DW_DLV_OK)
457 		goto error;
458 	/* TODO? */
459 	DIE_IF(ld.ld_cents != 1);
460 	show_location(&ld.ld_s[0], pf);
461 	free(ld.ld_s);
462 	dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
463 	return ;
464 error:
465 	die("Failed to find the location of %s at this address.\n"
466 	    " Perhaps, it has been optimized out.", pf->var);
467 }
468 
469 static int variable_callback(struct die_link *dlink, void *data)
470 {
471 	struct probe_finder *pf = (struct probe_finder *)data;
472 	Dwarf_Half tag;
473 	int ret;
474 
475 	ret = dwarf_tag(dlink->die, &tag, &__dw_error);
476 	DIE_IF(ret == DW_DLV_ERROR);
477 	if ((tag == DW_TAG_formal_parameter ||
478 	     tag == DW_TAG_variable) &&
479 	    (die_compare_name(dlink->die, pf->var) == 0)) {
480 		show_variable(dlink->die, pf);
481 		return 1;
482 	}
483 	/* TODO: Support struct members and arrays */
484 	return 0;
485 }
486 
487 /* Find a variable in a subprogram die */
488 static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
489 {
490 	int ret;
491 
492 	if (!is_c_varname(pf->var)) {
493 		/* Output raw parameters */
494 		ret = snprintf(pf->buf, pf->len, " %s", pf->var);
495 		DIE_IF(ret < 0);
496 		DIE_IF(ret >= pf->len);
497 		return ;
498 	}
499 
500 	pr_debug("Searching '%s' variable in context.\n", pf->var);
501 	/* Search child die for local variables and parameters. */
502 	ret = search_die_from_children(sp_die, variable_callback, pf);
503 	if (!ret)
504 		die("Failed to find '%s' in this function.", pf->var);
505 }
506 
507 /* Get a frame base on the address */
508 static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
509 {
510 	Dwarf_Attribute attr;
511 	int ret;
512 
513 	ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
514 	DIE_IF(ret != DW_DLV_OK);
515 	ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
516 	DIE_IF(ret != DW_DLV_OK);
517 	dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
518 }
519 
520 static void free_current_frame_base(struct probe_finder *pf)
521 {
522 	free(pf->fbloc.ld_s);
523 	memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
524 }
525 
526 /* Show a probe point to output buffer */
527 static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
528 			    struct probe_finder *pf)
529 {
530 	struct probe_point *pp = pf->pp;
531 	char *name;
532 	char tmp[MAX_PROBE_BUFFER];
533 	int ret, i, len;
534 
535 	/* Output name of probe point */
536 	ret = dwarf_diename(sp_die, &name, &__dw_error);
537 	DIE_IF(ret == DW_DLV_ERROR);
538 	if (ret == DW_DLV_OK) {
539 		ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
540 				(unsigned int)offs);
541 		/* Copy the function name if possible */
542 		if (!pp->function) {
543 			pp->function = strdup(name);
544 			pp->offset = offs;
545 		}
546 		dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
547 	} else {
548 		/* This function has no name. */
549 		ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr);
550 		if (!pp->function) {
551 			/* TODO: Use _stext */
552 			pp->function = strdup("");
553 			pp->offset = (int)pf->addr;
554 		}
555 	}
556 	DIE_IF(ret < 0);
557 	DIE_IF(ret >= MAX_PROBE_BUFFER);
558 	len = ret;
559 	pr_debug("Probe point found: %s\n", tmp);
560 
561 	/* Find each argument */
562 	get_current_frame_base(sp_die, pf);
563 	for (i = 0; i < pp->nr_args; i++) {
564 		pf->var = pp->args[i];
565 		pf->buf = &tmp[len];
566 		pf->len = MAX_PROBE_BUFFER - len;
567 		find_variable(sp_die, pf);
568 		len += strlen(pf->buf);
569 	}
570 	free_current_frame_base(pf);
571 
572 	pp->probes[pp->found] = strdup(tmp);
573 	pp->found++;
574 }
575 
576 static int probeaddr_callback(struct die_link *dlink, void *data)
577 {
578 	struct probe_finder *pf = (struct probe_finder *)data;
579 	Dwarf_Half tag;
580 	Dwarf_Signed offs;
581 	int ret;
582 
583 	ret = dwarf_tag(dlink->die, &tag, &__dw_error);
584 	DIE_IF(ret == DW_DLV_ERROR);
585 	/* Check the address is in this subprogram */
586 	if (tag == DW_TAG_subprogram &&
587 	    die_within_subprogram(dlink->die, pf->addr, &offs)) {
588 		show_probepoint(dlink->die, offs, pf);
589 		return 1;
590 	}
591 	return 0;
592 }
593 
594 /* Find probe point from its line number */
595 static void find_probe_point_by_line(struct probe_finder *pf)
596 {
597 	Dwarf_Signed cnt, i, clm;
598 	Dwarf_Line *lines;
599 	Dwarf_Unsigned lineno = 0;
600 	Dwarf_Addr addr;
601 	Dwarf_Unsigned fno;
602 	int ret;
603 
604 	ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error);
605 	DIE_IF(ret != DW_DLV_OK);
606 
607 	for (i = 0; i < cnt; i++) {
608 		ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
609 		DIE_IF(ret != DW_DLV_OK);
610 		if (fno != pf->fno)
611 			continue;
612 
613 		ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
614 		DIE_IF(ret != DW_DLV_OK);
615 		if (lineno != pf->lno)
616 			continue;
617 
618 		ret = dwarf_lineoff(lines[i], &clm, &__dw_error);
619 		DIE_IF(ret != DW_DLV_OK);
620 
621 		ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
622 		DIE_IF(ret != DW_DLV_OK);
623 		pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
624 			 (int)i, (unsigned)lineno, (int)clm, addr);
625 		pf->addr = addr;
626 		/* Search a real subprogram including this line, */
627 		ret = search_die_from_children(pf->cu_die,
628 					       probeaddr_callback, pf);
629 		if (ret == 0)
630 			die("Probe point is not found in subprograms.");
631 		/* Continuing, because target line might be inlined. */
632 	}
633 	dwarf_srclines_dealloc(__dw_debug, lines, cnt);
634 }
635 
636 /* Search function from function name */
637 static int probefunc_callback(struct die_link *dlink, void *data)
638 {
639 	struct probe_finder *pf = (struct probe_finder *)data;
640 	struct probe_point *pp = pf->pp;
641 	struct die_link *lk;
642 	Dwarf_Signed offs;
643 	Dwarf_Half tag;
644 	int ret;
645 
646 	ret = dwarf_tag(dlink->die, &tag, &__dw_error);
647 	DIE_IF(ret == DW_DLV_ERROR);
648 	if (tag == DW_TAG_subprogram) {
649 		if (die_compare_name(dlink->die, pp->function) == 0) {
650 			if (pp->line) {	/* Function relative line */
651 				pf->fno = die_get_decl_file(dlink->die);
652 				pf->lno = die_get_decl_line(dlink->die)
653 					 + pp->line;
654 				find_probe_point_by_line(pf);
655 				return 1;
656 			}
657 			if (die_inlined_subprogram(dlink->die)) {
658 				/* Inlined function, save it. */
659 				ret = dwarf_die_CU_offset(dlink->die,
660 							  &pf->inl_offs,
661 							  &__dw_error);
662 				DIE_IF(ret != DW_DLV_OK);
663 				pr_debug("inline definition offset %lld\n",
664 					 pf->inl_offs);
665 				return 0;	/* Continue to search */
666 			}
667 			/* Get probe address */
668 			pf->addr = die_get_entrypc(dlink->die);
669 			pf->addr += pp->offset;
670 			/* TODO: Check the address in this function */
671 			show_probepoint(dlink->die, pp->offset, pf);
672 			return 1; /* Exit; no same symbol in this CU. */
673 		}
674 	} else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
675 		if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
676 			/* Get probe address */
677 			pf->addr = die_get_entrypc(dlink->die);
678 			pf->addr += pp->offset;
679 			pr_debug("found inline addr: 0x%llx\n", pf->addr);
680 			/* Inlined function. Get a real subprogram */
681 			for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
682 				tag = 0;
683 				dwarf_tag(lk->die, &tag, &__dw_error);
684 				DIE_IF(ret == DW_DLV_ERROR);
685 				if (tag == DW_TAG_subprogram &&
686 				    !die_inlined_subprogram(lk->die))
687 					goto found;
688 			}
689 			die("Failed to find real subprogram.");
690 found:
691 			/* Get offset from subprogram */
692 			ret = die_within_subprogram(lk->die, pf->addr, &offs);
693 			DIE_IF(!ret);
694 			show_probepoint(lk->die, offs, pf);
695 			/* Continue to search */
696 		}
697 	}
698 	return 0;
699 }
700 
701 static void find_probe_point_by_func(struct probe_finder *pf)
702 {
703 	search_die_from_children(pf->cu_die, probefunc_callback, pf);
704 }
705 
706 /* Find a probe point */
707 int find_probepoint(int fd, struct probe_point *pp)
708 {
709 	Dwarf_Half addr_size = 0;
710 	Dwarf_Unsigned next_cuh = 0;
711 	int cu_number = 0, ret;
712 	struct probe_finder pf = {.pp = pp};
713 
714 	ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
715 	if (ret != DW_DLV_OK)
716 		return -ENOENT;
717 
718 	pp->found = 0;
719 	while (++cu_number) {
720 		/* Search CU (Compilation Unit) */
721 		ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
722 			&addr_size, &next_cuh, &__dw_error);
723 		DIE_IF(ret == DW_DLV_ERROR);
724 		if (ret == DW_DLV_NO_ENTRY)
725 			break;
726 
727 		/* Get the DIE(Debugging Information Entry) of this CU */
728 		ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error);
729 		DIE_IF(ret != DW_DLV_OK);
730 
731 		/* Check if target file is included. */
732 		if (pp->file)
733 			pf.fno = cu_find_fileno(pf.cu_die, pp->file);
734 
735 		if (!pp->file || pf.fno) {
736 			/* Save CU base address (for frame_base) */
737 			ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error);
738 			DIE_IF(ret == DW_DLV_ERROR);
739 			if (ret == DW_DLV_NO_ENTRY)
740 				pf.cu_base = 0;
741 			if (pp->function)
742 				find_probe_point_by_func(&pf);
743 			else {
744 				pf.lno = pp->line;
745 				find_probe_point_by_line(&pf);
746 			}
747 		}
748 		dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE);
749 	}
750 	ret = dwarf_finish(__dw_debug, &__dw_error);
751 	DIE_IF(ret != DW_DLV_OK);
752 
753 	return pp->found;
754 }
755 
756 
757 static void line_range_add_line(struct line_range *lr, unsigned int line)
758 {
759 	struct line_node *ln;
760 	struct list_head *p;
761 
762 	/* Reverse search, because new line will be the last one */
763 	list_for_each_entry_reverse(ln, &lr->line_list, list) {
764 		if (ln->line < line) {
765 			p = &ln->list;
766 			goto found;
767 		} else if (ln->line == line)	/* Already exist */
768 			return ;
769 	}
770 	/* List is empty, or the smallest entry */
771 	p = &lr->line_list;
772 found:
773 	pr_debug("Debug: add a line %u\n", line);
774 	ln = zalloc(sizeof(struct line_node));
775 	DIE_IF(ln == NULL);
776 	ln->line = line;
777 	INIT_LIST_HEAD(&ln->list);
778 	list_add(&ln->list, p);
779 }
780 
781 /* Find line range from its line number */
782 static void find_line_range_by_line(struct line_finder *lf)
783 {
784 	Dwarf_Signed cnt, i;
785 	Dwarf_Line *lines;
786 	Dwarf_Unsigned lineno = 0;
787 	Dwarf_Unsigned fno;
788 	Dwarf_Addr addr;
789 	int ret;
790 
791 	ret = dwarf_srclines(lf->cu_die, &lines, &cnt, &__dw_error);
792 	DIE_IF(ret != DW_DLV_OK);
793 
794 	for (i = 0; i < cnt; i++) {
795 		ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
796 		DIE_IF(ret != DW_DLV_OK);
797 		if (fno != lf->fno)
798 			continue;
799 
800 		ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
801 		DIE_IF(ret != DW_DLV_OK);
802 		if (lf->lno_s > lineno || lf->lno_e < lineno)
803 			continue;
804 
805 		/* Filter line in the function address range */
806 		if (lf->addr_s && lf->addr_e) {
807 			ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
808 			DIE_IF(ret != DW_DLV_OK);
809 			if (lf->addr_s > addr || lf->addr_e <= addr)
810 				continue;
811 		}
812 		line_range_add_line(lf->lr, (unsigned int)lineno);
813 	}
814 	dwarf_srclines_dealloc(__dw_debug, lines, cnt);
815 	if (!list_empty(&lf->lr->line_list))
816 		lf->found = 1;
817 }
818 
819 /* Search function from function name */
820 static int linefunc_callback(struct die_link *dlink, void *data)
821 {
822 	struct line_finder *lf = (struct line_finder *)data;
823 	struct line_range *lr = lf->lr;
824 	Dwarf_Half tag;
825 	int ret;
826 
827 	ret = dwarf_tag(dlink->die, &tag, &__dw_error);
828 	DIE_IF(ret == DW_DLV_ERROR);
829 	if (tag == DW_TAG_subprogram &&
830 	    die_compare_name(dlink->die, lr->function) == 0) {
831 		/* Get the address range of this function */
832 		ret = dwarf_highpc(dlink->die, &lf->addr_e, &__dw_error);
833 		if (ret == DW_DLV_OK)
834 			ret = dwarf_lowpc(dlink->die, &lf->addr_s, &__dw_error);
835 		DIE_IF(ret == DW_DLV_ERROR);
836 		if (ret == DW_DLV_NO_ENTRY) {
837 			lf->addr_s = 0;
838 			lf->addr_e = 0;
839 		}
840 
841 		lf->fno = die_get_decl_file(dlink->die);
842 		lr->offset = die_get_decl_line(dlink->die);;
843 		lf->lno_s = lr->offset + lr->start;
844 		if (!lr->end)
845 			lf->lno_e = (Dwarf_Unsigned)-1;
846 		else
847 			lf->lno_e = lr->offset + lr->end;
848 		lr->start = lf->lno_s;
849 		lr->end = lf->lno_e;
850 		find_line_range_by_line(lf);
851 		/* If we find a target function, this should be end. */
852 		lf->found = 1;
853 		return 1;
854 	}
855 	return 0;
856 }
857 
858 static void find_line_range_by_func(struct line_finder *lf)
859 {
860 	search_die_from_children(lf->cu_die, linefunc_callback, lf);
861 }
862 
863 int find_line_range(int fd, struct line_range *lr)
864 {
865 	Dwarf_Half addr_size = 0;
866 	Dwarf_Unsigned next_cuh = 0;
867 	int ret;
868 	struct line_finder lf = {.lr = lr};
869 
870 	ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
871 	if (ret != DW_DLV_OK)
872 		return -ENOENT;
873 
874 	while (!lf.found) {
875 		/* Search CU (Compilation Unit) */
876 		ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
877 			&addr_size, &next_cuh, &__dw_error);
878 		DIE_IF(ret == DW_DLV_ERROR);
879 		if (ret == DW_DLV_NO_ENTRY)
880 			break;
881 
882 		/* Get the DIE(Debugging Information Entry) of this CU */
883 		ret = dwarf_siblingof(__dw_debug, 0, &lf.cu_die, &__dw_error);
884 		DIE_IF(ret != DW_DLV_OK);
885 
886 		/* Check if target file is included. */
887 		if (lr->file)
888 			lf.fno = cu_find_fileno(lf.cu_die, lr->file);
889 
890 		if (!lr->file || lf.fno) {
891 			if (lr->function)
892 				find_line_range_by_func(&lf);
893 			else {
894 				lf.lno_s = lr->start;
895 				if (!lr->end)
896 					lf.lno_e = (Dwarf_Unsigned)-1;
897 				else
898 					lf.lno_e = lr->end;
899 				find_line_range_by_line(&lf);
900 			}
901 			/* Get the real file path */
902 			if (lf.found)
903 				cu_get_filename(lf.cu_die, lf.fno, &lr->path);
904 		}
905 		dwarf_dealloc(__dw_debug, lf.cu_die, DW_DLA_DIE);
906 	}
907 	ret = dwarf_finish(__dw_debug, &__dw_error);
908 	DIE_IF(ret != DW_DLV_OK);
909 	return lf.found;
910 }
911 
912