1 /* $NetBSD: libdwarf_attr.c,v 1.5 2024/03/03 17:37:32 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2007 John Birrell (jb@freebsd.org)
5 * Copyright (c) 2009-2011,2023 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.5 2024/03/03 17:37:32 christos Exp $");
33 ELFTC_VCSID("Id: libdwarf_attr.c 4019 2023-10-22 03:06:17Z 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 int ret;
107
108 ret = DW_DLE_NONE;
109 memset(&atref, 0, sizeof(atref));
110 atref.at_die = die;
111 atref.at_offset = *offsetp;
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 case DW_FORM_ref_sup4:
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 case DW_FORM_ref_sup8:
160 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 8);
161 break;
162 case DW_FORM_indirect:
163 form = _dwarf_read_uleb128(ds->ds_data, offsetp);
164 return (_dwarf_attr_init(dbg, ds, offsetp, dwarf_size, cu, die,
165 ad, form, 1, error));
166 case DW_FORM_ref_addr:
167 if (cu->cu_version == 2)
168 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
169 cu->cu_pointer_size);
170 else
171 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
172 dwarf_size);
173 break;
174 case DW_FORM_ref_udata:
175 case DW_FORM_udata:
176 case DW_FORM_loclistx:
177 case DW_FORM_rnglistx:
178 atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
179 break;
180 case DW_FORM_sdata:
181 atref.u[0].s64 = _dwarf_read_sleb128(ds->ds_data, offsetp);
182 break;
183 case DW_FORM_sec_offset:
184 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
185 break;
186 case DW_FORM_string:
187 atref.u[0].s = _dwarf_read_string(ds->ds_data, ds->ds_size,
188 offsetp);
189 break;
190 case DW_FORM_strp:
191 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
192 atref.u[1].s = _dwarf_strtab_get_table(dbg) + atref.u[0].u64;
193 break;
194 case DW_FORM_ref_sig8:
195 atref.u[0].u64 = 8;
196 atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
197 atref.u[0].u64);
198 break;
199 case DW_FORM_flag_present:
200 /* This form has no value encoded in the DIE. */
201 atref.u[0].u64 = 1;
202 break;
203 case DW_FORM_strx:
204 atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
205 /* TODO: .debug_str_offsets */
206 break;
207 case DW_FORM_addrx:
208 atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
209 /* TODO: .debug_addr */
210 break;
211 case DW_FORM_strp_sup:
212 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
213 /* TODO: supplementary object file. */
214 break;
215 case DW_FORM_data16:
216 atref.u[0].u64 = 16;
217 atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
218 atref.u[0].u64);
219 break;
220 case DW_FORM_line_strp:
221 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
222 atref.u[1].s = _dwarf_strtab_get_line_table(dbg) +
223 atref.u[0].u64;
224 break;
225 case DW_FORM_implicit_const:
226 /* DWARF5 7.5.3 Implicit constant stored in attrdef.
227 This form has no value encoded in the DIE. */
228 atref.u[0].s64 = ad->ad_const;
229 break;
230 case DW_FORM_strx1:
231 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
232 /* TODO: .debug_str_offsets */
233 break;
234 case DW_FORM_strx2:
235 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
236 /* TODO: .debug_str_offsets */
237 break;
238 case DW_FORM_strx3:
239 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 3);
240 /* TODO: .debug_str_offsets */
241 break;
242 case DW_FORM_strx4:
243 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4);
244 /* TODO: .debug_str_offsets */
245 break;
246 case DW_FORM_addrx1:
247 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
248 /* TODO: .debug_addr */
249 break;
250 case DW_FORM_addrx2:
251 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2);
252 /* TODO: .debug_addr */
253 break;
254 case DW_FORM_addrx3:
255 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 3);
256 /* TODO: .debug_addr */
257 break;
258 case DW_FORM_addrx4:
259 atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4);
260 /* TODO: .debug_addr */
261 break;
262
263 default:
264 DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
265 ret = DW_DLE_ATTR_FORM_BAD;
266 break;
267 }
268
269 if (ret == DW_DLE_NONE) {
270 if (form == DW_FORM_block || form == DW_FORM_block1 ||
271 form == DW_FORM_block2 || form == DW_FORM_block4) {
272 atref.at_block.bl_len = atref.u[0].u64;
273 atref.at_block.bl_data = atref.u[1].u8p;
274 }
275 ret = _dwarf_attr_add(die, &atref, NULL, error);
276 }
277
278 return (ret);
279 }
280
281 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)282 _dwarf_attr_write(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs,
283 Dwarf_CU cu, Dwarf_Attribute at, int pass2, Dwarf_Error *error)
284 {
285 struct _Dwarf_P_Expr_Entry *ee;
286 uint64_t value, offset, bs;
287 int ret;
288
289 assert(dbg != NULL && ds != NULL && cu != NULL && at != NULL);
290
291 /* Fill in reference to other DIE in the second pass. */
292 if (pass2) {
293 if (at->at_form != DW_FORM_ref4 && at->at_form != DW_FORM_ref8)
294 return (DW_DLE_NONE);
295 if (at->at_refdie == NULL || at->at_offset == 0)
296 return (DW_DLE_NONE);
297 offset = at->at_offset;
298 dbg->write(ds->ds_data, &offset, at->at_refdie->die_offset,
299 at->at_form == DW_FORM_ref4 ? 4 : 8);
300 return (DW_DLE_NONE);
301 }
302
303 switch (at->at_form) {
304 case DW_FORM_addr:
305 if (at->at_relsym)
306 ret = _dwarf_reloc_entry_add(dbg, drs, ds,
307 dwarf_drt_data_reloc, cu->cu_pointer_size,
308 ds->ds_size, at->at_relsym, at->u[0].u64, NULL,
309 error);
310 else
311 ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size);
312 break;
313 case DW_FORM_block:
314 case DW_FORM_block1:
315 case DW_FORM_block2:
316 case DW_FORM_block4:
317 /* Write block size. */
318 if (at->at_form == DW_FORM_block) {
319 ret = _dwarf_write_uleb128_alloc(&ds->ds_data,
320 &ds->ds_cap, &ds->ds_size, at->u[0].u64, error);
321 if (ret != DW_DLE_NONE)
322 break;
323 } else {
324 if (at->at_form == DW_FORM_block1)
325 bs = 1;
326 else if (at->at_form == DW_FORM_block2)
327 bs = 2;
328 else
329 bs = 4;
330 ret = WRITE_VALUE(at->u[0].u64, bs);
331 if (ret != DW_DLE_NONE)
332 break;
333 }
334
335 /* Keep block data offset for later use. */
336 offset = ds->ds_size;
337
338 /* Write block data. */
339 ret = WRITE_BLOCK(at->u[1].u8p, at->u[0].u64);
340 if (ret != DW_DLE_NONE)
341 break;
342 if (at->at_expr == NULL)
343 break;
344
345 /* Generate relocation entry for DW_OP_addr expressions. */
346 STAILQ_FOREACH(ee, &at->at_expr->pe_eelist, ee_next) {
347 if (ee->ee_loc.lr_atom != DW_OP_addr || ee->ee_sym == 0)
348 continue;
349 ret = _dwarf_reloc_entry_add(dbg, drs, ds,
350 dwarf_drt_data_reloc, dbg->dbg_pointer_size,
351 offset + ee->ee_loc.lr_offset + 1, ee->ee_sym,
352 ee->ee_loc.lr_number, NULL, error);
353 if (ret != DW_DLE_NONE)
354 break;
355 }
356 break;
357 case DW_FORM_data1:
358 case DW_FORM_flag:
359 case DW_FORM_ref1:
360 ret = WRITE_VALUE(at->u[0].u64, 1);
361 break;
362 case DW_FORM_data2:
363 case DW_FORM_ref2:
364 ret = WRITE_VALUE(at->u[0].u64, 2);
365 break;
366 case DW_FORM_data4:
367 if (at->at_relsym || at->at_relsec != NULL)
368 ret = _dwarf_reloc_entry_add(dbg, drs, ds,
369 dwarf_drt_data_reloc, 4, ds->ds_size, at->at_relsym,
370 at->u[0].u64, at->at_relsec, error);
371 else
372 ret = WRITE_VALUE(at->u[0].u64, 4);
373 break;
374 case DW_FORM_data8:
375 if (at->at_relsym || at->at_relsec != NULL)
376 ret = _dwarf_reloc_entry_add(dbg, drs, ds,
377 dwarf_drt_data_reloc, 8, ds->ds_size, at->at_relsym,
378 at->u[0].u64, at->at_relsec, error);
379 else
380 ret = WRITE_VALUE(at->u[0].u64, 8);
381 break;
382 case DW_FORM_ref4:
383 case DW_FORM_ref8:
384 /*
385 * The value of ref4 and ref8 could be a reference to another
386 * DIE within the CU. And if we don't know the ref DIE's
387 * offset at the moement, then we remember at_offset and fill
388 * it in the second pass.
389 */
390 if (at->at_refdie) {
391 value = at->at_refdie->die_offset;
392 if (value == 0) {
393 cu->cu_pass2 = 1;
394 at->at_offset = ds->ds_size;
395 }
396 } else
397 value = at->u[0].u64;
398 ret = WRITE_VALUE(value, at->at_form == DW_FORM_ref4 ? 4 : 8);
399 break;
400 case DW_FORM_indirect:
401 /* TODO. */
402 DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
403 ret = DW_DLE_ATTR_FORM_BAD;
404 break;
405 case DW_FORM_ref_addr:
406 /* DWARF2 format. */
407 if (at->at_relsym)
408 ret = _dwarf_reloc_entry_add(dbg, drs, ds,
409 dwarf_drt_data_reloc, cu->cu_pointer_size,
410 ds->ds_size, at->at_relsym, at->u[0].u64, NULL,
411 error);
412 else
413 ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size);
414 break;
415 case DW_FORM_ref_udata:
416 case DW_FORM_udata:
417 ret = WRITE_ULEB128(at->u[0].u64);
418 break;
419 case DW_FORM_sdata:
420 ret = WRITE_SLEB128(at->u[0].s64);
421 break;
422 case DW_FORM_string:
423 assert(at->u[0].s != NULL);
424 ret = WRITE_STRING(at->u[0].s);
425 break;
426 case DW_FORM_strp:
427 ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc,
428 4, ds->ds_size, 0, at->u[0].u64, ".debug_str", error);
429 break;
430 default:
431 DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
432 ret = DW_DLE_ATTR_FORM_BAD;
433 break;
434 }
435
436 return (ret);
437 }
438
439 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)440 _dwarf_add_AT_dataref(Dwarf_P_Debug dbg, Dwarf_P_Die die, Dwarf_Half attr,
441 Dwarf_Unsigned pc_value, Dwarf_Unsigned sym_index, const char *secname,
442 Dwarf_P_Attribute *atp, Dwarf_Error *error)
443 {
444 Dwarf_Attribute at;
445 int ret;
446
447 assert(dbg != NULL && die != NULL);
448
449 if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
450 return (ret);
451
452 at->at_die = die;
453 at->at_attrib = attr;
454 if (dbg->dbg_pointer_size == 4)
455 at->at_form = DW_FORM_data4;
456 else
457 at->at_form = DW_FORM_data8;
458 at->at_relsym = sym_index;
459 at->at_relsec = secname;
460 at->u[0].u64 = pc_value;
461
462 STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
463
464 if (atp)
465 *atp = at;
466
467 return (DW_DLE_NONE);
468 }
469
470 int
_dwarf_add_string_attr(Dwarf_P_Die die,Dwarf_P_Attribute * atp,Dwarf_Half attr,char * string,Dwarf_Error * error)471 _dwarf_add_string_attr(Dwarf_P_Die die, Dwarf_P_Attribute *atp, Dwarf_Half attr,
472 char *string, Dwarf_Error *error)
473 {
474 Dwarf_Attribute at;
475 Dwarf_Debug dbg;
476 int ret;
477
478 dbg = die != NULL ? die->die_dbg : NULL;
479
480 assert(atp != NULL);
481
482 if (die == NULL || string == NULL) {
483 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
484 return (DW_DLE_ARGUMENT);
485 }
486
487 if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
488 return (ret);
489
490 at->at_die = die;
491 at->at_attrib = attr;
492 at->at_form = DW_FORM_strp;
493 if ((ret = _dwarf_strtab_add(dbg, string, &at->u[0].u64,
494 error)) != DW_DLE_NONE) {
495 free(at);
496 return (ret);
497 }
498 at->u[1].s = _dwarf_strtab_get_table(dbg) + at->u[0].u64;
499
500 *atp = at;
501
502 STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
503
504 return (DW_DLE_NONE);
505 }
506
507 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)508 _dwarf_attr_gen(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs,
509 Dwarf_CU cu, Dwarf_Die die, int pass2, Dwarf_Error *error)
510 {
511 Dwarf_Attribute at;
512 int ret;
513
514 assert(dbg != NULL && ds != NULL && cu != NULL && die != NULL);
515
516 STAILQ_FOREACH(at, &die->die_attr, at_next) {
517 ret = _dwarf_attr_write(dbg, ds, drs, cu, at, pass2, error);
518 if (ret != DW_DLE_NONE)
519 return (ret);
520 }
521
522 return (DW_DLE_NONE);
523 }
524