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