1260684Skaiw/*-
2260684Skaiw * Copyright (c) 2007 John Birrell (jb@freebsd.org)
3260684Skaiw * Copyright (c) 2009-2011 Kai Wang
4260684Skaiw * All rights reserved.
5260684Skaiw *
6260684Skaiw * Redistribution and use in source and binary forms, with or without
7260684Skaiw * modification, are permitted provided that the following conditions
8260684Skaiw * are met:
9260684Skaiw * 1. Redistributions of source code must retain the above copyright
10260684Skaiw *    notice, this list of conditions and the following disclaimer.
11260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright
12260684Skaiw *    notice, this list of conditions and the following disclaimer in the
13260684Skaiw *    documentation and/or other materials provided with the distribution.
14260684Skaiw *
15260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16260684Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17260684Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18260684Skaiw * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19260684Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20260684Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21260684Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22260684Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23260684Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24260684Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25260684Skaiw * SUCH DAMAGE.
26260684Skaiw */
27260684Skaiw
28260684Skaiw#include "_libdwarf.h"
29260684Skaiw
30300311SemasteELFTC_VCSID("$Id: libdwarf_abbrev.c 3420 2016-02-27 02:14:05Z emaste $");
31260684Skaiw
32260684Skaiwint
33260684Skaiw_dwarf_abbrev_add(Dwarf_CU cu, uint64_t entry, uint64_t tag, uint8_t children,
34260684Skaiw    uint64_t aboff, Dwarf_Abbrev *abp, Dwarf_Error *error)
35260684Skaiw{
36260684Skaiw	Dwarf_Abbrev ab;
37260684Skaiw	Dwarf_Debug dbg;
38260684Skaiw
39260684Skaiw	dbg = cu != NULL ? cu->cu_dbg : NULL;
40260684Skaiw
41260684Skaiw	if ((ab = malloc(sizeof(struct _Dwarf_Abbrev))) == NULL) {
42260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
43260684Skaiw		return (DW_DLE_MEMORY);
44260684Skaiw	}
45260684Skaiw
46260684Skaiw	/* Initialise the abbrev structure. */
47260684Skaiw	ab->ab_entry	= entry;
48260684Skaiw	ab->ab_tag	= tag;
49260684Skaiw	ab->ab_children	= children;
50260684Skaiw	ab->ab_offset	= aboff;
51260684Skaiw	ab->ab_length	= 0;	/* fill in later. */
52260684Skaiw	ab->ab_atnum	= 0;	/* fill in later. */
53260684Skaiw
54260684Skaiw	/* Initialise the list of attribute definitions. */
55260684Skaiw	STAILQ_INIT(&ab->ab_attrdef);
56260684Skaiw
57260684Skaiw	/* Add the abbrev to the hash table of the compilation unit. */
58260684Skaiw	if (cu != NULL)
59260684Skaiw		HASH_ADD(ab_hh, cu->cu_abbrev_hash, ab_entry,
60260684Skaiw		    sizeof(ab->ab_entry), ab);
61260684Skaiw
62367466Sdim	*abp = ab;
63260684Skaiw	return (DW_DLE_NONE);
64260684Skaiw}
65260684Skaiw
66260684Skaiwint
67260684Skaiw_dwarf_attrdef_add(Dwarf_Debug dbg, Dwarf_Abbrev ab, uint64_t attr,
68260684Skaiw    uint64_t form, uint64_t adoff, Dwarf_AttrDef *adp, Dwarf_Error *error)
69260684Skaiw{
70260684Skaiw	Dwarf_AttrDef ad;
71260684Skaiw
72260684Skaiw	if (ab == NULL) {
73260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
74260684Skaiw		return (DW_DLE_ARGUMENT);
75260684Skaiw	}
76260684Skaiw
77260684Skaiw	if ((ad = malloc(sizeof(struct _Dwarf_AttrDef))) == NULL) {
78260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
79260684Skaiw		return (DW_DLE_MEMORY);
80260684Skaiw	}
81260684Skaiw
82260684Skaiw	/* Initialise the attribute definition structure. */
83260684Skaiw	ad->ad_attrib	= attr;
84260684Skaiw	ad->ad_form	= form;
85260684Skaiw	ad->ad_offset	= adoff;
86260684Skaiw
87260684Skaiw	/* Add the attribute definition to the list in the abbrev. */
88260684Skaiw	STAILQ_INSERT_TAIL(&ab->ab_attrdef, ad, ad_next);
89260684Skaiw
90260684Skaiw	/* Increase number of attribute counter. */
91260684Skaiw	ab->ab_atnum++;
92260684Skaiw
93260684Skaiw	if (adp != NULL)
94260684Skaiw		*adp = ad;
95260684Skaiw
96260684Skaiw	return (DW_DLE_NONE);
97260684Skaiw}
98260684Skaiw
99260684Skaiwint
100260684Skaiw_dwarf_abbrev_parse(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Unsigned *offset,
101260684Skaiw    Dwarf_Abbrev *abp, Dwarf_Error *error)
102260684Skaiw{
103260684Skaiw	Dwarf_Section *ds;
104260684Skaiw	uint64_t attr;
105260684Skaiw	uint64_t entry;
106260684Skaiw	uint64_t form;
107260684Skaiw	uint64_t aboff;
108260684Skaiw	uint64_t adoff;
109260684Skaiw	uint64_t tag;
110260684Skaiw	uint8_t children;
111260684Skaiw	int ret;
112260684Skaiw
113260684Skaiw	assert(abp != NULL);
114260684Skaiw
115260684Skaiw	ds = _dwarf_find_section(dbg, ".debug_abbrev");
116300311Semaste	if (ds == NULL || *offset >= ds->ds_size)
117260684Skaiw		return (DW_DLE_NO_ENTRY);
118260684Skaiw
119260684Skaiw	aboff = *offset;
120260684Skaiw
121260684Skaiw	entry = _dwarf_read_uleb128(ds->ds_data, offset);
122260684Skaiw	if (entry == 0) {
123260684Skaiw		/* Last entry. */
124260684Skaiw		ret = _dwarf_abbrev_add(cu, entry, 0, 0, aboff, abp,
125260684Skaiw		    error);
126260684Skaiw		if (ret == DW_DLE_NONE) {
127260684Skaiw			(*abp)->ab_length = 1;
128260684Skaiw			return (ret);
129260684Skaiw		} else
130260684Skaiw			return (ret);
131260684Skaiw	}
132260684Skaiw	tag = _dwarf_read_uleb128(ds->ds_data, offset);
133260684Skaiw	children = dbg->read(ds->ds_data, offset, 1);
134260684Skaiw	if ((ret = _dwarf_abbrev_add(cu, entry, tag, children, aboff,
135260684Skaiw	    abp, error)) != DW_DLE_NONE)
136260684Skaiw		return (ret);
137260684Skaiw
138260684Skaiw	/* Parse attribute definitions. */
139260684Skaiw	do {
140260684Skaiw		adoff = *offset;
141260684Skaiw		attr = _dwarf_read_uleb128(ds->ds_data, offset);
142260684Skaiw		form = _dwarf_read_uleb128(ds->ds_data, offset);
143260684Skaiw		if (attr != 0)
144260684Skaiw			if ((ret = _dwarf_attrdef_add(dbg, *abp, attr,
145260684Skaiw			    form, adoff, NULL, error)) != DW_DLE_NONE)
146260684Skaiw				return (ret);
147260684Skaiw	} while (attr != 0);
148260684Skaiw
149260684Skaiw	(*abp)->ab_length = *offset - aboff;
150260684Skaiw
151260684Skaiw	return (ret);
152260684Skaiw}
153260684Skaiw
154260684Skaiwint
155260684Skaiw_dwarf_abbrev_find(Dwarf_CU cu, uint64_t entry, Dwarf_Abbrev *abp,
156260684Skaiw    Dwarf_Error *error)
157260684Skaiw{
158260684Skaiw	Dwarf_Abbrev ab;
159260684Skaiw	Dwarf_Section *ds;
160260684Skaiw	Dwarf_Unsigned offset;
161260684Skaiw	int ret;
162260684Skaiw
163260684Skaiw	if (entry == 0)
164260684Skaiw		return (DW_DLE_NO_ENTRY);
165260684Skaiw
166260684Skaiw	/* Check if the desired abbrev entry is already in the hash table. */
167260684Skaiw	HASH_FIND(ab_hh, cu->cu_abbrev_hash, &entry, sizeof(entry), ab);
168260684Skaiw	if (ab != NULL) {
169260684Skaiw		*abp = ab;
170260684Skaiw		return (DW_DLE_NONE);
171260684Skaiw	}
172260684Skaiw
173260684Skaiw	if (cu->cu_abbrev_loaded) {
174260684Skaiw		return (DW_DLE_NO_ENTRY);
175260684Skaiw	}
176260684Skaiw
177260684Skaiw	/* Load and search the abbrev table. */
178260684Skaiw	ds = _dwarf_find_section(cu->cu_dbg, ".debug_abbrev");
179276398Semaste	if (ds == NULL)
180276398Semaste		return (DW_DLE_NO_ENTRY);
181276398Semaste
182260684Skaiw	offset = cu->cu_abbrev_offset_cur;
183260684Skaiw	while (offset < ds->ds_size) {
184260684Skaiw		ret = _dwarf_abbrev_parse(cu->cu_dbg, cu, &offset, &ab, error);
185260684Skaiw		if (ret != DW_DLE_NONE)
186260684Skaiw			return (ret);
187260684Skaiw		if (ab->ab_entry == entry) {
188260684Skaiw			cu->cu_abbrev_offset_cur = offset;
189260684Skaiw			*abp = ab;
190260684Skaiw			return (DW_DLE_NONE);
191260684Skaiw		}
192260684Skaiw		if (ab->ab_entry == 0) {
193260684Skaiw			cu->cu_abbrev_offset_cur = offset;
194260684Skaiw			cu->cu_abbrev_loaded = 1;
195260684Skaiw			break;
196260684Skaiw		}
197260684Skaiw	}
198260684Skaiw
199260684Skaiw	return (DW_DLE_NO_ENTRY);
200260684Skaiw}
201260684Skaiw
202260684Skaiwvoid
203260684Skaiw_dwarf_abbrev_cleanup(Dwarf_CU cu)
204260684Skaiw{
205260684Skaiw	Dwarf_Abbrev ab, tab;
206260684Skaiw	Dwarf_AttrDef ad, tad;
207260684Skaiw
208260684Skaiw	assert(cu != NULL);
209260684Skaiw
210260684Skaiw	HASH_ITER(ab_hh, cu->cu_abbrev_hash, ab, tab) {
211260684Skaiw		HASH_DELETE(ab_hh, cu->cu_abbrev_hash, ab);
212260684Skaiw		STAILQ_FOREACH_SAFE(ad, &ab->ab_attrdef, ad_next, tad) {
213260684Skaiw			STAILQ_REMOVE(&ab->ab_attrdef, ad, _Dwarf_AttrDef,
214260684Skaiw			    ad_next);
215260684Skaiw			free(ad);
216260684Skaiw		}
217260684Skaiw		free(ab);
218260684Skaiw	}
219260684Skaiw}
220260684Skaiw
221260684Skaiwint
222260684Skaiw_dwarf_abbrev_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
223260684Skaiw{
224260684Skaiw	Dwarf_CU cu;
225260684Skaiw	Dwarf_Abbrev ab;
226260684Skaiw	Dwarf_AttrDef ad;
227260684Skaiw	Dwarf_P_Section ds;
228260684Skaiw	int ret;
229260684Skaiw
230260684Skaiw	cu = STAILQ_FIRST(&dbg->dbg_cu);
231260684Skaiw	if (cu == NULL)
232260684Skaiw		return (DW_DLE_NONE);
233260684Skaiw
234260684Skaiw	/* Create .debug_abbrev section. */
235260684Skaiw	if ((ret = _dwarf_section_init(dbg, &ds, ".debug_abbrev", 0, error)) !=
236260684Skaiw	    DW_DLE_NONE)
237260684Skaiw		return (ret);
238260684Skaiw
239260684Skaiw	for (ab = cu->cu_abbrev_hash; ab != NULL; ab = ab->ab_hh.next) {
240260684Skaiw		RCHECK(WRITE_ULEB128(ab->ab_entry));
241260684Skaiw		RCHECK(WRITE_ULEB128(ab->ab_tag));
242260684Skaiw		RCHECK(WRITE_VALUE(ab->ab_children, 1));
243260684Skaiw		STAILQ_FOREACH(ad, &ab->ab_attrdef, ad_next) {
244260684Skaiw			RCHECK(WRITE_ULEB128(ad->ad_attrib));
245260684Skaiw			RCHECK(WRITE_ULEB128(ad->ad_form));
246260684Skaiw		}
247260684Skaiw		/* Signal end of attribute spec list. */
248260684Skaiw		RCHECK(WRITE_ULEB128(0));
249260684Skaiw		RCHECK(WRITE_ULEB128(0));
250260684Skaiw	}
251260684Skaiw	/* End of abbreviation for this CU. */
252260684Skaiw	RCHECK(WRITE_ULEB128(0));
253260684Skaiw
254260684Skaiw	/* Notify the creation of .debug_abbrev ELF section. */
255260684Skaiw	RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
256260684Skaiw
257260684Skaiw	return (DW_DLE_NONE);
258260684Skaiw
259260684Skaiwgen_fail:
260260684Skaiw
261260684Skaiw	_dwarf_section_free(dbg, &ds);
262260684Skaiw
263260684Skaiw	return (ret);
264260684Skaiw}
265