1 /*	$NetBSD: libdwarf_attr.c,v 1.4 2022/05/01 17:20:47 jkoshy 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.4 2022/05/01 17:20:47 jkoshy Exp $");
33 ELFTC_VCSID("Id: libdwarf_attr.c 3064 2014-06-06 19:35:55Z 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_offset = *offsetp;
113 	atref.at_attrib = ad->ad_attrib;
114 	atref.at_form = indirect ? form : ad->ad_form;
115 	atref.at_indirect = indirect;
116 	atref.at_ld = NULL;
117 
118 	switch (form) {
119 	case DW_FORM_addr:
120 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
121 		    cu->cu_pointer_size);
122 		break;
123 	case DW_FORM_block:
124 	case DW_FORM_exprloc:
125 		atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
126 		atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
127 		    atref.u[0].u64);
128 		break;
129 	case DW_FORM_block1:
130 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
131 		atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
132 		    atref.u[0].u64);
133 		break;
134 	case DW_FORM_block2:
135 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2);
136 		atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
137 		    atref.u[0].u64);
138 		break;
139 	case DW_FORM_block4:
140 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4);
141 		atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
142 		    atref.u[0].u64);
143 		break;
144 	case DW_FORM_data1:
145 	case DW_FORM_flag:
146 	case DW_FORM_ref1:
147 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
148 		break;
149 	case DW_FORM_data2:
150 	case DW_FORM_ref2:
151 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2);
152 		break;
153 	case DW_FORM_data4:
154 	case DW_FORM_ref4:
155 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4);
156 		break;
157 	case DW_FORM_data8:
158 	case DW_FORM_ref8:
159 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 8);
160 		break;
161 	case DW_FORM_indirect:
162 		form = _dwarf_read_uleb128(ds->ds_data, offsetp);
163 		return (_dwarf_attr_init(dbg, ds, offsetp, dwarf_size, cu, die,
164 		    ad, form, 1, error));
165 	case DW_FORM_ref_addr:
166 		if (cu->cu_version == 2)
167 			atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
168 			    cu->cu_pointer_size);
169 		else
170 			atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
171 			    dwarf_size);
172 		break;
173 	case DW_FORM_ref_udata:
174 	case DW_FORM_udata:
175 		atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
176 		break;
177 	case DW_FORM_sdata:
178 		atref.u[0].s64 = _dwarf_read_sleb128(ds->ds_data, offsetp);
179 		break;
180 	case DW_FORM_sec_offset:
181 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
182 		break;
183 	case DW_FORM_string:
184 		atref.u[0].s = _dwarf_read_string(ds->ds_data, ds->ds_size,
185 		    offsetp);
186 		break;
187 	case DW_FORM_strp:
188 		atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
189 		str = _dwarf_find_section(dbg, ".debug_str");
190 		assert(str != NULL);
191 		atref.u[1].s = (char *) str->ds_data + atref.u[0].u64;
192 		break;
193 	case DW_FORM_ref_sig8:
194 		atref.u[0].u64 = 8;
195 		atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
196 		    atref.u[0].u64);
197 		break;
198 	case DW_FORM_flag_present:
199 		/* This form has no value encoded in the DIE. */
200 		atref.u[0].u64 = 1;
201 		break;
202 	default:
203 		DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
204 		ret = DW_DLE_ATTR_FORM_BAD;
205 		break;
206 	}
207 
208 	if (ret == DW_DLE_NONE) {
209 		if (form == DW_FORM_block || form == DW_FORM_block1 ||
210 		    form == DW_FORM_block2 || form == DW_FORM_block4) {
211 			atref.at_block.bl_len = atref.u[0].u64;
212 			atref.at_block.bl_data = atref.u[1].u8p;
213 		}
214 		ret = _dwarf_attr_add(die, &atref, NULL, error);
215 	}
216 
217 	return (ret);
218 }
219 
220 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)221 _dwarf_attr_write(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs,
222     Dwarf_CU cu, Dwarf_Attribute at, int pass2, Dwarf_Error *error)
223 {
224 	struct _Dwarf_P_Expr_Entry *ee;
225 	uint64_t value, offset, bs;
226 	int ret;
227 
228 	assert(dbg != NULL && ds != NULL && cu != NULL && at != NULL);
229 
230 	/* Fill in reference to other DIE in the second pass. */
231 	if (pass2) {
232 		if (at->at_form != DW_FORM_ref4 && at->at_form != DW_FORM_ref8)
233 			return (DW_DLE_NONE);
234 		if (at->at_refdie == NULL || at->at_offset == 0)
235 			return (DW_DLE_NONE);
236 		offset = at->at_offset;
237 		dbg->write(ds->ds_data, &offset, at->at_refdie->die_offset,
238 		    at->at_form == DW_FORM_ref4 ? 4 : 8);
239 		return (DW_DLE_NONE);
240 	}
241 
242 	switch (at->at_form) {
243 	case DW_FORM_addr:
244 		if (at->at_relsym)
245 			ret = _dwarf_reloc_entry_add(dbg, drs, ds,
246 			    dwarf_drt_data_reloc, cu->cu_pointer_size,
247 			    ds->ds_size, at->at_relsym, at->u[0].u64, NULL,
248 			    error);
249 		else
250 			ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size);
251 		break;
252 	case DW_FORM_block:
253 	case DW_FORM_block1:
254 	case DW_FORM_block2:
255 	case DW_FORM_block4:
256 		/* Write block size. */
257 		if (at->at_form == DW_FORM_block) {
258 			ret = _dwarf_write_uleb128_alloc(&ds->ds_data,
259 			    &ds->ds_cap, &ds->ds_size, at->u[0].u64, error);
260 			if (ret != DW_DLE_NONE)
261 				break;
262 		} else {
263 			if (at->at_form == DW_FORM_block1)
264 				bs = 1;
265 			else if (at->at_form == DW_FORM_block2)
266 				bs = 2;
267 			else
268 				bs = 4;
269 			ret = WRITE_VALUE(at->u[0].u64, bs);
270 			if (ret != DW_DLE_NONE)
271 				break;
272 		}
273 
274 		/* Keep block data offset for later use. */
275 		offset = ds->ds_size;
276 
277 		/* Write block data. */
278 		ret = WRITE_BLOCK(at->u[1].u8p, at->u[0].u64);
279 		if (ret != DW_DLE_NONE)
280 			break;
281 		if (at->at_expr == NULL)
282 			break;
283 
284 		/* Generate relocation entry for DW_OP_addr expressions. */
285 		STAILQ_FOREACH(ee, &at->at_expr->pe_eelist, ee_next) {
286 			if (ee->ee_loc.lr_atom != DW_OP_addr || ee->ee_sym == 0)
287 				continue;
288 			ret = _dwarf_reloc_entry_add(dbg, drs, ds,
289 			    dwarf_drt_data_reloc, dbg->dbg_pointer_size,
290 			    offset + ee->ee_loc.lr_offset + 1, ee->ee_sym,
291 			    ee->ee_loc.lr_number, NULL, error);
292 			if (ret != DW_DLE_NONE)
293 				break;
294 		}
295 		break;
296 	case DW_FORM_data1:
297 	case DW_FORM_flag:
298 	case DW_FORM_ref1:
299 		ret = WRITE_VALUE(at->u[0].u64, 1);
300 		break;
301 	case DW_FORM_data2:
302 	case DW_FORM_ref2:
303 		ret = WRITE_VALUE(at->u[0].u64, 2);
304 		break;
305 	case DW_FORM_data4:
306 		if (at->at_relsym || at->at_relsec != NULL)
307 			ret = _dwarf_reloc_entry_add(dbg, drs, ds,
308 			    dwarf_drt_data_reloc, 4, ds->ds_size, at->at_relsym,
309 			    at->u[0].u64, at->at_relsec, error);
310 		else
311 			ret = WRITE_VALUE(at->u[0].u64, 4);
312 		break;
313 	case DW_FORM_data8:
314 		if (at->at_relsym || at->at_relsec != NULL)
315 			ret = _dwarf_reloc_entry_add(dbg, drs, ds,
316 			    dwarf_drt_data_reloc, 8, ds->ds_size, at->at_relsym,
317 			    at->u[0].u64, at->at_relsec, error);
318 		else
319 			ret = WRITE_VALUE(at->u[0].u64, 8);
320 		break;
321 	case DW_FORM_ref4:
322 	case DW_FORM_ref8:
323 		/*
324 		 * The value of ref4 and ref8 could be a reference to another
325 		 * DIE within the CU. And if we don't know the ref DIE's
326 		 * offset at the moement, then we remember at_offset and fill
327 		 * it in the second pass.
328 		 */
329 		if (at->at_refdie) {
330 			value = at->at_refdie->die_offset;
331 			if (value == 0) {
332 				cu->cu_pass2 = 1;
333 				at->at_offset = ds->ds_size;
334 			}
335 		} else
336 			value = at->u[0].u64;
337 		ret = WRITE_VALUE(value, at->at_form == DW_FORM_ref4 ? 4 : 8);
338 		break;
339 	case DW_FORM_indirect:
340 		/* TODO. */
341 		DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
342 		ret = DW_DLE_ATTR_FORM_BAD;
343 		break;
344 	case DW_FORM_ref_addr:
345 		/* DWARF2 format. */
346 		if (at->at_relsym)
347 			ret = _dwarf_reloc_entry_add(dbg, drs, ds,
348 			    dwarf_drt_data_reloc, cu->cu_pointer_size,
349 			    ds->ds_size, at->at_relsym, at->u[0].u64, NULL,
350 			    error);
351 		else
352 			ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size);
353 		break;
354 	case DW_FORM_ref_udata:
355 	case DW_FORM_udata:
356 		ret = WRITE_ULEB128(at->u[0].u64);
357 		break;
358 	case DW_FORM_sdata:
359 		ret = WRITE_SLEB128(at->u[0].s64);
360 		break;
361 	case DW_FORM_string:
362 		assert(at->u[0].s != NULL);
363 		ret = WRITE_STRING(at->u[0].s);
364 		break;
365 	case DW_FORM_strp:
366 		ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc,
367 		    4, ds->ds_size, 0, at->u[0].u64, ".debug_str", error);
368 		break;
369 	default:
370 		DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
371 		ret = DW_DLE_ATTR_FORM_BAD;
372 		break;
373 	}
374 
375 	return (ret);
376 }
377 
378 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)379 _dwarf_add_AT_dataref(Dwarf_P_Debug dbg, Dwarf_P_Die die, Dwarf_Half attr,
380     Dwarf_Unsigned pc_value, Dwarf_Unsigned sym_index, const char *secname,
381     Dwarf_P_Attribute *atp, Dwarf_Error *error)
382 {
383 	Dwarf_Attribute at;
384 	int ret;
385 
386 	assert(dbg != NULL && die != NULL);
387 
388 	if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
389 		return (ret);
390 
391 	at->at_die = die;
392 	at->at_attrib = attr;
393 	if (dbg->dbg_pointer_size == 4)
394 		at->at_form = DW_FORM_data4;
395 	else
396 		at->at_form = DW_FORM_data8;
397 	at->at_relsym = sym_index;
398 	at->at_relsec = secname;
399 	at->u[0].u64 = pc_value;
400 
401 	STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
402 
403 	if (atp)
404 		*atp = at;
405 
406 	return (DW_DLE_NONE);
407 }
408 
409 int
_dwarf_add_string_attr(Dwarf_P_Die die,Dwarf_P_Attribute * atp,Dwarf_Half attr,char * string,Dwarf_Error * error)410 _dwarf_add_string_attr(Dwarf_P_Die die, Dwarf_P_Attribute *atp, Dwarf_Half attr,
411     char *string, Dwarf_Error *error)
412 {
413 	Dwarf_Attribute at;
414 	Dwarf_Debug dbg;
415 	int ret;
416 
417 	dbg = die != NULL ? die->die_dbg : NULL;
418 
419 	assert(atp != NULL);
420 
421 	if (die == NULL || string == NULL) {
422 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
423 		return (DW_DLE_ARGUMENT);
424 	}
425 
426 	if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
427 		return (ret);
428 
429 	at->at_die = die;
430 	at->at_attrib = attr;
431 	at->at_form = DW_FORM_strp;
432 	if ((ret = _dwarf_strtab_add(dbg, string, &at->u[0].u64,
433 	    error)) != DW_DLE_NONE) {
434 		free(at);
435 		return (ret);
436 	}
437 	at->u[1].s = _dwarf_strtab_get_table(dbg) + at->u[0].u64;
438 
439 	*atp = at;
440 
441 	STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
442 
443 	return (DW_DLE_NONE);
444 }
445 
446 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)447 _dwarf_attr_gen(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs,
448     Dwarf_CU cu, Dwarf_Die die, int pass2, Dwarf_Error *error)
449 {
450 	Dwarf_Attribute at;
451 	int ret;
452 
453 	assert(dbg != NULL && ds != NULL && cu != NULL && die != NULL);
454 
455 	STAILQ_FOREACH(at, &die->die_attr, at_next) {
456 		ret = _dwarf_attr_write(dbg, ds, drs, cu, at, pass2, error);
457 		if (ret != DW_DLE_NONE)
458 			return (ret);
459 	}
460 
461 	return (DW_DLE_NONE);
462 }
463