1 /*	$NetBSD: libdwarf_attr.c,v 1.2 2014/03/09 16:58:04 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2007 John Birrell (jb@freebsd.org)
5  * Copyright (c) 2009-2011 Kai Wang
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include "_libdwarf.h"
31 
32 __RCSID("$NetBSD: libdwarf_attr.c,v 1.2 2014/03/09 16:58:04 christos Exp $");
33 ELFTC_VCSID("Id: libdwarf_attr.c 2966 2013-09-21 14:40:14Z kaiwang27 ");
34 
35 int
_dwarf_attr_alloc(Dwarf_Die die,Dwarf_Attribute * atp,Dwarf_Error * error)36 _dwarf_attr_alloc(Dwarf_Die die, Dwarf_Attribute *atp, Dwarf_Error *error)
37 {
38 	Dwarf_Attribute at;
39 
40 	assert(die != NULL);
41 	assert(atp != NULL);
42 
43 	if ((at = calloc(1, sizeof(struct _Dwarf_Attribute))) == NULL) {
44 		DWARF_SET_ERROR(die->die_dbg, error, DW_DLE_MEMORY);
45 		return (DW_DLE_MEMORY);
46 	}
47 
48 	*atp = at;
49 
50 	return (DW_DLE_NONE);
51 }
52 
53 static int
_dwarf_attr_add(Dwarf_Die die,Dwarf_Attribute atref,Dwarf_Attribute * atp,Dwarf_Error * error)54 _dwarf_attr_add(Dwarf_Die die, Dwarf_Attribute atref, Dwarf_Attribute *atp,
55     Dwarf_Error *error)
56 {
57 	Dwarf_Attribute at;
58 	int ret;
59 
60 	if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
61 		return (ret);
62 
63 	memcpy(at, atref, sizeof(struct _Dwarf_Attribute));
64 
65 	STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
66 
67 	/* Save a pointer to the attribute name if this is one. */
68 	if (at->at_attrib == DW_AT_name) {
69 		switch (at->at_form) {
70 		case DW_FORM_strp:
71 			die->die_name = at->u[1].s;
72 			break;
73 		case DW_FORM_string:
74 			die->die_name = at->u[0].s;
75 			break;
76 		default:
77 			break;
78 		}
79 	}
80 
81 	if (atp != NULL)
82 		*atp = at;
83 
84 	return (DW_DLE_NONE);
85 }
86 
87 Dwarf_Attribute
_dwarf_attr_find(Dwarf_Die die,Dwarf_Half attr)88 _dwarf_attr_find(Dwarf_Die die, Dwarf_Half attr)
89 {
90 	Dwarf_Attribute at;
91 
92 	STAILQ_FOREACH(at, &die->die_attr, at_next) {
93 		if (at->at_attrib == attr)
94 			break;
95 	}
96 
97 	return (at);
98 }
99 
100 int
_dwarf_attr_init(Dwarf_Debug dbg,Dwarf_Section * ds,uint64_t * offsetp,int dwarf_size,Dwarf_CU cu,Dwarf_Die die,Dwarf_AttrDef ad,uint64_t form,int indirect,Dwarf_Error * error)101 _dwarf_attr_init(Dwarf_Debug dbg, Dwarf_Section *ds, uint64_t *offsetp,
102     int dwarf_size, Dwarf_CU cu, Dwarf_Die die, Dwarf_AttrDef ad,
103     uint64_t form, int indirect, Dwarf_Error *error)
104 {
105 	struct _Dwarf_Attribute atref;
106 	Dwarf_Section *str;
107 	int ret;
108 
109 	ret = DW_DLE_NONE;
110 	memset(&atref, 0, sizeof(atref));
111 	atref.at_die = die;
112 	atref.at_attrib = ad->ad_attrib;
113 	atref.at_form = indirect ? form : ad->ad_form;
114 	atref.at_indirect = indirect;
115 	atref.at_ld = NULL;
116 
117 	switch (form) {
118 	case DW_FORM_addr:
119 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
120 		    cu->cu_pointer_size);
121 		break;
122 	case DW_FORM_block:
123 	case DW_FORM_exprloc:
124 		atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
125 		atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
126 		    atref.u[0].u64);
127 		break;
128 	case DW_FORM_block1:
129 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
130 		atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
131 		    atref.u[0].u64);
132 		break;
133 	case DW_FORM_block2:
134 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2);
135 		atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
136 		    atref.u[0].u64);
137 		break;
138 	case DW_FORM_block4:
139 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4);
140 		atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
141 		    atref.u[0].u64);
142 		break;
143 	case DW_FORM_data1:
144 	case DW_FORM_flag:
145 	case DW_FORM_ref1:
146 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
147 		break;
148 	case DW_FORM_data2:
149 	case DW_FORM_ref2:
150 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2);
151 		break;
152 	case DW_FORM_data4:
153 	case DW_FORM_ref4:
154 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4);
155 		break;
156 	case DW_FORM_data8:
157 	case DW_FORM_ref8:
158 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 8);
159 		break;
160 	case DW_FORM_indirect:
161 		form = _dwarf_read_uleb128(ds->ds_data, offsetp);
162 		return (_dwarf_attr_init(dbg, ds, offsetp, dwarf_size, cu, die,
163 		    ad, form, 1, error));
164 	case DW_FORM_ref_addr:
165 		if (cu->cu_version == 2)
166 			atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
167 			    cu->cu_pointer_size);
168 		else if (cu->cu_version == 3)
169 			atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
170 			    dwarf_size);
171 		break;
172 	case DW_FORM_ref_udata:
173 	case DW_FORM_udata:
174 		atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
175 		break;
176 	case DW_FORM_sdata:
177 		atref.u[0].s64 = _dwarf_read_sleb128(ds->ds_data, offsetp);
178 		break;
179 	case DW_FORM_sec_offset:
180 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
181 		break;
182 	case DW_FORM_string:
183 		atref.u[0].s = _dwarf_read_string(ds->ds_data, ds->ds_size,
184 		    offsetp);
185 		break;
186 	case DW_FORM_strp:
187 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
188 		str = _dwarf_find_section(dbg, ".debug_str");
189 		assert(str != NULL);
190 		atref.u[1].s = (char *) str->ds_data + atref.u[0].u64;
191 		break;
192 	case DW_FORM_ref_sig8:
193 		atref.u[0].u64 = 8;
194 		atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
195 		    atref.u[0].u64);
196 		break;
197 	case DW_FORM_flag_present:
198 		/* This form has no value encoded in the DIE. */
199 		atref.u[0].u64 = 1;
200 		break;
201 	default:
202 		DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
203 		ret = DW_DLE_ATTR_FORM_BAD;
204 		break;
205 	}
206 
207 	if (ret == DW_DLE_NONE) {
208 		if (form == DW_FORM_block || form == DW_FORM_block1 ||
209 		    form == DW_FORM_block2 || form == DW_FORM_block4) {
210 			atref.at_block.bl_len = atref.u[0].u64;
211 			atref.at_block.bl_data = atref.u[1].u8p;
212 		}
213 		ret = _dwarf_attr_add(die, &atref, NULL, error);
214 	}
215 
216 	return (ret);
217 }
218 
219 static int
_dwarf_attr_write(Dwarf_P_Debug dbg,Dwarf_P_Section ds,Dwarf_Rel_Section drs,Dwarf_CU cu,Dwarf_Attribute at,int pass2,Dwarf_Error * error)220 _dwarf_attr_write(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs,
221     Dwarf_CU cu, Dwarf_Attribute at, int pass2, Dwarf_Error *error)
222 {
223 	struct _Dwarf_P_Expr_Entry *ee;
224 	uint64_t value, offset, bs;
225 	int ret;
226 
227 	assert(dbg != NULL && ds != NULL && cu != NULL && at != NULL);
228 
229 	/* Fill in reference to other DIE in the second pass. */
230 	if (pass2) {
231 		if (at->at_form != DW_FORM_ref4 && at->at_form != DW_FORM_ref8)
232 			return (DW_DLE_NONE);
233 		if (at->at_refdie == NULL || at->at_offset == 0)
234 			return (DW_DLE_NONE);
235 		offset = at->at_offset;
236 		dbg->write(ds->ds_data, &offset, at->at_refdie->die_offset,
237 		    at->at_form == DW_FORM_ref4 ? 4 : 8);
238 		return (DW_DLE_NONE);
239 	}
240 
241 	switch (at->at_form) {
242 	case DW_FORM_addr:
243 		if (at->at_relsym)
244 			ret = _dwarf_reloc_entry_add(dbg, drs, ds,
245 			    dwarf_drt_data_reloc, cu->cu_pointer_size,
246 			    ds->ds_size, at->at_relsym, at->u[0].u64, NULL,
247 			    error);
248 		else
249 			ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size);
250 		break;
251 	case DW_FORM_block:
252 	case DW_FORM_block1:
253 	case DW_FORM_block2:
254 	case DW_FORM_block4:
255 		/* Write block size. */
256 		if (at->at_form == DW_FORM_block) {
257 			ret = _dwarf_write_uleb128_alloc(&ds->ds_data,
258 			    &ds->ds_cap, &ds->ds_size, at->u[0].u64, error);
259 			if (ret != DW_DLE_NONE)
260 				break;
261 		} else {
262 			if (at->at_form == DW_FORM_block1)
263 				bs = 1;
264 			else if (at->at_form == DW_FORM_block2)
265 				bs = 2;
266 			else
267 				bs = 4;
268 			ret = WRITE_VALUE(at->u[0].u64, bs);
269 			if (ret != DW_DLE_NONE)
270 				break;
271 		}
272 
273 		/* Keep block data offset for later use. */
274 		offset = ds->ds_size;
275 
276 		/* Write block data. */
277 		ret = WRITE_BLOCK(at->u[1].u8p, at->u[0].u64);
278 		if (ret != DW_DLE_NONE)
279 			break;
280 		if (at->at_expr == NULL)
281 			break;
282 
283 		/* Generate relocation entry for DW_OP_addr expressions. */
284 		STAILQ_FOREACH(ee, &at->at_expr->pe_eelist, ee_next) {
285 			if (ee->ee_loc.lr_atom != DW_OP_addr || ee->ee_sym == 0)
286 				continue;
287 			ret = _dwarf_reloc_entry_add(dbg, drs, ds,
288 			    dwarf_drt_data_reloc, dbg->dbg_pointer_size,
289 			    offset + ee->ee_loc.lr_offset + 1, ee->ee_sym,
290 			    ee->ee_loc.lr_number, NULL, error);
291 			if (ret != DW_DLE_NONE)
292 				break;
293 		}
294 		break;
295 	case DW_FORM_data1:
296 	case DW_FORM_flag:
297 	case DW_FORM_ref1:
298 		ret = WRITE_VALUE(at->u[0].u64, 1);
299 		break;
300 	case DW_FORM_data2:
301 	case DW_FORM_ref2:
302 		ret = WRITE_VALUE(at->u[0].u64, 2);
303 		break;
304 	case DW_FORM_data4:
305 		if (at->at_relsym || at->at_relsec != NULL)
306 			ret = _dwarf_reloc_entry_add(dbg, drs, ds,
307 			    dwarf_drt_data_reloc, 4, ds->ds_size, at->at_relsym,
308 			    at->u[0].u64, at->at_relsec, error);
309 		else
310 			ret = WRITE_VALUE(at->u[0].u64, 4);
311 		break;
312 	case DW_FORM_data8:
313 		if (at->at_relsym || at->at_relsec != NULL)
314 			ret = _dwarf_reloc_entry_add(dbg, drs, ds,
315 			    dwarf_drt_data_reloc, 8, ds->ds_size, at->at_relsym,
316 			    at->u[0].u64, at->at_relsec, error);
317 		else
318 			ret = WRITE_VALUE(at->u[0].u64, 8);
319 		break;
320 	case DW_FORM_ref4:
321 	case DW_FORM_ref8:
322 		/*
323 		 * The value of ref4 and ref8 could be a reference to another
324 		 * DIE within the CU. And if we don't know the ref DIE's
325 		 * offset at the moement, then we remember at_offset and fill
326 		 * it in the second pass.
327 		 */
328 		if (at->at_refdie) {
329 			value = at->at_refdie->die_offset;
330 			if (value == 0) {
331 				cu->cu_pass2 = 1;
332 				at->at_offset = ds->ds_size;
333 			}
334 		} else
335 			value = at->u[0].u64;
336 		ret = WRITE_VALUE(value, at->at_form == DW_FORM_ref4 ? 4 : 8);
337 		break;
338 	case DW_FORM_indirect:
339 		/* TODO. */
340 		DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
341 		ret = DW_DLE_ATTR_FORM_BAD;
342 		break;
343 	case DW_FORM_ref_addr:
344 		/* DWARF2 format. */
345 		if (at->at_relsym)
346 			ret = _dwarf_reloc_entry_add(dbg, drs, ds,
347 			    dwarf_drt_data_reloc, cu->cu_pointer_size,
348 			    ds->ds_size, at->at_relsym, at->u[0].u64, NULL,
349 			    error);
350 		else
351 			ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size);
352 		break;
353 	case DW_FORM_ref_udata:
354 	case DW_FORM_udata:
355 		ret = WRITE_ULEB128(at->u[0].u64);
356 		break;
357 	case DW_FORM_sdata:
358 		ret = WRITE_SLEB128(at->u[0].s64);
359 		break;
360 	case DW_FORM_string:
361 		assert(at->u[0].s != NULL);
362 		ret = WRITE_STRING(at->u[0].s);
363 		break;
364 	case DW_FORM_strp:
365 		ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc,
366 		    4, ds->ds_size, 0, at->u[0].u64, ".debug_str", error);
367 		break;
368 	default:
369 		DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
370 		ret = DW_DLE_ATTR_FORM_BAD;
371 		break;
372 	}
373 
374 	return (ret);
375 }
376 
377 int
_dwarf_add_AT_dataref(Dwarf_P_Debug dbg,Dwarf_P_Die die,Dwarf_Half attr,Dwarf_Unsigned pc_value,Dwarf_Unsigned sym_index,const char * secname,Dwarf_P_Attribute * atp,Dwarf_Error * error)378 _dwarf_add_AT_dataref(Dwarf_P_Debug dbg, Dwarf_P_Die die, Dwarf_Half attr,
379     Dwarf_Unsigned pc_value, Dwarf_Unsigned sym_index, const char *secname,
380     Dwarf_P_Attribute *atp, Dwarf_Error *error)
381 {
382 	Dwarf_Attribute at;
383 	int ret;
384 
385 	assert(dbg != NULL && die != NULL);
386 
387 	if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
388 		return (ret);
389 
390 	at->at_die = die;
391 	at->at_attrib = attr;
392 	if (dbg->dbg_pointer_size == 4)
393 		at->at_form = DW_FORM_data4;
394 	else
395 		at->at_form = DW_FORM_data8;
396 	at->at_relsym = sym_index;
397 	at->at_relsec = secname;
398 	at->u[0].u64 = pc_value;
399 
400 	STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
401 
402 	if (atp)
403 		*atp = at;
404 
405 	return (DW_DLE_NONE);
406 }
407 
408 int
_dwarf_add_string_attr(Dwarf_P_Die die,Dwarf_P_Attribute * atp,Dwarf_Half attr,char * string,Dwarf_Error * error)409 _dwarf_add_string_attr(Dwarf_P_Die die, Dwarf_P_Attribute *atp, Dwarf_Half attr,
410     char *string, Dwarf_Error *error)
411 {
412 	Dwarf_Attribute at;
413 	Dwarf_Debug dbg;
414 	int ret;
415 
416 	dbg = die != NULL ? die->die_dbg : NULL;
417 
418 	assert(atp != NULL);
419 
420 	if (die == NULL || string == NULL) {
421 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
422 		return (DW_DLE_ARGUMENT);
423 	}
424 
425 	if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
426 		return (ret);
427 
428 	at->at_die = die;
429 	at->at_attrib = attr;
430 	at->at_form = DW_FORM_strp;
431 	if ((ret = _dwarf_strtab_add(dbg, string, &at->u[0].u64,
432 	    error)) != DW_DLE_NONE) {
433 		free(at);
434 		return (ret);
435 	}
436 	at->u[1].s = _dwarf_strtab_get_table(dbg) + at->u[0].u64;
437 
438 	*atp = at;
439 
440 	STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
441 
442 	return (DW_DLE_NONE);
443 }
444 
445 int
_dwarf_attr_gen(Dwarf_P_Debug dbg,Dwarf_P_Section ds,Dwarf_Rel_Section drs,Dwarf_CU cu,Dwarf_Die die,int pass2,Dwarf_Error * error)446 _dwarf_attr_gen(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs,
447     Dwarf_CU cu, Dwarf_Die die, int pass2, Dwarf_Error *error)
448 {
449 	Dwarf_Attribute at;
450 	int ret;
451 
452 	assert(dbg != NULL && ds != NULL && cu != NULL && die != NULL);
453 
454 	STAILQ_FOREACH(at, &die->die_attr, at_next) {
455 		ret = _dwarf_attr_write(dbg, ds, drs, cu, at, pass2, error);
456 		if (ret != DW_DLE_NONE)
457 			return (ret);
458 	}
459 
460 	return (DW_DLE_NONE);
461 }
462