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