xref: /linux/tools/perf/util/probe-finder.c (revision 074fc0e4b3f5d24306c2995f2f3b0bd4759e8aeb)
14ea42b18SMasami Hiramatsu /*
24ea42b18SMasami Hiramatsu  * probe-finder.c : C expression to kprobe event converter
34ea42b18SMasami Hiramatsu  *
44ea42b18SMasami Hiramatsu  * Written by Masami Hiramatsu <mhiramat@redhat.com>
54ea42b18SMasami Hiramatsu  *
64ea42b18SMasami Hiramatsu  * This program is free software; you can redistribute it and/or modify
74ea42b18SMasami Hiramatsu  * it under the terms of the GNU General Public License as published by
84ea42b18SMasami Hiramatsu  * the Free Software Foundation; either version 2 of the License, or
94ea42b18SMasami Hiramatsu  * (at your option) any later version.
104ea42b18SMasami Hiramatsu  *
114ea42b18SMasami Hiramatsu  * This program is distributed in the hope that it will be useful,
124ea42b18SMasami Hiramatsu  * but WITHOUT ANY WARRANTY; without even the implied warranty of
134ea42b18SMasami Hiramatsu  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
144ea42b18SMasami Hiramatsu  * GNU General Public License for more details.
154ea42b18SMasami Hiramatsu  *
164ea42b18SMasami Hiramatsu  * You should have received a copy of the GNU General Public License
174ea42b18SMasami Hiramatsu  * along with this program; if not, write to the Free Software
184ea42b18SMasami Hiramatsu  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
194ea42b18SMasami Hiramatsu  *
204ea42b18SMasami Hiramatsu  */
214ea42b18SMasami Hiramatsu 
224ea42b18SMasami Hiramatsu #include <sys/utsname.h>
234ea42b18SMasami Hiramatsu #include <sys/types.h>
244ea42b18SMasami Hiramatsu #include <sys/stat.h>
254ea42b18SMasami Hiramatsu #include <fcntl.h>
264ea42b18SMasami Hiramatsu #include <errno.h>
274ea42b18SMasami Hiramatsu #include <stdio.h>
284ea42b18SMasami Hiramatsu #include <unistd.h>
294ea42b18SMasami Hiramatsu #include <getopt.h>
304ea42b18SMasami Hiramatsu #include <stdlib.h>
314ea42b18SMasami Hiramatsu #include <string.h>
324ea42b18SMasami Hiramatsu #include <stdarg.h>
334ea42b18SMasami Hiramatsu #include <ctype.h>
34*074fc0e4SMasami Hiramatsu 
35*074fc0e4SMasami Hiramatsu #include "util.h"
364ea42b18SMasami Hiramatsu #include "probe-finder.h"
374ea42b18SMasami Hiramatsu 
384ea42b18SMasami Hiramatsu 
394ea42b18SMasami Hiramatsu /* Dwarf_Die Linkage to parent Die */
404ea42b18SMasami Hiramatsu struct die_link {
414ea42b18SMasami Hiramatsu 	struct die_link *parent;	/* Parent die */
424ea42b18SMasami Hiramatsu 	Dwarf_Die die;			/* Current die */
434ea42b18SMasami Hiramatsu };
444ea42b18SMasami Hiramatsu 
454ea42b18SMasami Hiramatsu static Dwarf_Debug __dw_debug;
464ea42b18SMasami Hiramatsu static Dwarf_Error __dw_error;
474ea42b18SMasami Hiramatsu 
484ea42b18SMasami Hiramatsu /*
494ea42b18SMasami Hiramatsu  * Generic dwarf analysis helpers
504ea42b18SMasami Hiramatsu  */
514ea42b18SMasami Hiramatsu 
524ea42b18SMasami Hiramatsu #define X86_32_MAX_REGS 8
534ea42b18SMasami Hiramatsu const char *x86_32_regs_table[X86_32_MAX_REGS] = {
544ea42b18SMasami Hiramatsu 	"%ax",
554ea42b18SMasami Hiramatsu 	"%cx",
564ea42b18SMasami Hiramatsu 	"%dx",
574ea42b18SMasami Hiramatsu 	"%bx",
584ea42b18SMasami Hiramatsu 	"$stack",	/* Stack address instead of %sp */
594ea42b18SMasami Hiramatsu 	"%bp",
604ea42b18SMasami Hiramatsu 	"%si",
614ea42b18SMasami Hiramatsu 	"%di",
624ea42b18SMasami Hiramatsu };
634ea42b18SMasami Hiramatsu 
644ea42b18SMasami Hiramatsu #define X86_64_MAX_REGS 16
654ea42b18SMasami Hiramatsu const char *x86_64_regs_table[X86_64_MAX_REGS] = {
664ea42b18SMasami Hiramatsu 	"%ax",
674ea42b18SMasami Hiramatsu 	"%dx",
684ea42b18SMasami Hiramatsu 	"%cx",
694ea42b18SMasami Hiramatsu 	"%bx",
704ea42b18SMasami Hiramatsu 	"%si",
714ea42b18SMasami Hiramatsu 	"%di",
724ea42b18SMasami Hiramatsu 	"%bp",
734ea42b18SMasami Hiramatsu 	"%sp",
744ea42b18SMasami Hiramatsu 	"%r8",
754ea42b18SMasami Hiramatsu 	"%r9",
764ea42b18SMasami Hiramatsu 	"%r10",
774ea42b18SMasami Hiramatsu 	"%r11",
784ea42b18SMasami Hiramatsu 	"%r12",
794ea42b18SMasami Hiramatsu 	"%r13",
804ea42b18SMasami Hiramatsu 	"%r14",
814ea42b18SMasami Hiramatsu 	"%r15",
824ea42b18SMasami Hiramatsu };
834ea42b18SMasami Hiramatsu 
844ea42b18SMasami Hiramatsu /* TODO: switching by dwarf address size */
854ea42b18SMasami Hiramatsu #ifdef __x86_64__
864ea42b18SMasami Hiramatsu #define ARCH_MAX_REGS X86_64_MAX_REGS
874ea42b18SMasami Hiramatsu #define arch_regs_table x86_64_regs_table
884ea42b18SMasami Hiramatsu #else
894ea42b18SMasami Hiramatsu #define ARCH_MAX_REGS X86_32_MAX_REGS
904ea42b18SMasami Hiramatsu #define arch_regs_table x86_32_regs_table
914ea42b18SMasami Hiramatsu #endif
924ea42b18SMasami Hiramatsu 
934ea42b18SMasami Hiramatsu /* Return architecture dependent register string (for kprobe-tracer) */
944ea42b18SMasami Hiramatsu static const char *get_arch_regstr(unsigned int n)
954ea42b18SMasami Hiramatsu {
964ea42b18SMasami Hiramatsu 	return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
974ea42b18SMasami Hiramatsu }
984ea42b18SMasami Hiramatsu 
994ea42b18SMasami Hiramatsu /*
1004ea42b18SMasami Hiramatsu  * Compare the tail of two strings.
1014ea42b18SMasami Hiramatsu  * Return 0 if whole of either string is same as another's tail part.
1024ea42b18SMasami Hiramatsu  */
1034ea42b18SMasami Hiramatsu static int strtailcmp(const char *s1, const char *s2)
1044ea42b18SMasami Hiramatsu {
1054ea42b18SMasami Hiramatsu 	int i1 = strlen(s1);
1064ea42b18SMasami Hiramatsu 	int i2 = strlen(s2);
1074ea42b18SMasami Hiramatsu 	while (--i1 > 0 && --i2 > 0) {
1084ea42b18SMasami Hiramatsu 		if (s1[i1] != s2[i2])
1094ea42b18SMasami Hiramatsu 			return s1[i1] - s2[i2];
1104ea42b18SMasami Hiramatsu 	}
1114ea42b18SMasami Hiramatsu 	return 0;
1124ea42b18SMasami Hiramatsu }
1134ea42b18SMasami Hiramatsu 
1144ea42b18SMasami Hiramatsu /* Find the fileno of the target file. */
1154ea42b18SMasami Hiramatsu static Dwarf_Unsigned die_get_fileno(Dwarf_Die cu_die, const char *fname)
1164ea42b18SMasami Hiramatsu {
1174ea42b18SMasami Hiramatsu 	Dwarf_Signed cnt, i;
1184ea42b18SMasami Hiramatsu 	Dwarf_Unsigned found = 0;
1194ea42b18SMasami Hiramatsu 	char **srcs;
1204ea42b18SMasami Hiramatsu 	int ret;
1214ea42b18SMasami Hiramatsu 
1224ea42b18SMasami Hiramatsu 	if (!fname)
1234ea42b18SMasami Hiramatsu 		return 0;
1244ea42b18SMasami Hiramatsu 
1254ea42b18SMasami Hiramatsu 	ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
1264ea42b18SMasami Hiramatsu 	if (ret == DW_DLV_OK) {
1274ea42b18SMasami Hiramatsu 		for (i = 0; i < cnt && !found; i++) {
1284ea42b18SMasami Hiramatsu 			if (strtailcmp(srcs[i], fname) == 0)
1294ea42b18SMasami Hiramatsu 				found = i + 1;
1304ea42b18SMasami Hiramatsu 			dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
1314ea42b18SMasami Hiramatsu 		}
1324ea42b18SMasami Hiramatsu 		for (; i < cnt; i++)
1334ea42b18SMasami Hiramatsu 			dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
1344ea42b18SMasami Hiramatsu 		dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
1354ea42b18SMasami Hiramatsu 	}
1364ea42b18SMasami Hiramatsu 	if (found)
1374ea42b18SMasami Hiramatsu 		debug("found fno: %d\n", (int)found);
1384ea42b18SMasami Hiramatsu 	return found;
1394ea42b18SMasami Hiramatsu }
1404ea42b18SMasami Hiramatsu 
1414ea42b18SMasami Hiramatsu /* Compare diename and tname */
142*074fc0e4SMasami Hiramatsu static int die_compare_name(Dwarf_Die dw_die, const char *tname)
1434ea42b18SMasami Hiramatsu {
1444ea42b18SMasami Hiramatsu 	char *name;
1454ea42b18SMasami Hiramatsu 	int ret;
146*074fc0e4SMasami Hiramatsu 	ret = dwarf_diename(dw_die, &name, &__dw_error);
1474ea42b18SMasami Hiramatsu 	ERR_IF(ret == DW_DLV_ERROR);
1484ea42b18SMasami Hiramatsu 	if (ret == DW_DLV_OK) {
1494ea42b18SMasami Hiramatsu 		ret = strcmp(tname, name);
1504ea42b18SMasami Hiramatsu 		dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
1514ea42b18SMasami Hiramatsu 	} else
1524ea42b18SMasami Hiramatsu 		ret = -1;
1534ea42b18SMasami Hiramatsu 	return ret;
1544ea42b18SMasami Hiramatsu }
1554ea42b18SMasami Hiramatsu 
1564ea42b18SMasami Hiramatsu /* Check the address is in the subprogram(function). */
1574ea42b18SMasami Hiramatsu static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr,
1584ea42b18SMasami Hiramatsu 				 Dwarf_Signed *offs)
1594ea42b18SMasami Hiramatsu {
1604ea42b18SMasami Hiramatsu 	Dwarf_Addr lopc, hipc;
1614ea42b18SMasami Hiramatsu 	int ret;
1624ea42b18SMasami Hiramatsu 
1634ea42b18SMasami Hiramatsu 	/* TODO: check ranges */
1644ea42b18SMasami Hiramatsu 	ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
1654ea42b18SMasami Hiramatsu 	ERR_IF(ret == DW_DLV_ERROR);
1664ea42b18SMasami Hiramatsu 	if (ret == DW_DLV_NO_ENTRY)
1674ea42b18SMasami Hiramatsu 		return 0;
1684ea42b18SMasami Hiramatsu 	ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
1694ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
1704ea42b18SMasami Hiramatsu 	if (lopc <= addr && addr < hipc) {
1714ea42b18SMasami Hiramatsu 		*offs = addr - lopc;
1724ea42b18SMasami Hiramatsu 		return 1;
1734ea42b18SMasami Hiramatsu 	} else
1744ea42b18SMasami Hiramatsu 		return 0;
1754ea42b18SMasami Hiramatsu }
1764ea42b18SMasami Hiramatsu 
1774ea42b18SMasami Hiramatsu /* Check the die is inlined function */
178*074fc0e4SMasami Hiramatsu static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
1794ea42b18SMasami Hiramatsu {
1804ea42b18SMasami Hiramatsu 	/* TODO: check strictly */
1814ea42b18SMasami Hiramatsu 	Dwarf_Bool inl;
1824ea42b18SMasami Hiramatsu 	int ret;
1834ea42b18SMasami Hiramatsu 
184*074fc0e4SMasami Hiramatsu 	ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error);
1854ea42b18SMasami Hiramatsu 	ERR_IF(ret == DW_DLV_ERROR);
1864ea42b18SMasami Hiramatsu 	return inl;
1874ea42b18SMasami Hiramatsu }
1884ea42b18SMasami Hiramatsu 
1894ea42b18SMasami Hiramatsu /* Get the offset of abstruct_origin */
190*074fc0e4SMasami Hiramatsu static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
1914ea42b18SMasami Hiramatsu {
1924ea42b18SMasami Hiramatsu 	Dwarf_Attribute attr;
1934ea42b18SMasami Hiramatsu 	Dwarf_Off cu_offs;
1944ea42b18SMasami Hiramatsu 	int ret;
1954ea42b18SMasami Hiramatsu 
196*074fc0e4SMasami Hiramatsu 	ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error);
1974ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
1984ea42b18SMasami Hiramatsu 	ret = dwarf_formref(attr, &cu_offs, &__dw_error);
1994ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
2004ea42b18SMasami Hiramatsu 	dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
2014ea42b18SMasami Hiramatsu 	return cu_offs;
2024ea42b18SMasami Hiramatsu }
2034ea42b18SMasami Hiramatsu 
2044ea42b18SMasami Hiramatsu /* Get entry pc(or low pc, 1st entry of ranges)  of the die */
205*074fc0e4SMasami Hiramatsu static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
2064ea42b18SMasami Hiramatsu {
2074ea42b18SMasami Hiramatsu 	Dwarf_Attribute attr;
2084ea42b18SMasami Hiramatsu 	Dwarf_Addr addr;
2094ea42b18SMasami Hiramatsu 	Dwarf_Off offs;
2104ea42b18SMasami Hiramatsu 	Dwarf_Ranges *ranges;
2114ea42b18SMasami Hiramatsu 	Dwarf_Signed cnt;
2124ea42b18SMasami Hiramatsu 	int ret;
2134ea42b18SMasami Hiramatsu 
2144ea42b18SMasami Hiramatsu 	/* Try to get entry pc */
215*074fc0e4SMasami Hiramatsu 	ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error);
2164ea42b18SMasami Hiramatsu 	ERR_IF(ret == DW_DLV_ERROR);
2174ea42b18SMasami Hiramatsu 	if (ret == DW_DLV_OK) {
2184ea42b18SMasami Hiramatsu 		ret = dwarf_formaddr(attr, &addr, &__dw_error);
2194ea42b18SMasami Hiramatsu 		ERR_IF(ret != DW_DLV_OK);
2204ea42b18SMasami Hiramatsu 		dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
2214ea42b18SMasami Hiramatsu 		return addr;
2224ea42b18SMasami Hiramatsu 	}
2234ea42b18SMasami Hiramatsu 
2244ea42b18SMasami Hiramatsu 	/* Try to get low pc */
225*074fc0e4SMasami Hiramatsu 	ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
2264ea42b18SMasami Hiramatsu 	ERR_IF(ret == DW_DLV_ERROR);
2274ea42b18SMasami Hiramatsu 	if (ret == DW_DLV_OK)
2284ea42b18SMasami Hiramatsu 		return addr;
2294ea42b18SMasami Hiramatsu 
2304ea42b18SMasami Hiramatsu 	/* Try to get ranges */
231*074fc0e4SMasami Hiramatsu 	ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
2324ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
2334ea42b18SMasami Hiramatsu 	ret = dwarf_formref(attr, &offs, &__dw_error);
2344ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
2354ea42b18SMasami Hiramatsu 	ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
2364ea42b18SMasami Hiramatsu 				&__dw_error);
2374ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
2384ea42b18SMasami Hiramatsu 	addr = ranges[0].dwr_addr1;
2394ea42b18SMasami Hiramatsu 	dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
2404ea42b18SMasami Hiramatsu 	return addr;
2414ea42b18SMasami Hiramatsu }
2424ea42b18SMasami Hiramatsu 
2434ea42b18SMasami Hiramatsu /*
2444ea42b18SMasami Hiramatsu  * Search a Die from Die tree.
2454ea42b18SMasami Hiramatsu  * Note: cur_link->die should be deallocated in this function.
2464ea42b18SMasami Hiramatsu  */
2474ea42b18SMasami Hiramatsu static int __search_die_tree(struct die_link *cur_link,
2484ea42b18SMasami Hiramatsu 			     int (*die_cb)(struct die_link *, void *),
2494ea42b18SMasami Hiramatsu 			     void *data)
2504ea42b18SMasami Hiramatsu {
2514ea42b18SMasami Hiramatsu 	Dwarf_Die new_die;
2524ea42b18SMasami Hiramatsu 	struct die_link new_link;
2534ea42b18SMasami Hiramatsu 	int ret;
2544ea42b18SMasami Hiramatsu 
2554ea42b18SMasami Hiramatsu 	if (!die_cb)
2564ea42b18SMasami Hiramatsu 		return 0;
2574ea42b18SMasami Hiramatsu 
2584ea42b18SMasami Hiramatsu 	/* Check current die */
2594ea42b18SMasami Hiramatsu 	while (!(ret = die_cb(cur_link, data))) {
2604ea42b18SMasami Hiramatsu 		/* Check child die */
2614ea42b18SMasami Hiramatsu 		ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
2624ea42b18SMasami Hiramatsu 		ERR_IF(ret == DW_DLV_ERROR);
2634ea42b18SMasami Hiramatsu 		if (ret == DW_DLV_OK) {
2644ea42b18SMasami Hiramatsu 			new_link.parent = cur_link;
2654ea42b18SMasami Hiramatsu 			new_link.die = new_die;
2664ea42b18SMasami Hiramatsu 			ret = __search_die_tree(&new_link, die_cb, data);
2674ea42b18SMasami Hiramatsu 			if (ret)
2684ea42b18SMasami Hiramatsu 				break;
2694ea42b18SMasami Hiramatsu 		}
2704ea42b18SMasami Hiramatsu 
2714ea42b18SMasami Hiramatsu 		/* Move to next sibling */
2724ea42b18SMasami Hiramatsu 		ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
2734ea42b18SMasami Hiramatsu 				      &__dw_error);
2744ea42b18SMasami Hiramatsu 		ERR_IF(ret == DW_DLV_ERROR);
2754ea42b18SMasami Hiramatsu 		dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
2764ea42b18SMasami Hiramatsu 		cur_link->die = new_die;
2774ea42b18SMasami Hiramatsu 		if (ret == DW_DLV_NO_ENTRY)
2784ea42b18SMasami Hiramatsu 			return 0;
2794ea42b18SMasami Hiramatsu 	}
2804ea42b18SMasami Hiramatsu 	dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
2814ea42b18SMasami Hiramatsu 	return ret;
2824ea42b18SMasami Hiramatsu }
2834ea42b18SMasami Hiramatsu 
2844ea42b18SMasami Hiramatsu /* Search a die in its children's die tree */
2854ea42b18SMasami Hiramatsu static int search_die_from_children(Dwarf_Die parent_die,
2864ea42b18SMasami Hiramatsu 				    int (*die_cb)(struct die_link *, void *),
2874ea42b18SMasami Hiramatsu 				    void *data)
2884ea42b18SMasami Hiramatsu {
2894ea42b18SMasami Hiramatsu 	struct die_link new_link;
2904ea42b18SMasami Hiramatsu 	int ret;
2914ea42b18SMasami Hiramatsu 
2924ea42b18SMasami Hiramatsu 	new_link.parent = NULL;
2934ea42b18SMasami Hiramatsu 	ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
2944ea42b18SMasami Hiramatsu 	ERR_IF(ret == DW_DLV_ERROR);
2954ea42b18SMasami Hiramatsu 	if (ret == DW_DLV_OK)
2964ea42b18SMasami Hiramatsu 		return __search_die_tree(&new_link, die_cb, data);
2974ea42b18SMasami Hiramatsu 	else
2984ea42b18SMasami Hiramatsu 		return 0;
2994ea42b18SMasami Hiramatsu }
3004ea42b18SMasami Hiramatsu 
3014ea42b18SMasami Hiramatsu /* Find a locdesc corresponding to the address */
3024ea42b18SMasami Hiramatsu static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
3034ea42b18SMasami Hiramatsu 			    Dwarf_Addr addr)
3044ea42b18SMasami Hiramatsu {
3054ea42b18SMasami Hiramatsu 	Dwarf_Signed lcnt;
3064ea42b18SMasami Hiramatsu 	Dwarf_Locdesc **llbuf;
3074ea42b18SMasami Hiramatsu 	int ret, i;
3084ea42b18SMasami Hiramatsu 
3094ea42b18SMasami Hiramatsu 	ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
3104ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
3114ea42b18SMasami Hiramatsu 	ret = DW_DLV_NO_ENTRY;
3124ea42b18SMasami Hiramatsu 	for (i = 0; i < lcnt; ++i) {
3134ea42b18SMasami Hiramatsu 		if (llbuf[i]->ld_lopc <= addr &&
3144ea42b18SMasami Hiramatsu 		    llbuf[i]->ld_hipc > addr) {
3154ea42b18SMasami Hiramatsu 			memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
3164ea42b18SMasami Hiramatsu 			desc->ld_s =
3174ea42b18SMasami Hiramatsu 				malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
3184ea42b18SMasami Hiramatsu 			ERR_IF(desc->ld_s == NULL);
3194ea42b18SMasami Hiramatsu 			memcpy(desc->ld_s, llbuf[i]->ld_s,
3204ea42b18SMasami Hiramatsu 				sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
3214ea42b18SMasami Hiramatsu 			ret = DW_DLV_OK;
3224ea42b18SMasami Hiramatsu 			break;
3234ea42b18SMasami Hiramatsu 		}
3244ea42b18SMasami Hiramatsu 		dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
3254ea42b18SMasami Hiramatsu 		dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
3264ea42b18SMasami Hiramatsu 	}
3274ea42b18SMasami Hiramatsu 	/* Releasing loop */
3284ea42b18SMasami Hiramatsu 	for (; i < lcnt; ++i) {
3294ea42b18SMasami Hiramatsu 		dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
3304ea42b18SMasami Hiramatsu 		dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
3314ea42b18SMasami Hiramatsu 	}
3324ea42b18SMasami Hiramatsu 	dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
3334ea42b18SMasami Hiramatsu 	return ret;
3344ea42b18SMasami Hiramatsu }
3354ea42b18SMasami Hiramatsu 
3364ea42b18SMasami Hiramatsu /*
3374ea42b18SMasami Hiramatsu  * Probe finder related functions
3384ea42b18SMasami Hiramatsu  */
3394ea42b18SMasami Hiramatsu 
3404ea42b18SMasami Hiramatsu /* Show a location */
3414ea42b18SMasami Hiramatsu static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
3424ea42b18SMasami Hiramatsu {
3434ea42b18SMasami Hiramatsu 	Dwarf_Small op;
3444ea42b18SMasami Hiramatsu 	Dwarf_Unsigned regn;
3454ea42b18SMasami Hiramatsu 	Dwarf_Signed offs;
3464ea42b18SMasami Hiramatsu 	int deref = 0, ret;
3474ea42b18SMasami Hiramatsu 	const char *regs;
3484ea42b18SMasami Hiramatsu 
3494ea42b18SMasami Hiramatsu 	op = loc->lr_atom;
3504ea42b18SMasami Hiramatsu 
3514ea42b18SMasami Hiramatsu 	/* If this is based on frame buffer, set the offset */
3524ea42b18SMasami Hiramatsu 	if (op == DW_OP_fbreg) {
3534ea42b18SMasami Hiramatsu 		deref = 1;
3544ea42b18SMasami Hiramatsu 		offs = (Dwarf_Signed)loc->lr_number;
3554ea42b18SMasami Hiramatsu 		op = pf->fbloc.ld_s[0].lr_atom;
3564ea42b18SMasami Hiramatsu 		loc = &pf->fbloc.ld_s[0];
3574ea42b18SMasami Hiramatsu 	} else
3584ea42b18SMasami Hiramatsu 		offs = 0;
3594ea42b18SMasami Hiramatsu 
3604ea42b18SMasami Hiramatsu 	if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
3614ea42b18SMasami Hiramatsu 		regn = op - DW_OP_breg0;
3624ea42b18SMasami Hiramatsu 		offs += (Dwarf_Signed)loc->lr_number;
3634ea42b18SMasami Hiramatsu 		deref = 1;
3644ea42b18SMasami Hiramatsu 	} else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
3654ea42b18SMasami Hiramatsu 		regn = op - DW_OP_reg0;
3664ea42b18SMasami Hiramatsu 	} else if (op == DW_OP_bregx) {
3674ea42b18SMasami Hiramatsu 		regn = loc->lr_number;
3684ea42b18SMasami Hiramatsu 		offs += (Dwarf_Signed)loc->lr_number2;
3694ea42b18SMasami Hiramatsu 		deref = 1;
3704ea42b18SMasami Hiramatsu 	} else if (op == DW_OP_regx) {
3714ea42b18SMasami Hiramatsu 		regn = loc->lr_number;
3724ea42b18SMasami Hiramatsu 	} else
373*074fc0e4SMasami Hiramatsu 		die("Dwarf_OP %d is not supported.\n", op);
3744ea42b18SMasami Hiramatsu 
3754ea42b18SMasami Hiramatsu 	regs = get_arch_regstr(regn);
3764ea42b18SMasami Hiramatsu 	if (!regs)
377*074fc0e4SMasami Hiramatsu 		die("%lld exceeds max register number.\n", regn);
3784ea42b18SMasami Hiramatsu 
3794ea42b18SMasami Hiramatsu 	if (deref)
3804ea42b18SMasami Hiramatsu 		ret = snprintf(pf->buf, pf->len,
3814ea42b18SMasami Hiramatsu 				 " %s=%+lld(%s)", pf->var, offs, regs);
3824ea42b18SMasami Hiramatsu 	else
3834ea42b18SMasami Hiramatsu 		ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
3844ea42b18SMasami Hiramatsu 	ERR_IF(ret < 0);
3854ea42b18SMasami Hiramatsu 	ERR_IF(ret >= pf->len);
3864ea42b18SMasami Hiramatsu }
3874ea42b18SMasami Hiramatsu 
3884ea42b18SMasami Hiramatsu /* Show a variables in kprobe event format */
3894ea42b18SMasami Hiramatsu static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
3904ea42b18SMasami Hiramatsu {
3914ea42b18SMasami Hiramatsu 	Dwarf_Attribute attr;
3924ea42b18SMasami Hiramatsu 	Dwarf_Locdesc ld;
3934ea42b18SMasami Hiramatsu 	int ret;
3944ea42b18SMasami Hiramatsu 
3954ea42b18SMasami Hiramatsu 	ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error);
3964ea42b18SMasami Hiramatsu 	if (ret != DW_DLV_OK)
3974ea42b18SMasami Hiramatsu 		goto error;
3984ea42b18SMasami Hiramatsu 	ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base));
3994ea42b18SMasami Hiramatsu 	if (ret != DW_DLV_OK)
4004ea42b18SMasami Hiramatsu 		goto error;
4014ea42b18SMasami Hiramatsu 	/* TODO? */
4024ea42b18SMasami Hiramatsu 	ERR_IF(ld.ld_cents != 1);
4034ea42b18SMasami Hiramatsu 	show_location(&ld.ld_s[0], pf);
4044ea42b18SMasami Hiramatsu 	free(ld.ld_s);
4054ea42b18SMasami Hiramatsu 	dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
4064ea42b18SMasami Hiramatsu 	return ;
4074ea42b18SMasami Hiramatsu error:
408*074fc0e4SMasami Hiramatsu 	die("Failed to find the location of %s at this address.\n"
409*074fc0e4SMasami Hiramatsu 	    " Perhaps, it has been optimized out.\n", pf->var);
4104ea42b18SMasami Hiramatsu }
4114ea42b18SMasami Hiramatsu 
4124ea42b18SMasami Hiramatsu static int variable_callback(struct die_link *dlink, void *data)
4134ea42b18SMasami Hiramatsu {
4144ea42b18SMasami Hiramatsu 	struct probe_finder *pf = (struct probe_finder *)data;
4154ea42b18SMasami Hiramatsu 	Dwarf_Half tag;
4164ea42b18SMasami Hiramatsu 	int ret;
4174ea42b18SMasami Hiramatsu 
4184ea42b18SMasami Hiramatsu 	ret = dwarf_tag(dlink->die, &tag, &__dw_error);
4194ea42b18SMasami Hiramatsu 	ERR_IF(ret == DW_DLV_ERROR);
4204ea42b18SMasami Hiramatsu 	if ((tag == DW_TAG_formal_parameter ||
4214ea42b18SMasami Hiramatsu 	     tag == DW_TAG_variable) &&
4224ea42b18SMasami Hiramatsu 	    (die_compare_name(dlink->die, pf->var) == 0)) {
4234ea42b18SMasami Hiramatsu 		show_variable(dlink->die, pf);
4244ea42b18SMasami Hiramatsu 		return 1;
4254ea42b18SMasami Hiramatsu 	}
4264ea42b18SMasami Hiramatsu 	/* TODO: Support struct members and arrays */
4274ea42b18SMasami Hiramatsu 	return 0;
4284ea42b18SMasami Hiramatsu }
4294ea42b18SMasami Hiramatsu 
4304ea42b18SMasami Hiramatsu /* Find a variable in a subprogram die */
4314ea42b18SMasami Hiramatsu static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
4324ea42b18SMasami Hiramatsu {
4334ea42b18SMasami Hiramatsu 	int ret;
4344ea42b18SMasami Hiramatsu 
4354ea42b18SMasami Hiramatsu 	if (!is_c_varname(pf->var)) {
4364ea42b18SMasami Hiramatsu 		/* Output raw parameters */
4374ea42b18SMasami Hiramatsu 		ret = snprintf(pf->buf, pf->len, " %s", pf->var);
4384ea42b18SMasami Hiramatsu 		ERR_IF(ret < 0);
4394ea42b18SMasami Hiramatsu 		ERR_IF(ret >= pf->len);
4404ea42b18SMasami Hiramatsu 		return ;
4414ea42b18SMasami Hiramatsu 	}
4424ea42b18SMasami Hiramatsu 
4434ea42b18SMasami Hiramatsu 	debug("Searching '%s' variable in context.\n", pf->var);
4444ea42b18SMasami Hiramatsu 	/* Search child die for local variables and parameters. */
4454ea42b18SMasami Hiramatsu 	ret = search_die_from_children(sp_die, variable_callback, pf);
4464ea42b18SMasami Hiramatsu 	if (!ret)
447*074fc0e4SMasami Hiramatsu 		die("Failed to find '%s' in this function.\n", pf->var);
4484ea42b18SMasami Hiramatsu }
4494ea42b18SMasami Hiramatsu 
4504ea42b18SMasami Hiramatsu /* Get a frame base on the address */
4514ea42b18SMasami Hiramatsu static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
4524ea42b18SMasami Hiramatsu {
4534ea42b18SMasami Hiramatsu 	Dwarf_Attribute attr;
4544ea42b18SMasami Hiramatsu 	int ret;
4554ea42b18SMasami Hiramatsu 
4564ea42b18SMasami Hiramatsu 	ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
4574ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
4584ea42b18SMasami Hiramatsu 	ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
4594ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
4604ea42b18SMasami Hiramatsu 	dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
4614ea42b18SMasami Hiramatsu }
4624ea42b18SMasami Hiramatsu 
4634ea42b18SMasami Hiramatsu static void free_current_frame_base(struct probe_finder *pf)
4644ea42b18SMasami Hiramatsu {
4654ea42b18SMasami Hiramatsu 	free(pf->fbloc.ld_s);
4664ea42b18SMasami Hiramatsu 	memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
4674ea42b18SMasami Hiramatsu }
4684ea42b18SMasami Hiramatsu 
4694ea42b18SMasami Hiramatsu /* Show a probe point to output buffer */
4704ea42b18SMasami Hiramatsu static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
4714ea42b18SMasami Hiramatsu 			    struct probe_finder *pf)
4724ea42b18SMasami Hiramatsu {
4734ea42b18SMasami Hiramatsu 	struct probe_point *pp = pf->pp;
4744ea42b18SMasami Hiramatsu 	char *name;
4754ea42b18SMasami Hiramatsu 	char tmp[MAX_PROBE_BUFFER];
4764ea42b18SMasami Hiramatsu 	int ret, i, len;
4774ea42b18SMasami Hiramatsu 
4784ea42b18SMasami Hiramatsu 	/* Output name of probe point */
4794ea42b18SMasami Hiramatsu 	ret = dwarf_diename(sp_die, &name, &__dw_error);
4804ea42b18SMasami Hiramatsu 	ERR_IF(ret == DW_DLV_ERROR);
4814ea42b18SMasami Hiramatsu 	if (ret == DW_DLV_OK) {
4824ea42b18SMasami Hiramatsu 		ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
4834ea42b18SMasami Hiramatsu 				(unsigned int)offs);
4844ea42b18SMasami Hiramatsu 		dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
4854ea42b18SMasami Hiramatsu 	} else {
4864ea42b18SMasami Hiramatsu 		/* This function has no name. */
4874ea42b18SMasami Hiramatsu 		ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr);
4884ea42b18SMasami Hiramatsu 	}
4894ea42b18SMasami Hiramatsu 	ERR_IF(ret < 0);
4904ea42b18SMasami Hiramatsu 	ERR_IF(ret >= MAX_PROBE_BUFFER);
4914ea42b18SMasami Hiramatsu 	len = ret;
4924ea42b18SMasami Hiramatsu 
4934ea42b18SMasami Hiramatsu 	/* Find each argument */
4944ea42b18SMasami Hiramatsu 	get_current_frame_base(sp_die, pf);
4954ea42b18SMasami Hiramatsu 	for (i = 0; i < pp->nr_args; i++) {
4964ea42b18SMasami Hiramatsu 		pf->var = pp->args[i];
4974ea42b18SMasami Hiramatsu 		pf->buf = &tmp[len];
4984ea42b18SMasami Hiramatsu 		pf->len = MAX_PROBE_BUFFER - len;
4994ea42b18SMasami Hiramatsu 		find_variable(sp_die, pf);
5004ea42b18SMasami Hiramatsu 		len += strlen(pf->buf);
5014ea42b18SMasami Hiramatsu 	}
5024ea42b18SMasami Hiramatsu 	free_current_frame_base(pf);
5034ea42b18SMasami Hiramatsu 
5044ea42b18SMasami Hiramatsu 	pp->probes[pp->found] = strdup(tmp);
5054ea42b18SMasami Hiramatsu 	pp->found++;
5064ea42b18SMasami Hiramatsu }
5074ea42b18SMasami Hiramatsu 
5084ea42b18SMasami Hiramatsu static int probeaddr_callback(struct die_link *dlink, void *data)
5094ea42b18SMasami Hiramatsu {
5104ea42b18SMasami Hiramatsu 	struct probe_finder *pf = (struct probe_finder *)data;
5114ea42b18SMasami Hiramatsu 	Dwarf_Half tag;
5124ea42b18SMasami Hiramatsu 	Dwarf_Signed offs;
5134ea42b18SMasami Hiramatsu 	int ret;
5144ea42b18SMasami Hiramatsu 
5154ea42b18SMasami Hiramatsu 	ret = dwarf_tag(dlink->die, &tag, &__dw_error);
5164ea42b18SMasami Hiramatsu 	ERR_IF(ret == DW_DLV_ERROR);
5174ea42b18SMasami Hiramatsu 	/* Check the address is in this subprogram */
5184ea42b18SMasami Hiramatsu 	if (tag == DW_TAG_subprogram &&
5194ea42b18SMasami Hiramatsu 	    die_within_subprogram(dlink->die, pf->addr, &offs)) {
5204ea42b18SMasami Hiramatsu 		show_probepoint(dlink->die, offs, pf);
5214ea42b18SMasami Hiramatsu 		return 1;
5224ea42b18SMasami Hiramatsu 	}
5234ea42b18SMasami Hiramatsu 	return 0;
5244ea42b18SMasami Hiramatsu }
5254ea42b18SMasami Hiramatsu 
5264ea42b18SMasami Hiramatsu /* Find probe point from its line number */
5274ea42b18SMasami Hiramatsu static void find_by_line(Dwarf_Die cu_die, struct probe_finder *pf)
5284ea42b18SMasami Hiramatsu {
5294ea42b18SMasami Hiramatsu 	struct probe_point *pp = pf->pp;
5304ea42b18SMasami Hiramatsu 	Dwarf_Signed cnt, i;
5314ea42b18SMasami Hiramatsu 	Dwarf_Line *lines;
5324ea42b18SMasami Hiramatsu 	Dwarf_Unsigned lineno = 0;
5334ea42b18SMasami Hiramatsu 	Dwarf_Addr addr;
5344ea42b18SMasami Hiramatsu 	Dwarf_Unsigned fno;
5354ea42b18SMasami Hiramatsu 	int ret;
5364ea42b18SMasami Hiramatsu 
5374ea42b18SMasami Hiramatsu 	ret = dwarf_srclines(cu_die, &lines, &cnt, &__dw_error);
5384ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
5394ea42b18SMasami Hiramatsu 
5404ea42b18SMasami Hiramatsu 	for (i = 0; i < cnt; i++) {
5414ea42b18SMasami Hiramatsu 		ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
5424ea42b18SMasami Hiramatsu 		ERR_IF(ret != DW_DLV_OK);
5434ea42b18SMasami Hiramatsu 		if (fno != pf->fno)
5444ea42b18SMasami Hiramatsu 			continue;
5454ea42b18SMasami Hiramatsu 
5464ea42b18SMasami Hiramatsu 		ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
5474ea42b18SMasami Hiramatsu 		ERR_IF(ret != DW_DLV_OK);
5484ea42b18SMasami Hiramatsu 		if (lineno != (Dwarf_Unsigned)pp->line)
5494ea42b18SMasami Hiramatsu 			continue;
5504ea42b18SMasami Hiramatsu 
5514ea42b18SMasami Hiramatsu 		ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
5524ea42b18SMasami Hiramatsu 		ERR_IF(ret != DW_DLV_OK);
5534ea42b18SMasami Hiramatsu 		debug("Probe point found: 0x%llx\n", addr);
5544ea42b18SMasami Hiramatsu 		pf->addr = addr;
5554ea42b18SMasami Hiramatsu 		/* Search a real subprogram including this line, */
5564ea42b18SMasami Hiramatsu 		ret = search_die_from_children(cu_die, probeaddr_callback, pf);
5574ea42b18SMasami Hiramatsu 		if (ret == 0)
558*074fc0e4SMasami Hiramatsu 			die("Probe point is not found in subprograms.\n");
5594ea42b18SMasami Hiramatsu 		/* Continuing, because target line might be inlined. */
5604ea42b18SMasami Hiramatsu 	}
5614ea42b18SMasami Hiramatsu 	dwarf_srclines_dealloc(__dw_debug, lines, cnt);
5624ea42b18SMasami Hiramatsu }
5634ea42b18SMasami Hiramatsu 
5644ea42b18SMasami Hiramatsu /* Search function from function name */
5654ea42b18SMasami Hiramatsu static int probefunc_callback(struct die_link *dlink, void *data)
5664ea42b18SMasami Hiramatsu {
5674ea42b18SMasami Hiramatsu 	struct probe_finder *pf = (struct probe_finder *)data;
5684ea42b18SMasami Hiramatsu 	struct probe_point *pp = pf->pp;
5694ea42b18SMasami Hiramatsu 	struct die_link *lk;
5704ea42b18SMasami Hiramatsu 	Dwarf_Signed offs;
5714ea42b18SMasami Hiramatsu 	Dwarf_Half tag;
5724ea42b18SMasami Hiramatsu 	int ret;
5734ea42b18SMasami Hiramatsu 
5744ea42b18SMasami Hiramatsu 	ret = dwarf_tag(dlink->die, &tag, &__dw_error);
5754ea42b18SMasami Hiramatsu 	ERR_IF(ret == DW_DLV_ERROR);
5764ea42b18SMasami Hiramatsu 	if (tag == DW_TAG_subprogram) {
5774ea42b18SMasami Hiramatsu 		if (die_compare_name(dlink->die, pp->function) == 0) {
5784ea42b18SMasami Hiramatsu 			if (die_inlined_subprogram(dlink->die)) {
5794ea42b18SMasami Hiramatsu 				/* Inlined function, save it. */
5804ea42b18SMasami Hiramatsu 				ret = dwarf_die_CU_offset(dlink->die,
5814ea42b18SMasami Hiramatsu 							  &pf->inl_offs,
5824ea42b18SMasami Hiramatsu 							  &__dw_error);
5834ea42b18SMasami Hiramatsu 				ERR_IF(ret != DW_DLV_OK);
5844ea42b18SMasami Hiramatsu 				debug("inline definition offset %lld\n",
5854ea42b18SMasami Hiramatsu 					pf->inl_offs);
5864ea42b18SMasami Hiramatsu 				return 0;
5874ea42b18SMasami Hiramatsu 			}
5884ea42b18SMasami Hiramatsu 			/* Get probe address */
5894ea42b18SMasami Hiramatsu 			pf->addr = die_get_entrypc(dlink->die);
5904ea42b18SMasami Hiramatsu 			pf->addr += pp->offset;
5914ea42b18SMasami Hiramatsu 			/* TODO: Check the address in this function */
5924ea42b18SMasami Hiramatsu 			show_probepoint(dlink->die, pp->offset, pf);
5934ea42b18SMasami Hiramatsu 			/* Continue to search */
5944ea42b18SMasami Hiramatsu 		}
5954ea42b18SMasami Hiramatsu 	} else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
5964ea42b18SMasami Hiramatsu 		if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
5974ea42b18SMasami Hiramatsu 			/* Get probe address */
5984ea42b18SMasami Hiramatsu 			pf->addr = die_get_entrypc(dlink->die);
5994ea42b18SMasami Hiramatsu 			pf->addr += pp->offset;
6004ea42b18SMasami Hiramatsu 			debug("found inline addr: 0x%llx\n", pf->addr);
6014ea42b18SMasami Hiramatsu 			/* Inlined function. Get a real subprogram */
6024ea42b18SMasami Hiramatsu 			for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
6034ea42b18SMasami Hiramatsu 				tag = 0;
6044ea42b18SMasami Hiramatsu 				dwarf_tag(lk->die, &tag, &__dw_error);
6054ea42b18SMasami Hiramatsu 				ERR_IF(ret == DW_DLV_ERROR);
6064ea42b18SMasami Hiramatsu 				if (tag == DW_TAG_subprogram &&
6074ea42b18SMasami Hiramatsu 				    !die_inlined_subprogram(lk->die))
6084ea42b18SMasami Hiramatsu 					goto found;
6094ea42b18SMasami Hiramatsu 			}
610*074fc0e4SMasami Hiramatsu 			die("Failed to find real subprogram.\n");
6114ea42b18SMasami Hiramatsu found:
6124ea42b18SMasami Hiramatsu 			/* Get offset from subprogram */
6134ea42b18SMasami Hiramatsu 			ret = die_within_subprogram(lk->die, pf->addr, &offs);
6144ea42b18SMasami Hiramatsu 			ERR_IF(!ret);
6154ea42b18SMasami Hiramatsu 			show_probepoint(lk->die, offs, pf);
6164ea42b18SMasami Hiramatsu 			/* Continue to search */
6174ea42b18SMasami Hiramatsu 		}
6184ea42b18SMasami Hiramatsu 	}
6194ea42b18SMasami Hiramatsu 	return 0;
6204ea42b18SMasami Hiramatsu }
6214ea42b18SMasami Hiramatsu 
6224ea42b18SMasami Hiramatsu static void find_by_func(Dwarf_Die cu_die, struct probe_finder *pf)
6234ea42b18SMasami Hiramatsu {
6244ea42b18SMasami Hiramatsu 	search_die_from_children(cu_die, probefunc_callback, pf);
6254ea42b18SMasami Hiramatsu }
6264ea42b18SMasami Hiramatsu 
6274ea42b18SMasami Hiramatsu /* Find a probe point */
6284ea42b18SMasami Hiramatsu int find_probepoint(int fd, struct probe_point *pp)
6294ea42b18SMasami Hiramatsu {
6304ea42b18SMasami Hiramatsu 	Dwarf_Half addr_size = 0;
6314ea42b18SMasami Hiramatsu 	Dwarf_Unsigned next_cuh = 0;
6324ea42b18SMasami Hiramatsu 	Dwarf_Die cu_die = 0;
6334ea42b18SMasami Hiramatsu 	int cu_number = 0, ret;
6344ea42b18SMasami Hiramatsu 	struct probe_finder pf = {.pp = pp};
6354ea42b18SMasami Hiramatsu 
6364ea42b18SMasami Hiramatsu 	ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
6374ea42b18SMasami Hiramatsu 	if (ret != DW_DLV_OK)
638*074fc0e4SMasami Hiramatsu 		die("Failed to call dwarf_init(). Maybe, not a dwarf file.\n");
6394ea42b18SMasami Hiramatsu 
6404ea42b18SMasami Hiramatsu 	pp->found = 0;
6414ea42b18SMasami Hiramatsu 	while (++cu_number) {
6424ea42b18SMasami Hiramatsu 		/* Search CU (Compilation Unit) */
6434ea42b18SMasami Hiramatsu 		ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
6444ea42b18SMasami Hiramatsu 			&addr_size, &next_cuh, &__dw_error);
6454ea42b18SMasami Hiramatsu 		ERR_IF(ret == DW_DLV_ERROR);
6464ea42b18SMasami Hiramatsu 		if (ret == DW_DLV_NO_ENTRY)
6474ea42b18SMasami Hiramatsu 			break;
6484ea42b18SMasami Hiramatsu 
6494ea42b18SMasami Hiramatsu 		/* Get the DIE(Debugging Information Entry) of this CU */
6504ea42b18SMasami Hiramatsu 		ret = dwarf_siblingof(__dw_debug, 0, &cu_die, &__dw_error);
6514ea42b18SMasami Hiramatsu 		ERR_IF(ret != DW_DLV_OK);
6524ea42b18SMasami Hiramatsu 
6534ea42b18SMasami Hiramatsu 		/* Check if target file is included. */
6544ea42b18SMasami Hiramatsu 		if (pp->file)
6554ea42b18SMasami Hiramatsu 			pf.fno = die_get_fileno(cu_die, pp->file);
6564ea42b18SMasami Hiramatsu 
6574ea42b18SMasami Hiramatsu 		if (!pp->file || pf.fno) {
6584ea42b18SMasami Hiramatsu 			/* Save CU base address (for frame_base) */
6594ea42b18SMasami Hiramatsu 			ret = dwarf_lowpc(cu_die, &pf.cu_base, &__dw_error);
6604ea42b18SMasami Hiramatsu 			ERR_IF(ret == DW_DLV_ERROR);
6614ea42b18SMasami Hiramatsu 			if (ret == DW_DLV_NO_ENTRY)
6624ea42b18SMasami Hiramatsu 				pf.cu_base = 0;
6634ea42b18SMasami Hiramatsu 			if (pp->line)
6644ea42b18SMasami Hiramatsu 				find_by_line(cu_die, &pf);
6654ea42b18SMasami Hiramatsu 			if (pp->function)
6664ea42b18SMasami Hiramatsu 				find_by_func(cu_die, &pf);
6674ea42b18SMasami Hiramatsu 		}
6684ea42b18SMasami Hiramatsu 		dwarf_dealloc(__dw_debug, cu_die, DW_DLA_DIE);
6694ea42b18SMasami Hiramatsu 	}
6704ea42b18SMasami Hiramatsu 	ret = dwarf_finish(__dw_debug, &__dw_error);
6714ea42b18SMasami Hiramatsu 	ERR_IF(ret != DW_DLV_OK);
6724ea42b18SMasami Hiramatsu 
6734ea42b18SMasami Hiramatsu 	return pp->found;
6744ea42b18SMasami Hiramatsu }
6754ea42b18SMasami Hiramatsu 
676