1221569Sobrien/*-
2221569Sobrien * Copyright (c) 2008-2009, 2011, Juniper Networks, Inc.
3221569Sobrien * All rights reserved.
4221569Sobrien *
5221569Sobrien * Redistribution and use in source and binary forms, with or without
6221569Sobrien * modification, are permitted provided that the following conditions
7221569Sobrien * are met:
8221569Sobrien * 1. Redistributions of source code must retain the above copyright
9221569Sobrien *    notice, this list of conditions and the following disclaimer.
10221569Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11221569Sobrien *    notice, this list of conditions and the following disclaimer in the
12221569Sobrien *    documentation and/or other materials provided with the distribution.
13221569Sobrien *
14221569Sobrien * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15221569Sobrien * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16221569Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17221569Sobrien * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
18221569Sobrien * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19221569Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20221569Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21221569Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22221569Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23221569Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24221569Sobrien * THE POSSIBILITY OF SUCH DAMAGE.
25221569Sobrien *
26221569Sobrien *	JNPR: dwarf_func.c 336441 2009-10-17 09:19:54Z deo
27221569Sobrien */
28221569Sobrien
29221569Sobrien#include <sys/cdefs.h>
30221569Sobrien__FBSDID("$FreeBSD$");
31221569Sobrien
32221569Sobrien#include <stdlib.h>
33221569Sobrien#include <string.h>
34221569Sobrien#include <libdwarf.h>
35221569Sobrien#include <_libdwarf.h>
36221569Sobrien
37221569Sobrienstatic void
38221569Sobriendwarf_add_function(Dwarf_Debug dbg, Dwarf_Func func)
39221569Sobrien{
40221569Sobrien
41221569Sobrien	STAILQ_INSERT_TAIL(&dbg->dbg_func, func, func_next);
42221569Sobrien}
43221569Sobrien
44221569Sobrienint
45221569Sobriendwarf_function_get_addr_range(Dwarf_Func f, Dwarf_Addr *low_pc,
46221569Sobrien    Dwarf_Addr *high_pc)
47221569Sobrien{
48221569Sobrien
49221569Sobrien	*low_pc = f->func_low_pc;
50221569Sobrien	*high_pc = f->func_high_pc;
51221569Sobrien	return 0;
52221569Sobrien}
53221569Sobrien
54221569Sobrienint
55221569Sobriendwarf_inlined_function_get_addr_range(Dwarf_Inlined_Func f, Dwarf_Addr *low_pc,
56221569Sobrien    Dwarf_Addr *high_pc)
57221569Sobrien{
58221569Sobrien
59221569Sobrien	*low_pc = f->ifunc_low_pc;
60221569Sobrien	*high_pc = f->ifunc_high_pc;
61221569Sobrien	return 0;
62221569Sobrien}
63221569Sobrien
64221569Sobrienint
65221569Sobriendwarf_function_is_inlined(Dwarf_Func f)
66221569Sobrien{
67221569Sobrien
68221569Sobrien	if (f->func_is_inlined == DW_INL_inlined ||
69221569Sobrien	    f->func_is_inlined == DW_INL_declared_inlined)
70221569Sobrien		return 1;
71221569Sobrien	else
72221569Sobrien		return 0;
73221569Sobrien}
74221569Sobrien
75221569SobrienDwarf_Func
76221569Sobriendwarf_find_function_by_name(Dwarf_Debug dbg, const char *name)
77221569Sobrien{
78221569Sobrien	/* XXX: replace with a fast version */
79221569Sobrien
80221569Sobrien	Dwarf_Func func;
81221569Sobrien	STAILQ_FOREACH(func, &dbg->dbg_func, func_next) {
82221569Sobrien		if (strcmp(name, func->func_name) == 0)
83221569Sobrien			return func;
84221569Sobrien	}
85221569Sobrien	return NULL;
86221569Sobrien}
87221569Sobrien
88221569SobrienDwarf_Func
89221569Sobriendwarf_find_function_by_offset(Dwarf_Debug dbg, Dwarf_Off off)
90221569Sobrien{
91221569Sobrien
92221569Sobrien	Dwarf_Func func;
93221569Sobrien	Dwarf_Die die;
94221569Sobrien	/* printf("look for %llx\n", off); */
95221569Sobrien	STAILQ_FOREACH(func, &dbg->dbg_func, func_next) {
96221569Sobrien		die = func->func_die;
97221569Sobrien		if ((off_t)die->die_offset == off) {
98221569Sobrien			return func;
99221569Sobrien		}
100221569Sobrien	}
101221569Sobrien	return NULL;
102221569Sobrien}
103221569Sobrien
104221569Sobrienvoid
105221569Sobriendwarf_build_function_table(Dwarf_Debug dbg)
106221569Sobrien{
107221569Sobrien	Dwarf_CU cu;
108221569Sobrien	Dwarf_AttrValue av;
109221569Sobrien	Dwarf_Die die, origin_die;
110221569Sobrien	Dwarf_Func func, origin_func;
111221569Sobrien	Dwarf_Inlined_Func ifunc;
112221569Sobrien	unsigned long long offset;
113221569Sobrien	const char *name;
114221569Sobrien	Dwarf_Error error;
115221569Sobrien
116221569Sobrien	/*
117221569Sobrien	 * find out all the functions
118221569Sobrien	 */
119221569Sobrien	STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
120221569Sobrien		STAILQ_FOREACH(die, &cu->cu_die, die_next) {
121221569Sobrien			if (die->die_a->a_tag == DW_TAG_subprogram) {
122221569Sobrien				/*
123221569Sobrien				 * Some function has multiple entries, i.e.
124221569Sobrien				 * if a function is inlined, it has many
125221569Sobrien				 * abstract/concrete instances, the abstract
126221569Sobrien				 * instances are with DW_TAG_subprogram.
127221569Sobrien				 */
128221569Sobrien				dwarf_attrval_string(die, DW_AT_name, &name,
129221569Sobrien				    &error);
130221569Sobrien				func = dwarf_find_function_by_name(dbg, name);
131221569Sobrien				if (func == NULL) {
132221569Sobrien					func = malloc(
133221569Sobrien					    sizeof(struct _Dwarf_Func));
134221569Sobrien					DWARF_ASSERT(func);
135221569Sobrien
136221569Sobrien					func->func_die = die;
137221569Sobrien					func->func_name = name;
138221569Sobrien					STAILQ_INIT(
139221569Sobrien					    &func->func_inlined_instances);
140221569Sobrien
141221569Sobrien					dwarf_add_function(dbg, func);
142221569Sobrien					STAILQ_FOREACH(av, &die->die_attrval,
143221569Sobrien					    av_next) {
144221569Sobrien						switch (av->av_attrib) {
145221569Sobrien						case DW_AT_low_pc:
146221569Sobrien							func->func_low_pc =
147221569Sobrien							    av->u[0].u64;
148221569Sobrien							break;
149221569Sobrien						case DW_AT_high_pc:
150221569Sobrien							func->func_high_pc =
151221569Sobrien							    av->u[0].u64;
152221569Sobrien							break;
153221569Sobrien						case DW_AT_inline:
154221569Sobrien							func->func_is_inlined =
155221569Sobrien							    av->u[0].u64;
156221569Sobrien							break;
157221569Sobrien						}
158221569Sobrien					}
159221569Sobrien				}
160221569Sobrien			}
161221569Sobrien		}
162221569Sobrien	}
163221569Sobrien
164221569Sobrien	/*
165221569Sobrien	 * Now check the concrete inlined instances.
166221569Sobrien	 */
167221569Sobrien	STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
168221569Sobrien		STAILQ_FOREACH(die, &cu->cu_die, die_next) {
169221569Sobrien			if (die->die_a->a_tag == DW_TAG_inlined_subroutine) {
170221569Sobrien				ifunc = malloc(
171221569Sobrien				    sizeof(struct _Dwarf_Inlined_Func));
172221569Sobrien				DWARF_ASSERT(ifunc);
173221569Sobrien				STAILQ_FOREACH(av, &die->die_attrval, av_next) {
174221569Sobrien					switch (av->av_attrib) {
175221569Sobrien					case DW_AT_abstract_origin:
176221569Sobrien						offset = av->u[0].u64 +
177221569Sobrien						    die->die_cu->cu_offset;
178221569Sobrien						origin_die = dwarf_die_find(
179221569Sobrien							die, offset);
180221569Sobrien						DWARF_ASSERT(origin_die != 0);
181221569Sobrien
182221569Sobrien						/*
183221569Sobrien						 * the abstract origin must
184221569Sobrien						 * have been merged with
185221569Sobrien						 * another die
186221569Sobrien						 */
187221569Sobrien						dwarf_attrval_string(
188221569Sobrien						    origin_die, DW_AT_name,
189221569Sobrien						    &name, &error);
190221569Sobrien						origin_func =
191221569Sobrien						    dwarf_find_function_by_name
192221569Sobrien						    (dbg, name);
193221569Sobrien						DWARF_ASSERT(origin_func != 0);
194221569Sobrien
195221569Sobrien						STAILQ_INSERT_TAIL(
196221569Sobrien						    &origin_func->
197221569Sobrien						    func_inlined_instances,
198221569Sobrien						    ifunc, ifunc_next);
199221569Sobrien
200221569Sobrien						break;
201221569Sobrien					case DW_AT_low_pc:
202221569Sobrien						ifunc->ifunc_low_pc =
203221569Sobrien						    av->u[0].u64;
204221569Sobrien						break;
205221569Sobrien					case DW_AT_high_pc:
206221569Sobrien						ifunc->ifunc_high_pc =
207221569Sobrien						    av->u[0].u64;
208221569Sobrien						break;
209221569Sobrien					}
210221569Sobrien				}
211221569Sobrien			}
212221569Sobrien		}
213221569Sobrien	}
214221569Sobrien}
215221569Sobrien
216221569Sobrienvoid
217221569Sobriendwarf_function_iterate_inlined_instance(Dwarf_Func func,
218221569Sobrien    Dwarf_Inlined_Callback f, void *data)
219221569Sobrien{
220221569Sobrien	Dwarf_Inlined_Func ifunc;
221221569Sobrien
222221569Sobrien	if (!dwarf_function_is_inlined(func))
223221569Sobrien		return;
224221569Sobrien	STAILQ_FOREACH(ifunc, &func->func_inlined_instances, ifunc_next) {
225221569Sobrien		f(ifunc, data);
226221569Sobrien	}
227221569Sobrien}
228