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