1/*-
2 * Copyright (c) 2007 John Birrell (jb@freebsd.org)
3 * Copyright (c) 2009-2011 Kai Wang
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include "_libdwarf.h"
29
30ELFTC_VCSID("$Id: libdwarf_abbrev.c 3420 2016-02-27 02:14:05Z emaste $");
31
32int
33_dwarf_abbrev_add(Dwarf_CU cu, uint64_t entry, uint64_t tag, uint8_t children,
34    uint64_t aboff, Dwarf_Abbrev *abp, Dwarf_Error *error)
35{
36	Dwarf_Abbrev ab;
37	Dwarf_Debug dbg;
38
39	dbg = cu != NULL ? cu->cu_dbg : NULL;
40
41	if ((ab = malloc(sizeof(struct _Dwarf_Abbrev))) == NULL) {
42		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
43		return (DW_DLE_MEMORY);
44	}
45
46	/* Initialise the abbrev structure. */
47	ab->ab_entry	= entry;
48	ab->ab_tag	= tag;
49	ab->ab_children	= children;
50	ab->ab_offset	= aboff;
51	ab->ab_length	= 0;	/* fill in later. */
52	ab->ab_atnum	= 0;	/* fill in later. */
53
54	/* Initialise the list of attribute definitions. */
55	STAILQ_INIT(&ab->ab_attrdef);
56
57	/* Add the abbrev to the hash table of the compilation unit. */
58	if (cu != NULL)
59		HASH_ADD(ab_hh, cu->cu_abbrev_hash, ab_entry,
60		    sizeof(ab->ab_entry), ab);
61
62	*abp = ab;
63	return (DW_DLE_NONE);
64}
65
66int
67_dwarf_attrdef_add(Dwarf_Debug dbg, Dwarf_Abbrev ab, uint64_t attr,
68    uint64_t form, uint64_t adoff, Dwarf_AttrDef *adp, Dwarf_Error *error)
69{
70	Dwarf_AttrDef ad;
71
72	if (ab == NULL) {
73		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
74		return (DW_DLE_ARGUMENT);
75	}
76
77	if ((ad = malloc(sizeof(struct _Dwarf_AttrDef))) == NULL) {
78		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
79		return (DW_DLE_MEMORY);
80	}
81
82	/* Initialise the attribute definition structure. */
83	ad->ad_attrib	= attr;
84	ad->ad_form	= form;
85	ad->ad_offset	= adoff;
86
87	/* Add the attribute definition to the list in the abbrev. */
88	STAILQ_INSERT_TAIL(&ab->ab_attrdef, ad, ad_next);
89
90	/* Increase number of attribute counter. */
91	ab->ab_atnum++;
92
93	if (adp != NULL)
94		*adp = ad;
95
96	return (DW_DLE_NONE);
97}
98
99int
100_dwarf_abbrev_parse(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Unsigned *offset,
101    Dwarf_Abbrev *abp, Dwarf_Error *error)
102{
103	Dwarf_Section *ds;
104	uint64_t attr;
105	uint64_t entry;
106	uint64_t form;
107	uint64_t aboff;
108	uint64_t adoff;
109	uint64_t tag;
110	uint8_t children;
111	int ret;
112
113	assert(abp != NULL);
114
115	ds = _dwarf_find_section(dbg, ".debug_abbrev");
116	if (ds == NULL || *offset >= ds->ds_size)
117		return (DW_DLE_NO_ENTRY);
118
119	aboff = *offset;
120
121	entry = _dwarf_read_uleb128(ds->ds_data, offset);
122	if (entry == 0) {
123		/* Last entry. */
124		ret = _dwarf_abbrev_add(cu, entry, 0, 0, aboff, abp,
125		    error);
126		if (ret == DW_DLE_NONE) {
127			(*abp)->ab_length = 1;
128			return (ret);
129		} else
130			return (ret);
131	}
132	tag = _dwarf_read_uleb128(ds->ds_data, offset);
133	children = dbg->read(ds->ds_data, offset, 1);
134	if ((ret = _dwarf_abbrev_add(cu, entry, tag, children, aboff,
135	    abp, error)) != DW_DLE_NONE)
136		return (ret);
137
138	/* Parse attribute definitions. */
139	do {
140		adoff = *offset;
141		attr = _dwarf_read_uleb128(ds->ds_data, offset);
142		form = _dwarf_read_uleb128(ds->ds_data, offset);
143		if (attr != 0)
144			if ((ret = _dwarf_attrdef_add(dbg, *abp, attr,
145			    form, adoff, NULL, error)) != DW_DLE_NONE)
146				return (ret);
147	} while (attr != 0);
148
149	(*abp)->ab_length = *offset - aboff;
150
151	return (ret);
152}
153
154int
155_dwarf_abbrev_find(Dwarf_CU cu, uint64_t entry, Dwarf_Abbrev *abp,
156    Dwarf_Error *error)
157{
158	Dwarf_Abbrev ab;
159	Dwarf_Section *ds;
160	Dwarf_Unsigned offset;
161	int ret;
162
163	if (entry == 0)
164		return (DW_DLE_NO_ENTRY);
165
166	/* Check if the desired abbrev entry is already in the hash table. */
167	HASH_FIND(ab_hh, cu->cu_abbrev_hash, &entry, sizeof(entry), ab);
168	if (ab != NULL) {
169		*abp = ab;
170		return (DW_DLE_NONE);
171	}
172
173	if (cu->cu_abbrev_loaded) {
174		return (DW_DLE_NO_ENTRY);
175	}
176
177	/* Load and search the abbrev table. */
178	ds = _dwarf_find_section(cu->cu_dbg, ".debug_abbrev");
179	if (ds == NULL)
180		return (DW_DLE_NO_ENTRY);
181
182	offset = cu->cu_abbrev_offset_cur;
183	while (offset < ds->ds_size) {
184		ret = _dwarf_abbrev_parse(cu->cu_dbg, cu, &offset, &ab, error);
185		if (ret != DW_DLE_NONE)
186			return (ret);
187		if (ab->ab_entry == entry) {
188			cu->cu_abbrev_offset_cur = offset;
189			*abp = ab;
190			return (DW_DLE_NONE);
191		}
192		if (ab->ab_entry == 0) {
193			cu->cu_abbrev_offset_cur = offset;
194			cu->cu_abbrev_loaded = 1;
195			break;
196		}
197	}
198
199	return (DW_DLE_NO_ENTRY);
200}
201
202void
203_dwarf_abbrev_cleanup(Dwarf_CU cu)
204{
205	Dwarf_Abbrev ab, tab;
206	Dwarf_AttrDef ad, tad;
207
208	assert(cu != NULL);
209
210	HASH_ITER(ab_hh, cu->cu_abbrev_hash, ab, tab) {
211		HASH_DELETE(ab_hh, cu->cu_abbrev_hash, ab);
212		STAILQ_FOREACH_SAFE(ad, &ab->ab_attrdef, ad_next, tad) {
213			STAILQ_REMOVE(&ab->ab_attrdef, ad, _Dwarf_AttrDef,
214			    ad_next);
215			free(ad);
216		}
217		free(ab);
218	}
219}
220
221int
222_dwarf_abbrev_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
223{
224	Dwarf_CU cu;
225	Dwarf_Abbrev ab;
226	Dwarf_AttrDef ad;
227	Dwarf_P_Section ds;
228	int ret;
229
230	cu = STAILQ_FIRST(&dbg->dbg_cu);
231	if (cu == NULL)
232		return (DW_DLE_NONE);
233
234	/* Create .debug_abbrev section. */
235	if ((ret = _dwarf_section_init(dbg, &ds, ".debug_abbrev", 0, error)) !=
236	    DW_DLE_NONE)
237		return (ret);
238
239	for (ab = cu->cu_abbrev_hash; ab != NULL; ab = ab->ab_hh.next) {
240		RCHECK(WRITE_ULEB128(ab->ab_entry));
241		RCHECK(WRITE_ULEB128(ab->ab_tag));
242		RCHECK(WRITE_VALUE(ab->ab_children, 1));
243		STAILQ_FOREACH(ad, &ab->ab_attrdef, ad_next) {
244			RCHECK(WRITE_ULEB128(ad->ad_attrib));
245			RCHECK(WRITE_ULEB128(ad->ad_form));
246		}
247		/* Signal end of attribute spec list. */
248		RCHECK(WRITE_ULEB128(0));
249		RCHECK(WRITE_ULEB128(0));
250	}
251	/* End of abbreviation for this CU. */
252	RCHECK(WRITE_ULEB128(0));
253
254	/* Notify the creation of .debug_abbrev ELF section. */
255	RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
256
257	return (DW_DLE_NONE);
258
259gen_fail:
260
261	_dwarf_section_free(dbg, &ds);
262
263	return (ret);
264}
265