1 /*	$NetBSD: libdwarf_nametbl.c,v 1.2 2014/03/09 16:58:04 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009,2010 Kai Wang
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include "_libdwarf.h"
30 
31 __RCSID("$NetBSD: libdwarf_nametbl.c,v 1.2 2014/03/09 16:58:04 christos Exp $");
32 ELFTC_VCSID("Id: libdwarf_nametbl.c 2070 2011-10-27 03:05:32Z jkoshy ");
33 
34 void
_dwarf_nametbl_cleanup(Dwarf_NameSec * nsp)35 _dwarf_nametbl_cleanup(Dwarf_NameSec *nsp)
36 {
37 	Dwarf_NameSec ns;
38 	Dwarf_NameTbl nt, tnt;
39 	Dwarf_NamePair np, tnp;
40 
41 	assert(nsp != NULL);
42 	if ((ns = *nsp) == NULL)
43 		return;
44 
45 	STAILQ_FOREACH_SAFE(nt, &ns->ns_ntlist, nt_next, tnt) {
46 		STAILQ_FOREACH_SAFE(np, &nt->nt_nplist, np_next, tnp) {
47 			STAILQ_REMOVE(&nt->nt_nplist, np, _Dwarf_NamePair,
48 			    np_next);
49 			free(np);
50 		}
51 		STAILQ_REMOVE(&ns->ns_ntlist, nt, _Dwarf_NameTbl, nt_next);
52 		free(nt);
53 	}
54 	if (ns->ns_array)
55 		free(ns->ns_array);
56 	free(ns);
57 	*nsp = NULL;
58 }
59 
60 int
_dwarf_nametbl_init(Dwarf_Debug dbg,Dwarf_NameSec * namesec,Dwarf_Section * ds,Dwarf_Error * error)61 _dwarf_nametbl_init(Dwarf_Debug dbg, Dwarf_NameSec *namesec, Dwarf_Section *ds,
62     Dwarf_Error *error)
63 {
64 	Dwarf_CU cu;
65 	Dwarf_NameSec ns;
66 	Dwarf_NameTbl nt;
67 	Dwarf_NamePair np;
68 	uint64_t offset, dwarf_size, length, cuoff;
69 	char *p;
70 	int i, ret;
71 
72 	assert(*namesec == NULL);
73 
74 	if ((ns = malloc(sizeof(struct _Dwarf_NameSec))) == NULL) {
75 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
76 		return (DW_DLE_MEMORY);
77 	}
78 	STAILQ_INIT(&ns->ns_ntlist);
79 	ns->ns_array = NULL;
80 	ns->ns_len = 0;
81 
82 	offset = 0;
83 	while (offset < ds->ds_size) {
84 
85 		/* Allocate a new name table. */
86 		if ((nt = malloc(sizeof(struct _Dwarf_NameTbl))) == NULL) {
87 			ret = DW_DLE_MEMORY;
88 			DWARF_SET_ERROR(dbg, error, ret);
89 			goto fail_cleanup;
90 		}
91 		STAILQ_INIT(&nt->nt_nplist);
92 		STAILQ_INSERT_TAIL(&ns->ns_ntlist, nt, nt_next);
93 
94 		/* Read in the table header. */
95 		length = dbg->read(ds->ds_data, &offset, 4);
96 		if (length == 0xffffffff) {
97 			dwarf_size = 8;
98 			length = dbg->read(ds->ds_data, &offset, 8);
99 		} else
100 			dwarf_size = 4;
101 
102 		nt->nt_length = length;
103 		/* FIXME: verify version */
104 		nt->nt_version = dbg->read(ds->ds_data, &offset, 2);
105 		nt->nt_cu_offset = dbg->read(ds->ds_data, &offset, dwarf_size);
106 		nt->nt_cu_length = dbg->read(ds->ds_data, &offset, dwarf_size);
107 
108 		if (!dbg->dbg_info_loaded) {
109 			ret = _dwarf_info_load(dbg, 1, error);
110 			if (ret != DW_DLE_NONE)
111 				goto fail_cleanup;
112 		}
113 
114 		/* Find the referenced CU. */
115 		STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
116 			if (cu->cu_offset == nt->nt_cu_offset)
117 				break;
118 		}
119 		nt->nt_cu = cu;	/* FIXME: Check if NULL here */
120 
121 		/* Add name pairs. */
122 		while (offset < ds->ds_size) {
123 			cuoff = dbg->read(ds->ds_data, &offset, dwarf_size);
124 			if (cuoff == 0)
125 				break;
126 			if ((np = malloc(sizeof(struct _Dwarf_NamePair))) ==
127 			    NULL) {
128 				ret = DW_DLE_MEMORY;
129 				DWARF_SET_ERROR(dbg, error, ret);
130 				goto fail_cleanup;
131 			}
132 			np->np_nt = nt;
133 			np->np_offset = cuoff;
134 			p = (char *) ds->ds_data;
135 			np->np_name = &p[offset];
136 			while (p[offset++] != '\0')
137 				;
138 			STAILQ_INSERT_TAIL(&nt->nt_nplist, np, np_next);
139 			ns->ns_len++;
140 		}
141 	}
142 
143 	/* Build array of name pairs from all tables. */
144 	if (ns->ns_len > 0) {
145 		if ((ns->ns_array = malloc(sizeof(Dwarf_NamePair) *
146 		    ns->ns_len)) == NULL) {
147 			ret = DW_DLE_MEMORY;
148 			DWARF_SET_ERROR(dbg, error, ret);
149 			goto fail_cleanup;
150 		}
151 
152 		i = 0;
153 		STAILQ_FOREACH(nt, &ns->ns_ntlist, nt_next) {
154 			STAILQ_FOREACH(np, &nt->nt_nplist, np_next)
155 				ns->ns_array[i++] = np;
156 		}
157 		assert((Dwarf_Unsigned)i == ns->ns_len);
158 	}
159 
160 	*namesec = ns;
161 
162 	return (DW_DLE_NONE);
163 
164 fail_cleanup:
165 
166 	_dwarf_nametbl_cleanup(&ns);
167 
168 	return (ret);
169 }
170 
171 int
_dwarf_nametbl_gen(Dwarf_P_Debug dbg,const char * name,Dwarf_NameTbl nt,Dwarf_Error * error)172 _dwarf_nametbl_gen(Dwarf_P_Debug dbg, const char *name, Dwarf_NameTbl nt,
173     Dwarf_Error *error)
174 {
175 	Dwarf_P_Section ds;
176 	Dwarf_Rel_Section drs;
177 	Dwarf_NamePair np;
178 	uint64_t offset;
179 	int ret;
180 
181 	assert(dbg != NULL && name != NULL);
182 	if (nt == NULL || STAILQ_EMPTY(&nt->nt_nplist))
183 		return (DW_DLE_NONE);
184 
185 	nt->nt_length = 0;
186 	nt->nt_version = 2;
187 	nt->nt_cu = STAILQ_FIRST(&dbg->dbg_cu);
188 	assert(nt->nt_cu != NULL);
189 	nt->nt_cu_offset = nt->nt_cu->cu_offset;
190 	nt->nt_cu_length = nt->nt_cu->cu_length;
191 
192 	/* Create name lookup section. */
193 	if ((ret = _dwarf_section_init(dbg, &ds, name, 0, error)) !=
194 	    DW_DLE_NONE)
195 		goto gen_fail0;
196 
197 	/* Create relocation section for the name lookup section. */
198 	RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error));
199 
200 	/* Write table header. */
201 	RCHECK(WRITE_VALUE(nt->nt_length, 4));
202 	RCHECK(WRITE_VALUE(nt->nt_version, 2));
203 	RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4,
204 	    ds->ds_size, 0, nt->nt_cu_offset, ".debug_info", error));
205 	RCHECK(WRITE_VALUE(nt->nt_cu_length, 4));
206 
207 	/* Write tuples. */
208 	STAILQ_FOREACH(np, &nt->nt_nplist, np_next) {
209 		assert(np->np_die != NULL);
210 		np->np_offset = np->np_die->die_offset;
211 		RCHECK(WRITE_VALUE(np->np_offset, 4));
212 		RCHECK(WRITE_STRING(np->np_name));
213 	}
214 	RCHECK(WRITE_VALUE(0, 4));
215 
216 	/* Fill in the length field. */
217 	nt->nt_length = ds->ds_size - 4;
218 	offset = 0;
219 	dbg->write(ds->ds_data, &offset, nt->nt_length, 4);
220 
221 	/* Inform application the creation of name lookup ELF section. */
222 	RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
223 
224 	/* Finalize relocation section for the name lookup section. */
225 	RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
226 
227 	return (DW_DLE_NONE);
228 
229 gen_fail:
230 	_dwarf_reloc_section_free(dbg, &drs);
231 
232 gen_fail0:
233 	_dwarf_section_free(dbg, &ds);
234 
235 	return (ret);
236 }
237 
238 void
_dwarf_nametbl_pro_cleanup(Dwarf_NameTbl * ntp)239 _dwarf_nametbl_pro_cleanup(Dwarf_NameTbl *ntp)
240 {
241 	Dwarf_NameTbl nt;
242 	Dwarf_NamePair np, tnp;
243 
244 	assert(ntp != NULL);
245 	if ((nt = *ntp) == NULL)
246 		return;
247 
248 	STAILQ_FOREACH_SAFE(np, &nt->nt_nplist, np_next, tnp) {
249 		STAILQ_REMOVE(&nt->nt_nplist, np, _Dwarf_NamePair, np_next);
250 		if (np->np_name)
251 			free(np->np_name);
252 		free(np);
253 	}
254 	free(nt);
255 	*ntp = NULL;
256 }
257