Home | History | Annotate | Line # | Download | only in libdwarf
      1 /*	$NetBSD: libdwarf_frame.c,v 1.5 2024/03/03 17:37:32 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2009-2011,2014 Kai Wang
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include "_libdwarf.h"
     30 
     31 __RCSID("$NetBSD: libdwarf_frame.c,v 1.5 2024/03/03 17:37:32 christos Exp $");
     32 ELFTC_VCSID("Id: libdwarf_frame.c 3804 2020-02-07 02:13:34Z emaste");
     33 
     34 static int
     35 _dwarf_frame_find_cie(Dwarf_FrameSec fs, Dwarf_Unsigned offset,
     36     Dwarf_Cie *ret_cie)
     37 {
     38 	Dwarf_Cie cie;
     39 
     40 	STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) {
     41 		if (cie->cie_offset == offset)
     42 			break;
     43 	}
     44 
     45 	if (cie == NULL)
     46 		return (DW_DLE_NO_ENTRY);
     47 
     48 	if (ret_cie != NULL)
     49 		*ret_cie = cie;
     50 
     51 	return (DW_DLE_NONE);
     52 }
     53 
     54 static int
     55 _dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg, Dwarf_Cie cie, uint64_t *val,
     56     uint8_t *data, uint64_t *offsetp, uint8_t encode, Dwarf_Addr pc,
     57     Dwarf_Error *error)
     58 {
     59 	uint8_t application;
     60 
     61 	if (encode == DW_EH_PE_omit)
     62 		return (DW_DLE_NONE);
     63 
     64 	application = encode & 0xf0;
     65 	encode &= 0x0f;
     66 
     67 	switch (encode) {
     68 	case DW_EH_PE_absptr:
     69 		*val = dbg->read(data, offsetp, cie->cie_addrsize);
     70 		break;
     71 	case DW_EH_PE_uleb128:
     72 		*val = _dwarf_read_uleb128(data, offsetp);
     73 		break;
     74 	case DW_EH_PE_udata2:
     75 		*val = dbg->read(data, offsetp, 2);
     76 		break;
     77 	case DW_EH_PE_udata4:
     78 		*val = dbg->read(data, offsetp, 4);
     79 		break;
     80 	case DW_EH_PE_udata8:
     81 		*val = dbg->read(data, offsetp, 8);
     82 		break;
     83 	case DW_EH_PE_sleb128:
     84 		*val = _dwarf_read_sleb128(data, offsetp);
     85 		break;
     86 	case DW_EH_PE_sdata2:
     87 		*val = (int16_t) dbg->read(data, offsetp, 2);
     88 		break;
     89 	case DW_EH_PE_sdata4:
     90 		*val = (int32_t) dbg->read(data, offsetp, 4);
     91 		break;
     92 	case DW_EH_PE_sdata8:
     93 		*val = dbg->read(data, offsetp, 8);
     94 		break;
     95 	default:
     96 		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
     97 		return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
     98 	}
     99 
    100 	if (application == DW_EH_PE_pcrel) {
    101 		/*
    102 		 * Value is relative to .eh_frame section virtual addr.
    103 		 */
    104 		switch (encode) {
    105 		case DW_EH_PE_uleb128:
    106 		case DW_EH_PE_udata2:
    107 		case DW_EH_PE_udata4:
    108 		case DW_EH_PE_udata8:
    109 			*val += pc;
    110 			break;
    111 		case DW_EH_PE_sleb128:
    112 		case DW_EH_PE_sdata2:
    113 		case DW_EH_PE_sdata4:
    114 		case DW_EH_PE_sdata8:
    115 			*val = pc + (int64_t) *val;
    116 			break;
    117 		default:
    118 			/* DW_EH_PE_absptr is absolute value. */
    119 			break;
    120 		}
    121 	}
    122 
    123 	/* XXX Applications other than DW_EH_PE_pcrel are not handled. */
    124 
    125 	return (DW_DLE_NONE);
    126 }
    127 
    128 static int
    129 _dwarf_frame_parse_lsb_cie_augment(Dwarf_Debug dbg, Dwarf_Cie cie,
    130     Dwarf_Error *error)
    131 {
    132 	uint8_t *aug_p, *augdata_p;
    133 	uint64_t val, offset;
    134 	uint8_t encode;
    135 	int ret;
    136 
    137 	assert(cie->cie_augment != NULL && *cie->cie_augment == 'z');
    138 
    139 	/*
    140 	 * Here we're only interested in the presence of augment 'R'
    141 	 * and associated CIE augment data, which describes the
    142 	 * encoding scheme of FDE PC begin and range.
    143 	 */
    144 	aug_p = &cie->cie_augment[1];
    145 	augdata_p = cie->cie_augdata;
    146 	while (*aug_p != '\0') {
    147 		switch (*aug_p) {
    148 		case 'S':
    149 			break;
    150 		case 'L':
    151 			/* Skip one augment in augment data. */
    152 			augdata_p++;
    153 			break;
    154 		case 'P':
    155 			/* Skip two augments in augment data. */
    156 			encode = *augdata_p++;
    157 			offset = 0;
    158 			ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
    159 			    augdata_p, &offset, encode, 0, error);
    160 			if (ret != DW_DLE_NONE)
    161 				return (ret);
    162 			augdata_p += offset;
    163 			break;
    164 		case 'R':
    165 			cie->cie_fde_encode = *augdata_p++;
    166 			break;
    167 		default:
    168 			DWARF_SET_ERROR(dbg, error,
    169 			    DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
    170 			return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
    171 		}
    172 		aug_p++;
    173 	}
    174 
    175 	return (DW_DLE_NONE);
    176 }
    177 
    178 static int
    179 _dwarf_frame_add_cie(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds,
    180     Dwarf_Unsigned *off, Dwarf_Cie *ret_cie, Dwarf_Error *error)
    181 {
    182 	Dwarf_Cie cie;
    183 	uint64_t length;
    184 	int dwarf_size, ret;
    185 	char *p;
    186 
    187 	/* Check if we already added this CIE. */
    188 	if (_dwarf_frame_find_cie(fs, *off, &cie) != DW_DLE_NO_ENTRY) {
    189 		*off += cie->cie_length + 4;
    190 		return (DW_DLE_NONE);
    191 	}
    192 
    193 	if ((cie = calloc(1, sizeof(struct _Dwarf_Cie))) == NULL) {
    194 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
    195 		return (DW_DLE_MEMORY);
    196 	}
    197 	STAILQ_INSERT_TAIL(&fs->fs_cielist, cie, cie_next);
    198 
    199 	cie->cie_dbg = dbg;
    200 	cie->cie_index = fs->fs_cielen;
    201 	cie->cie_offset = *off;
    202 
    203 	length = dbg->read(ds->ds_data, off, 4);
    204 	if (length == 0xffffffff) {
    205 		dwarf_size = 8;
    206 		length = dbg->read(ds->ds_data, off, 8);
    207 	} else
    208 		dwarf_size = 4;
    209 
    210 	if (length > ds->ds_size - *off) {
    211 		DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
    212 		return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
    213 	}
    214 
    215 	(void) dbg->read(ds->ds_data, off, dwarf_size); /* Skip CIE id. */
    216 	cie->cie_length = length;
    217 
    218 	cie->cie_version = dbg->read(ds->ds_data, off, 1);
    219 	if (cie->cie_version != 1 && cie->cie_version != 3 &&
    220 	    cie->cie_version != 4) {
    221 		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_VERSION_BAD);
    222 		return (DW_DLE_FRAME_VERSION_BAD);
    223 	}
    224 
    225 	cie->cie_augment = ds->ds_data + *off;
    226 	p = (char *) ds->ds_data;
    227 	while (p[(*off)++] != '\0')
    228 		;
    229 
    230 	/* We only recognize normal .dwarf_frame and GNU .eh_frame sections. */
    231 	if (*cie->cie_augment != 0 && *cie->cie_augment != 'z') {
    232 		*off = cie->cie_offset + ((dwarf_size == 4) ? 4 : 12) +
    233 		    cie->cie_length;
    234 		return (DW_DLE_NONE);
    235 	}
    236 
    237 	/* Optional EH Data field for .eh_frame section. */
    238 	if (strstr((char *)cie->cie_augment, "eh") != NULL)
    239 		cie->cie_ehdata = dbg->read(ds->ds_data, off,
    240 		    dbg->dbg_pointer_size);
    241 
    242 	/* DWARF4 added "address_size" and "segment_size". */
    243 	if (cie->cie_version == 4) {
    244 		cie->cie_addrsize = dbg->read(ds->ds_data, off, 1);
    245 		cie->cie_segmentsize = dbg->read(ds->ds_data, off, 1);
    246 	} else {
    247 		/*
    248 		 * Otherwise (DWARF[23]) we just set CIE addrsize to the
    249 		 * debug context pointer size.
    250 		 */
    251 		cie->cie_addrsize = dbg->dbg_pointer_size;
    252 	}
    253 
    254 	cie->cie_caf = _dwarf_read_uleb128(ds->ds_data, off);
    255 	cie->cie_daf = _dwarf_read_sleb128(ds->ds_data, off);
    256 
    257 	/* Return address register. */
    258 	if (cie->cie_version == 1)
    259 		cie->cie_ra = dbg->read(ds->ds_data, off, 1);
    260 	else
    261 		cie->cie_ra = _dwarf_read_uleb128(ds->ds_data, off);
    262 
    263 	/* Optional CIE augmentation data for .eh_frame section. */
    264 	if (*cie->cie_augment == 'z') {
    265 		cie->cie_auglen = _dwarf_read_uleb128(ds->ds_data, off);
    266 		cie->cie_augdata = ds->ds_data + *off;
    267 		*off += cie->cie_auglen;
    268 		/*
    269 		 * XXX Use DW_EH_PE_absptr for default FDE PC start/range,
    270 		 * in case _dwarf_frame_parse_lsb_cie_augment fails to
    271 		 * find out the real encode.
    272 		 */
    273 		cie->cie_fde_encode = DW_EH_PE_absptr;
    274 		ret = _dwarf_frame_parse_lsb_cie_augment(dbg, cie, error);
    275 		if (ret != DW_DLE_NONE)
    276 			return (ret);
    277 	}
    278 
    279 	/* CIE Initial instructions. */
    280 	cie->cie_initinst = ds->ds_data + *off;
    281 	if (dwarf_size == 4)
    282 		cie->cie_instlen = cie->cie_offset + 4 + length - *off;
    283 	else
    284 		cie->cie_instlen = cie->cie_offset + 12 + length - *off;
    285 
    286 	*off += cie->cie_instlen;
    287 
    288 #ifdef FRAME_DEBUG
    289 	printf("cie:\n");
    290 	printf("\tcie_version=%u cie_offset=%ju cie_length=%ju cie_augment=%s"
    291 	    " cie_instlen=%ju cie->cie_caf=%ju cie->cie_daf=%jd off=%ju\n",
    292 	    cie->cie_version, cie->cie_offset, cie->cie_length,
    293 	    (char *)cie->cie_augment, cie->cie_instlen, cie->cie_caf,
    294 	    cie->cie_daf, *off);
    295 #endif
    296 
    297 	if (ret_cie != NULL)
    298 		*ret_cie = cie;
    299 
    300 	fs->fs_cielen++;
    301 
    302 	return (DW_DLE_NONE);
    303 }
    304 
    305 static int
    306 _dwarf_frame_add_fde(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds,
    307     Dwarf_Unsigned *off, int eh_frame, Dwarf_Error *error)
    308 {
    309 	Dwarf_Cie cie;
    310 	Dwarf_Fde fde;
    311 	Dwarf_Unsigned cieoff;
    312 	uint64_t length, val;
    313 	int dwarf_size, ret;
    314 
    315 	if ((fde = calloc(1, sizeof(struct _Dwarf_Fde))) == NULL) {
    316 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
    317 		return (DW_DLE_MEMORY);
    318 	}
    319 	STAILQ_INSERT_TAIL(&fs->fs_fdelist, fde, fde_next);
    320 
    321 	fde->fde_dbg = dbg;
    322 	fde->fde_fs = fs;
    323 	fde->fde_addr = ds->ds_data + *off;
    324 	fde->fde_offset = *off;
    325 
    326 	length = dbg->read(ds->ds_data, off, 4);
    327 	if (length == 0xffffffff) {
    328 		dwarf_size = 8;
    329 		length = dbg->read(ds->ds_data, off, 8);
    330 	} else
    331 		dwarf_size = 4;
    332 
    333 	if (length > ds->ds_size - *off) {
    334 		DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
    335 		return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
    336 	}
    337 
    338 	fde->fde_length = length;
    339 
    340 	if (eh_frame) {
    341 		fde->fde_cieoff = dbg->read(ds->ds_data, off, 4);
    342 		cieoff = *off - (4 + fde->fde_cieoff);
    343 		/* This delta should never be 0. */
    344 		if (cieoff == fde->fde_offset) {
    345 			DWARF_SET_ERROR(dbg, error, DW_DLE_NO_CIE_FOR_FDE);
    346 			return (DW_DLE_NO_CIE_FOR_FDE);
    347 		}
    348 	} else {
    349 		fde->fde_cieoff = dbg->read(ds->ds_data, off, dwarf_size);
    350 		cieoff = fde->fde_cieoff;
    351 	}
    352 
    353 	if (_dwarf_frame_find_cie(fs, cieoff, &cie) ==
    354 	    DW_DLE_NO_ENTRY) {
    355 		ret = _dwarf_frame_add_cie(dbg, fs, ds, &cieoff, &cie,
    356 		    error);
    357 		if (ret != DW_DLE_NONE)
    358 			return (ret);
    359 	}
    360 	fde->fde_cie = cie;
    361 	if (eh_frame) {
    362 		/*
    363 		 * The FDE PC start/range for .eh_frame is encoded according
    364 		 * to the LSB spec's extension to DWARF2.
    365 		 */
    366 		ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
    367 		    ds->ds_data, off, cie->cie_fde_encode, ds->ds_addr + *off,
    368 		    error);
    369 		if (ret != DW_DLE_NONE)
    370 			return (ret);
    371 		fde->fde_initloc = val;
    372 		/*
    373 		 * FDE PC range should not be relative value to anything.
    374 		 * So pass 0 for pc value.
    375 		 */
    376 		ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
    377 		    ds->ds_data, off, cie->cie_fde_encode, 0, error);
    378 		if (ret != DW_DLE_NONE)
    379 			return (ret);
    380 		fde->fde_adrange = val;
    381 	} else {
    382 		fde->fde_initloc = dbg->read(ds->ds_data, off,
    383 		    cie->cie_addrsize);
    384 		fde->fde_adrange = dbg->read(ds->ds_data, off,
    385 		    cie->cie_addrsize);
    386 	}
    387 
    388 	/* Optional FDE augmentation data for .eh_frame section. (ignored) */
    389 	if (eh_frame && *cie->cie_augment == 'z') {
    390 		fde->fde_auglen = _dwarf_read_uleb128(ds->ds_data, off);
    391 		fde->fde_augdata = ds->ds_data + *off;
    392 		*off += fde->fde_auglen;
    393 	}
    394 
    395 	fde->fde_inst = ds->ds_data + *off;
    396 	if (dwarf_size == 4)
    397 		fde->fde_instlen = fde->fde_offset + 4 + length - *off;
    398 	else
    399 		fde->fde_instlen = fde->fde_offset + 12 + length - *off;
    400 
    401 	*off += fde->fde_instlen;
    402 
    403 #ifdef FRAME_DEBUG
    404 	printf("fde:");
    405 	if (eh_frame)
    406 		printf("(eh_frame)");
    407 	putchar('\n');
    408 	printf("\tfde_offset=%ju fde_length=%ju fde_cieoff=%ju"
    409 	    " fde_instlen=%ju off=%ju\n", fde->fde_offset, fde->fde_length,
    410 	    fde->fde_cieoff, fde->fde_instlen, *off);
    411 #endif
    412 
    413 	fs->fs_fdelen++;
    414 
    415 	return (DW_DLE_NONE);
    416 }
    417 
    418 static void
    419 _dwarf_frame_section_cleanup(Dwarf_FrameSec fs)
    420 {
    421 	Dwarf_Cie cie, tcie;
    422 	Dwarf_Fde fde, tfde;
    423 
    424 	STAILQ_FOREACH_SAFE(cie, &fs->fs_cielist, cie_next, tcie) {
    425 		STAILQ_REMOVE(&fs->fs_cielist, cie, _Dwarf_Cie, cie_next);
    426 		free(cie);
    427 	}
    428 
    429 	STAILQ_FOREACH_SAFE(fde, &fs->fs_fdelist, fde_next, tfde) {
    430 		STAILQ_REMOVE(&fs->fs_fdelist, fde, _Dwarf_Fde, fde_next);
    431 		free(fde);
    432 	}
    433 
    434 	if (fs->fs_ciearray != NULL)
    435 		free(fs->fs_ciearray);
    436 	if (fs->fs_fdearray != NULL)
    437 		free(fs->fs_fdearray);
    438 
    439 	free(fs);
    440 }
    441 
    442 static int
    443 _dwarf_frame_section_init(Dwarf_Debug dbg, Dwarf_FrameSec *frame_sec,
    444     Dwarf_Section *ds, int eh_frame, Dwarf_Error *error)
    445 {
    446 	Dwarf_FrameSec fs;
    447 	Dwarf_Cie cie;
    448 	Dwarf_Fde fde;
    449 	uint64_t length, offset, cie_id, entry_off;
    450 	int dwarf_size, i, ret;
    451 
    452 	assert(frame_sec != NULL);
    453 	assert(*frame_sec == NULL);
    454 
    455 	if ((fs = calloc(1, sizeof(struct _Dwarf_FrameSec))) == NULL) {
    456 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
    457 		return (DW_DLE_MEMORY);
    458 	}
    459 	STAILQ_INIT(&fs->fs_cielist);
    460 	STAILQ_INIT(&fs->fs_fdelist);
    461 
    462 	offset = 0;
    463 	while (offset < ds->ds_size) {
    464 		entry_off = offset;
    465 		length = dbg->read(ds->ds_data, &offset, 4);
    466 		if (length == 0xffffffff) {
    467 			dwarf_size = 8;
    468 			length = dbg->read(ds->ds_data, &offset, 8);
    469 		} else
    470 			dwarf_size = 4;
    471 
    472 		if (length > ds->ds_size - offset ||
    473 		    (length == 0 && !eh_frame)) {
    474 			ret = DW_DLE_DEBUG_FRAME_LENGTH_BAD;
    475 			DWARF_SET_ERROR(dbg, error, ret);
    476 			goto fail_cleanup;
    477 		}
    478 
    479 		/* Check terminator for .eh_frame */
    480 		if (eh_frame && length == 0)
    481 			break;
    482 
    483 		cie_id = dbg->read(ds->ds_data, &offset, dwarf_size);
    484 
    485 		if (eh_frame) {
    486 			/* GNU .eh_frame use CIE id 0. */
    487 			if (cie_id == 0)
    488 				ret = _dwarf_frame_add_cie(dbg, fs, ds,
    489 				    &entry_off, NULL, error);
    490 			else
    491 				ret = _dwarf_frame_add_fde(dbg, fs, ds,
    492 				    &entry_off, 1, error);
    493 		} else {
    494 			/* .dwarf_frame use CIE id ~0 */
    495 			if ((dwarf_size == 4 && cie_id == ~0U) ||
    496 			    (dwarf_size == 8 && cie_id == ~0ULL))
    497 				ret = _dwarf_frame_add_cie(dbg, fs, ds,
    498 				    &entry_off, NULL, error);
    499 			else
    500 				ret = _dwarf_frame_add_fde(dbg, fs, ds,
    501 				    &entry_off, 0, error);
    502 		}
    503 
    504 		if (ret != DW_DLE_NONE)
    505 			goto fail_cleanup;
    506 
    507 		offset = entry_off;
    508 	}
    509 
    510 	/* Create CIE array. */
    511 	if (fs->fs_cielen > 0) {
    512 		if ((fs->fs_ciearray = malloc(sizeof(Dwarf_Cie) *
    513 		    fs->fs_cielen)) == NULL) {
    514 			ret = DW_DLE_MEMORY;
    515 			DWARF_SET_ERROR(dbg, error, ret);
    516 			goto fail_cleanup;
    517 		}
    518 		i = 0;
    519 		STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) {
    520 			fs->fs_ciearray[i++] = cie;
    521 		}
    522 		assert((Dwarf_Unsigned)i == fs->fs_cielen);
    523 	}
    524 
    525 	/* Create FDE array. */
    526 	if (fs->fs_fdelen > 0) {
    527 		if ((fs->fs_fdearray = malloc(sizeof(Dwarf_Fde) *
    528 		    fs->fs_fdelen)) == NULL) {
    529 			ret = DW_DLE_MEMORY;
    530 			DWARF_SET_ERROR(dbg, error, ret);
    531 			goto fail_cleanup;
    532 		}
    533 		i = 0;
    534 		STAILQ_FOREACH(fde, &fs->fs_fdelist, fde_next) {
    535 			fs->fs_fdearray[i++] = fde;
    536 		}
    537 		assert((Dwarf_Unsigned)i == fs->fs_fdelen);
    538 	}
    539 
    540 	*frame_sec = fs;
    541 
    542 	return (DW_DLE_NONE);
    543 
    544 fail_cleanup:
    545 
    546 	_dwarf_frame_section_cleanup(fs);
    547 
    548 	return (ret);
    549 }
    550 
    551 static int
    552 _dwarf_frame_run_inst(Dwarf_Debug dbg, Dwarf_Regtable3 *rt, uint8_t addr_size,
    553     uint8_t *insts, Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf,
    554     Dwarf_Addr pc, Dwarf_Addr pc_req, Dwarf_Addr *row_pc, Dwarf_Error *error)
    555 {
    556 	Dwarf_Regtable3 *init_rt, *saved_rt;
    557 	uint8_t *p, *pe;
    558 	uint8_t high2, low6;
    559 	uint64_t reg, reg2, uoff, soff;
    560 	int ret;
    561 
    562 #define	CFA	rt->rt3_cfa_rule
    563 #define	INITCFA	init_rt->rt3_cfa_rule
    564 #define	RL	rt->rt3_rules
    565 #define	INITRL	init_rt->rt3_rules
    566 
    567 #define CHECK_TABLE_SIZE(x)						\
    568 	do {								\
    569 		if ((x) >= rt->rt3_reg_table_size) {			\
    570 			DWARF_SET_ERROR(dbg, error,			\
    571 			    DW_DLE_DF_REG_NUM_TOO_HIGH);		\
    572 			ret = DW_DLE_DF_REG_NUM_TOO_HIGH;		\
    573 			goto program_done;				\
    574 		}							\
    575 	} while(0)
    576 
    577 #ifdef FRAME_DEBUG
    578 	printf("frame_run_inst: (caf=%ju, daf=%jd)\n", caf, daf);
    579 #endif
    580 
    581 	ret = DW_DLE_NONE;
    582 	init_rt = saved_rt = NULL;
    583 	*row_pc = pc;
    584 
    585 	/* Save a copy of the table as initial state. */
    586 	_dwarf_frame_regtable_copy(dbg, &init_rt, rt, error);
    587 
    588 	p = insts;
    589 	pe = p + len;
    590 
    591 	while (p < pe) {
    592 
    593 #ifdef FRAME_DEBUG
    594 		printf("p=%p pe=%p pc=%#jx pc_req=%#jx\n", p, pe, pc, pc_req);
    595 #endif
    596 
    597 		if (*p == DW_CFA_nop) {
    598 #ifdef FRAME_DEBUG
    599 			printf("DW_CFA_nop\n");
    600 #endif
    601 			p++;
    602 			continue;
    603 		}
    604 
    605 		high2 = *p & 0xc0;
    606 		low6 = *p & 0x3f;
    607 		p++;
    608 
    609 		if (high2 > 0) {
    610 			switch (high2) {
    611 			case DW_CFA_advance_loc:
    612 				pc += low6 * caf;
    613 #ifdef FRAME_DEBUG
    614 				printf("DW_CFA_advance_loc(%#jx(%u))\n", pc,
    615 				    low6);
    616 #endif
    617 				if (pc_req < pc)
    618 					goto program_done;
    619 				break;
    620 			case DW_CFA_offset:
    621 				*row_pc = pc;
    622 				CHECK_TABLE_SIZE(low6);
    623 				RL[low6].dw_offset_relevant = 1;
    624 				RL[low6].dw_value_type = DW_EXPR_OFFSET;
    625 				RL[low6].dw_regnum = dbg->dbg_frame_cfa_value;
    626 				RL[low6].dw_offset_or_block_len =
    627 				    _dwarf_decode_uleb128(&p) * daf;
    628 #ifdef FRAME_DEBUG
    629 				printf("DW_CFA_offset(%jd)\n",
    630 				    RL[low6].dw_offset_or_block_len);
    631 #endif
    632 				break;
    633 			case DW_CFA_restore:
    634 				*row_pc = pc;
    635 				CHECK_TABLE_SIZE(low6);
    636 				memcpy(&RL[low6], &INITRL[low6],
    637 				    sizeof(Dwarf_Regtable_Entry3));
    638 #ifdef FRAME_DEBUG
    639 				printf("DW_CFA_restore(%u)\n", low6);
    640 #endif
    641 				break;
    642 			default:
    643 				DWARF_SET_ERROR(dbg, error,
    644 				    DW_DLE_FRAME_INSTR_EXEC_ERROR);
    645 				ret = DW_DLE_FRAME_INSTR_EXEC_ERROR;
    646 				goto program_done;
    647 			}
    648 
    649 			continue;
    650 		}
    651 
    652 		switch (low6) {
    653 		case DW_CFA_set_loc:
    654 			pc = dbg->decode(&p, addr_size);
    655 #ifdef FRAME_DEBUG
    656 			printf("DW_CFA_set_loc(pc=%#jx)\n", pc);
    657 #endif
    658 			if (pc_req < pc)
    659 				goto program_done;
    660 			break;
    661 		case DW_CFA_advance_loc1:
    662 			pc += dbg->decode(&p, 1) * caf;
    663 #ifdef FRAME_DEBUG
    664 			printf("DW_CFA_set_loc1(pc=%#jx)\n", pc);
    665 #endif
    666 			if (pc_req < pc)
    667 				goto program_done;
    668 			break;
    669 		case DW_CFA_advance_loc2:
    670 			pc += dbg->decode(&p, 2) * caf;
    671 #ifdef FRAME_DEBUG
    672 			printf("DW_CFA_set_loc2(pc=%#jx)\n", pc);
    673 #endif
    674 			if (pc_req < pc)
    675 				goto program_done;
    676 			break;
    677 		case DW_CFA_advance_loc4:
    678 			pc += dbg->decode(&p, 4) * caf;
    679 #ifdef FRAME_DEBUG
    680 			printf("DW_CFA_set_loc4(pc=%#jx)\n", pc);
    681 #endif
    682 			if (pc_req < pc)
    683 				goto program_done;
    684 			break;
    685 		case DW_CFA_offset_extended:
    686 			*row_pc = pc;
    687 			reg = _dwarf_decode_uleb128(&p);
    688 			uoff = _dwarf_decode_uleb128(&p);
    689 			CHECK_TABLE_SIZE(reg);
    690 			RL[reg].dw_offset_relevant = 1;
    691 			RL[reg].dw_value_type = DW_EXPR_OFFSET;
    692 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
    693 			RL[reg].dw_offset_or_block_len = uoff * daf;
    694 #ifdef FRAME_DEBUG
    695 			printf("DW_CFA_offset_extended(reg=%ju,uoff=%ju)\n",
    696 			    reg, uoff);
    697 #endif
    698 			break;
    699 		case DW_CFA_restore_extended:
    700 			*row_pc = pc;
    701 			reg = _dwarf_decode_uleb128(&p);
    702 			CHECK_TABLE_SIZE(reg);
    703 			memcpy(&RL[reg], &INITRL[reg],
    704 			    sizeof(Dwarf_Regtable_Entry3));
    705 #ifdef FRAME_DEBUG
    706 			printf("DW_CFA_restore_extended(%ju)\n", reg);
    707 #endif
    708 			break;
    709 		case DW_CFA_undefined:
    710 			*row_pc = pc;
    711 			reg = _dwarf_decode_uleb128(&p);
    712 			CHECK_TABLE_SIZE(reg);
    713 			RL[reg].dw_offset_relevant = 0;
    714 			RL[reg].dw_regnum = dbg->dbg_frame_undefined_value;
    715 #ifdef FRAME_DEBUG
    716 			printf("DW_CFA_undefined(%ju)\n", reg);
    717 #endif
    718 			break;
    719 		case DW_CFA_same_value:
    720 			reg = _dwarf_decode_uleb128(&p);
    721 			CHECK_TABLE_SIZE(reg);
    722 			RL[reg].dw_offset_relevant = 0;
    723 			RL[reg].dw_regnum = dbg->dbg_frame_same_value;
    724 #ifdef FRAME_DEBUG
    725 			printf("DW_CFA_same_value(%ju)\n", reg);
    726 #endif
    727 			break;
    728 		case DW_CFA_register:
    729 			*row_pc = pc;
    730 			reg = _dwarf_decode_uleb128(&p);
    731 			reg2 = _dwarf_decode_uleb128(&p);
    732 			CHECK_TABLE_SIZE(reg);
    733 			RL[reg].dw_offset_relevant = 0;
    734 			RL[reg].dw_regnum = reg2;
    735 #ifdef FRAME_DEBUG
    736 			printf("DW_CFA_register(reg=%ju,reg2=%ju)\n", reg,
    737 			    reg2);
    738 #endif
    739 			break;
    740 		case DW_CFA_remember_state:
    741 			_dwarf_frame_regtable_copy(dbg, &saved_rt, rt, error);
    742 #ifdef FRAME_DEBUG
    743 			printf("DW_CFA_remember_state\n");
    744 #endif
    745 			break;
    746 		case DW_CFA_restore_state:
    747 			*row_pc = pc;
    748 			_dwarf_frame_regtable_copy(dbg, &rt, saved_rt, error);
    749 #ifdef FRAME_DEBUG
    750 			printf("DW_CFA_restore_state\n");
    751 #endif
    752 			break;
    753 		case DW_CFA_def_cfa:
    754 			*row_pc = pc;
    755 			reg = _dwarf_decode_uleb128(&p);
    756 			uoff = _dwarf_decode_uleb128(&p);
    757 			CFA.dw_offset_relevant = 1;
    758 			CFA.dw_value_type = DW_EXPR_OFFSET;
    759 			CFA.dw_regnum = reg;
    760 			CFA.dw_offset_or_block_len = uoff;
    761 #ifdef FRAME_DEBUG
    762 			printf("DW_CFA_def_cfa(reg=%ju,uoff=%ju)\n", reg, uoff);
    763 #endif
    764 			break;
    765 		case DW_CFA_def_cfa_register:
    766 			*row_pc = pc;
    767 			reg = _dwarf_decode_uleb128(&p);
    768 			CFA.dw_regnum = reg;
    769 			/*
    770 			 * Note that DW_CFA_def_cfa_register change the CFA
    771 			 * rule register while keep the old offset. So we
    772 			 * should not touch the CFA.dw_offset_relevant flag
    773 			 * here.
    774 			 */
    775 #ifdef FRAME_DEBUG
    776 			printf("DW_CFA_def_cfa_register(%ju)\n", reg);
    777 #endif
    778 			break;
    779 		case DW_CFA_def_cfa_offset:
    780 			*row_pc = pc;
    781 			uoff = _dwarf_decode_uleb128(&p);
    782 			CFA.dw_offset_relevant = 1;
    783 			CFA.dw_value_type = DW_EXPR_OFFSET;
    784 			CFA.dw_offset_or_block_len = uoff;
    785 #ifdef FRAME_DEBUG
    786 			printf("DW_CFA_def_cfa_offset(%ju)\n", uoff);
    787 #endif
    788 			break;
    789 		case DW_CFA_def_cfa_expression:
    790 			*row_pc = pc;
    791 			CFA.dw_offset_relevant = 0;
    792 			CFA.dw_value_type = DW_EXPR_EXPRESSION;
    793 			CFA.dw_offset_or_block_len = _dwarf_decode_uleb128(&p);
    794 			CFA.dw_block_ptr = p;
    795 			p += CFA.dw_offset_or_block_len;
    796 #ifdef FRAME_DEBUG
    797 			printf("DW_CFA_def_cfa_expression\n");
    798 #endif
    799 			break;
    800 		case DW_CFA_expression:
    801 			*row_pc = pc;
    802 			reg = _dwarf_decode_uleb128(&p);
    803 			CHECK_TABLE_SIZE(reg);
    804 			RL[reg].dw_offset_relevant = 0;
    805 			RL[reg].dw_value_type = DW_EXPR_EXPRESSION;
    806 			RL[reg].dw_offset_or_block_len =
    807 			    _dwarf_decode_uleb128(&p);
    808 			RL[reg].dw_block_ptr = p;
    809 			p += RL[reg].dw_offset_or_block_len;
    810 #ifdef FRAME_DEBUG
    811 			printf("DW_CFA_expression\n");
    812 #endif
    813 			break;
    814 		case DW_CFA_offset_extended_sf:
    815 			*row_pc = pc;
    816 			reg = _dwarf_decode_uleb128(&p);
    817 			soff = _dwarf_decode_sleb128(&p);
    818 			CHECK_TABLE_SIZE(reg);
    819 			RL[reg].dw_offset_relevant = 1;
    820 			RL[reg].dw_value_type = DW_EXPR_OFFSET;
    821 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
    822 			RL[reg].dw_offset_or_block_len = soff * daf;
    823 #ifdef FRAME_DEBUG
    824 			printf("DW_CFA_offset_extended_sf(reg=%ju,soff=%jd)\n",
    825 			    reg, soff);
    826 #endif
    827 			break;
    828 		case DW_CFA_def_cfa_sf:
    829 			*row_pc = pc;
    830 			reg = _dwarf_decode_uleb128(&p);
    831 			soff = _dwarf_decode_sleb128(&p);
    832 			CFA.dw_offset_relevant = 1;
    833 			CFA.dw_value_type = DW_EXPR_OFFSET;
    834 			CFA.dw_regnum = reg;
    835 			CFA.dw_offset_or_block_len = soff * daf;
    836 #ifdef FRAME_DEBUG
    837 			printf("DW_CFA_def_cfa_sf(reg=%ju,soff=%jd)\n", reg,
    838 			    soff);
    839 #endif
    840 			break;
    841 		case DW_CFA_def_cfa_offset_sf:
    842 			*row_pc = pc;
    843 			soff = _dwarf_decode_sleb128(&p);
    844 			CFA.dw_offset_relevant = 1;
    845 			CFA.dw_value_type = DW_EXPR_OFFSET;
    846 			CFA.dw_offset_or_block_len = soff * daf;
    847 #ifdef FRAME_DEBUG
    848 			printf("DW_CFA_def_cfa_offset_sf(soff=%jd)\n", soff);
    849 #endif
    850 			break;
    851 		case DW_CFA_val_offset:
    852 			*row_pc = pc;
    853 			reg = _dwarf_decode_uleb128(&p);
    854 			uoff = _dwarf_decode_uleb128(&p);
    855 			CHECK_TABLE_SIZE(reg);
    856 			RL[reg].dw_offset_relevant = 1;
    857 			RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET;
    858 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
    859 			RL[reg].dw_offset_or_block_len = uoff * daf;
    860 #ifdef FRAME_DEBUG
    861 			printf("DW_CFA_val_offset(reg=%ju,uoff=%ju)\n", reg,
    862 			    uoff);
    863 #endif
    864 			break;
    865 		case DW_CFA_val_offset_sf:
    866 			*row_pc = pc;
    867 			reg = _dwarf_decode_uleb128(&p);
    868 			soff = _dwarf_decode_sleb128(&p);
    869 			CHECK_TABLE_SIZE(reg);
    870 			RL[reg].dw_offset_relevant = 1;
    871 			RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET;
    872 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
    873 			RL[reg].dw_offset_or_block_len = soff * daf;
    874 #ifdef FRAME_DEBUG
    875 			printf("DW_CFA_val_offset_sf(reg=%ju,soff=%jd)\n", reg,
    876 			    soff);
    877 #endif
    878 			break;
    879 		case DW_CFA_val_expression:
    880 			*row_pc = pc;
    881 			reg = _dwarf_decode_uleb128(&p);
    882 			CHECK_TABLE_SIZE(reg);
    883 			RL[reg].dw_offset_relevant = 0;
    884 			RL[reg].dw_value_type = DW_EXPR_VAL_EXPRESSION;
    885 			RL[reg].dw_offset_or_block_len =
    886 			    _dwarf_decode_uleb128(&p);
    887 			RL[reg].dw_block_ptr = p;
    888 			p += RL[reg].dw_offset_or_block_len;
    889 #ifdef FRAME_DEBUG
    890 			printf("DW_CFA_val_expression\n");
    891 #endif
    892 			break;
    893 		default:
    894 			DWARF_SET_ERROR(dbg, error,
    895 			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
    896 			ret = DW_DLE_FRAME_INSTR_EXEC_ERROR;
    897 			goto program_done;
    898 		}
    899 	}
    900 
    901 program_done:
    902 
    903 	free(init_rt->rt3_rules);
    904 	free(init_rt);
    905 	if (saved_rt) {
    906 		free(saved_rt->rt3_rules);
    907 		free(saved_rt);
    908 	}
    909 
    910 	return (ret);
    911 
    912 #undef	CFA
    913 #undef	INITCFA
    914 #undef	RL
    915 #undef	INITRL
    916 #undef	CHECK_TABLE_SIZE
    917 }
    918 
    919 static int
    920 _dwarf_frame_convert_inst(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts,
    921     Dwarf_Unsigned len, Dwarf_Unsigned *count, Dwarf_Frame_Op *fop,
    922     Dwarf_Frame_Op3 *fop3, Dwarf_Error *error)
    923 {
    924 	uint8_t *p, *pe;
    925 	uint8_t high2, low6;
    926 	uint64_t reg, reg2, uoff, soff, blen;
    927 
    928 #define	SET_BASE_OP(x)						\
    929 	do {							\
    930 		if (fop != NULL)				\
    931 			fop[*count].fp_base_op = (x) >> 6;	\
    932 		if (fop3 != NULL)				\
    933 			fop3[*count].fp_base_op = (x) >> 6;	\
    934 	} while(0)
    935 
    936 #define	SET_EXTENDED_OP(x)					\
    937 	do {							\
    938 		if (fop != NULL)				\
    939 			fop[*count].fp_extended_op = (x);	\
    940 		if (fop3 != NULL)				\
    941 			fop3[*count].fp_extended_op = (x);	\
    942 	} while(0)
    943 
    944 #define	SET_REGISTER(x)						\
    945 	do {							\
    946 		if (fop != NULL)				\
    947 			fop[*count].fp_register = (x);		\
    948 		if (fop3 != NULL)				\
    949 			fop3[*count].fp_register = (x);		\
    950 	} while(0)
    951 
    952 #define	SET_OFFSET(x)						\
    953 	do {							\
    954 		if (fop != NULL)				\
    955 			fop[*count].fp_offset = (x);		\
    956 		if (fop3 != NULL)				\
    957 			fop3[*count].fp_offset_or_block_len =	\
    958 			    (x);				\
    959 	} while(0)
    960 
    961 #define	SET_INSTR_OFFSET(x)					\
    962 	do {							\
    963 		if (fop != NULL)				\
    964 			fop[*count].fp_instr_offset = (x);	\
    965 		if (fop3 != NULL)				\
    966 			fop3[*count].fp_instr_offset = (x);	\
    967 	} while(0)
    968 
    969 #define	SET_BLOCK_LEN(x)					\
    970 	do {							\
    971 		if (fop3 != NULL)				\
    972 			fop3[*count].fp_offset_or_block_len =	\
    973 			    (x);				\
    974 	} while(0)
    975 
    976 #define	SET_EXPR_BLOCK(addr, len)					\
    977 	do {								\
    978 		if (fop3 != NULL) {					\
    979 			fop3[*count].fp_expr_block =			\
    980 			    malloc((size_t) (len));			\
    981 			if (fop3[*count].fp_expr_block == NULL)	{	\
    982 				DWARF_SET_ERROR(dbg, error,		\
    983 				    DW_DLE_MEMORY);			\
    984 				return (DW_DLE_MEMORY);			\
    985 			}						\
    986 			memcpy(&fop3[*count].fp_expr_block,		\
    987 			    (addr), (len));				\
    988 		}							\
    989 	} while(0)
    990 
    991 	*count = 0;
    992 
    993 	p = insts;
    994 	pe = p + len;
    995 
    996 	while (p < pe) {
    997 
    998 		SET_INSTR_OFFSET(p - insts);
    999 
   1000 		if (*p == DW_CFA_nop) {
   1001 			p++;
   1002 			(*count)++;
   1003 			continue;
   1004 		}
   1005 
   1006 		high2 = *p & 0xc0;
   1007 		low6 = *p & 0x3f;
   1008 		p++;
   1009 
   1010 		if (high2 > 0) {
   1011 			switch (high2) {
   1012 			case DW_CFA_advance_loc:
   1013 				SET_BASE_OP(high2);
   1014 				SET_OFFSET(low6);
   1015 				break;
   1016 			case DW_CFA_offset:
   1017 				SET_BASE_OP(high2);
   1018 				SET_REGISTER(low6);
   1019 				uoff = _dwarf_decode_uleb128(&p);
   1020 				SET_OFFSET(uoff);
   1021 				break;
   1022 			case DW_CFA_restore:
   1023 				SET_BASE_OP(high2);
   1024 				SET_REGISTER(low6);
   1025 				break;
   1026 			default:
   1027 				DWARF_SET_ERROR(dbg, error,
   1028 				    DW_DLE_FRAME_INSTR_EXEC_ERROR);
   1029 				return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
   1030 			}
   1031 
   1032 			(*count)++;
   1033 			continue;
   1034 		}
   1035 
   1036 		SET_EXTENDED_OP(low6);
   1037 
   1038 		switch (low6) {
   1039 		case DW_CFA_set_loc:
   1040 			uoff = dbg->decode(&p, addr_size);
   1041 			SET_OFFSET(uoff);
   1042 			break;
   1043 		case DW_CFA_advance_loc1:
   1044 			uoff = dbg->decode(&p, 1);
   1045 			SET_OFFSET(uoff);
   1046 			break;
   1047 		case DW_CFA_advance_loc2:
   1048 			uoff = dbg->decode(&p, 2);
   1049 			SET_OFFSET(uoff);
   1050 			break;
   1051 		case DW_CFA_advance_loc4:
   1052 			uoff = dbg->decode(&p, 4);
   1053 			SET_OFFSET(uoff);
   1054 			break;
   1055 		case DW_CFA_offset_extended:
   1056 		case DW_CFA_def_cfa:
   1057 		case DW_CFA_val_offset:
   1058 			reg = _dwarf_decode_uleb128(&p);
   1059 			uoff = _dwarf_decode_uleb128(&p);
   1060 			SET_REGISTER(reg);
   1061 			SET_OFFSET(uoff);
   1062 			break;
   1063 		case DW_CFA_restore_extended:
   1064 		case DW_CFA_undefined:
   1065 		case DW_CFA_same_value:
   1066 		case DW_CFA_def_cfa_register:
   1067 			reg = _dwarf_decode_uleb128(&p);
   1068 			SET_REGISTER(reg);
   1069 			break;
   1070 		case DW_CFA_register:
   1071 			reg = _dwarf_decode_uleb128(&p);
   1072 			reg2 = _dwarf_decode_uleb128(&p);
   1073 			SET_REGISTER(reg);
   1074 			SET_OFFSET(reg2);
   1075 			break;
   1076 		case DW_CFA_remember_state:
   1077 		case DW_CFA_restore_state:
   1078 			break;
   1079 		case DW_CFA_def_cfa_offset:
   1080 			uoff = _dwarf_decode_uleb128(&p);
   1081 			SET_OFFSET(uoff);
   1082 			break;
   1083 		case DW_CFA_def_cfa_expression:
   1084 			blen = _dwarf_decode_uleb128(&p);
   1085 			SET_BLOCK_LEN(blen);
   1086 			SET_EXPR_BLOCK(p, blen);
   1087 			p += blen;
   1088 			break;
   1089 		case DW_CFA_expression:
   1090 		case DW_CFA_val_expression:
   1091 			reg = _dwarf_decode_uleb128(&p);
   1092 			blen = _dwarf_decode_uleb128(&p);
   1093 			SET_REGISTER(reg);
   1094 			SET_BLOCK_LEN(blen);
   1095 			SET_EXPR_BLOCK(p, blen);
   1096 			p += blen;
   1097 			break;
   1098 		case DW_CFA_offset_extended_sf:
   1099 		case DW_CFA_def_cfa_sf:
   1100 		case DW_CFA_val_offset_sf:
   1101 			reg = _dwarf_decode_uleb128(&p);
   1102 			soff = _dwarf_decode_sleb128(&p);
   1103 			SET_REGISTER(reg);
   1104 			SET_OFFSET(soff);
   1105 			break;
   1106 		case DW_CFA_def_cfa_offset_sf:
   1107 			soff = _dwarf_decode_sleb128(&p);
   1108 			SET_OFFSET(soff);
   1109 			break;
   1110 		default:
   1111 			DWARF_SET_ERROR(dbg, error,
   1112 			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
   1113 			return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
   1114 		}
   1115 
   1116 		(*count)++;
   1117 	}
   1118 
   1119 	return (DW_DLE_NONE);
   1120 }
   1121 
   1122 int
   1123 _dwarf_frame_get_fop(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts,
   1124     Dwarf_Unsigned len, Dwarf_Frame_Op **ret_oplist, Dwarf_Signed *ret_opcnt,
   1125     Dwarf_Error *error)
   1126 {
   1127 	Dwarf_Frame_Op *oplist;
   1128 	Dwarf_Unsigned count;
   1129 	int ret;
   1130 
   1131 	ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count,
   1132 	    NULL, NULL, error);
   1133 	if (ret != DW_DLE_NONE)
   1134 		return (ret);
   1135 
   1136 	if ((oplist = calloc(count, sizeof(Dwarf_Frame_Op))) == NULL) {
   1137 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
   1138 		return (DW_DLE_MEMORY);
   1139 	}
   1140 
   1141 	ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count,
   1142 	    oplist, NULL, error);
   1143 	if (ret != DW_DLE_NONE) {
   1144 		free(oplist);
   1145 		return (ret);
   1146 	}
   1147 
   1148 	*ret_oplist = oplist;
   1149 	*ret_opcnt = count;
   1150 
   1151 	return (DW_DLE_NONE);
   1152 }
   1153 
   1154 int
   1155 _dwarf_frame_regtable_copy(Dwarf_Debug dbg, Dwarf_Regtable3 **dest,
   1156     Dwarf_Regtable3 *src, Dwarf_Error *error)
   1157 {
   1158 	int i;
   1159 
   1160 	assert(dest != NULL);
   1161 	assert(src != NULL);
   1162 
   1163 	if (*dest == NULL) {
   1164 		if ((*dest = malloc(sizeof(Dwarf_Regtable3))) == NULL) {
   1165 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
   1166 			return (DW_DLE_MEMORY);
   1167 		}
   1168 		(*dest)->rt3_reg_table_size = src->rt3_reg_table_size;
   1169 		(*dest)->rt3_rules = malloc(src->rt3_reg_table_size *
   1170 		    sizeof(Dwarf_Regtable_Entry3));
   1171 		if ((*dest)->rt3_rules == NULL) {
   1172 			free(*dest);
   1173 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
   1174 			return (DW_DLE_MEMORY);
   1175 		}
   1176 	}
   1177 
   1178 	memcpy(&(*dest)->rt3_cfa_rule, &src->rt3_cfa_rule,
   1179 	    sizeof(Dwarf_Regtable_Entry3));
   1180 
   1181 	for (i = 0; i < (*dest)->rt3_reg_table_size &&
   1182 	     i < src->rt3_reg_table_size; i++)
   1183 		memcpy(&(*dest)->rt3_rules[i], &src->rt3_rules[i],
   1184 		    sizeof(Dwarf_Regtable_Entry3));
   1185 
   1186 	for (; i < (*dest)->rt3_reg_table_size; i++)
   1187 		(*dest)->rt3_rules[i].dw_regnum =
   1188 		    dbg->dbg_frame_undefined_value;
   1189 
   1190 	return (DW_DLE_NONE);
   1191 }
   1192 
   1193 int
   1194 _dwarf_frame_get_internal_table(Dwarf_Fde fde, Dwarf_Addr pc_req,
   1195     Dwarf_Regtable3 **ret_rt, Dwarf_Addr *ret_row_pc, Dwarf_Error *error)
   1196 {
   1197 	Dwarf_Debug dbg;
   1198 	Dwarf_Cie cie;
   1199 	Dwarf_Regtable3 *rt;
   1200 	Dwarf_Addr row_pc;
   1201 	int i, ret;
   1202 
   1203 	assert(ret_rt != NULL);
   1204 
   1205 	dbg = fde->fde_dbg;
   1206 	assert(dbg != NULL);
   1207 
   1208 	rt = dbg->dbg_internal_reg_table;
   1209 
   1210 	/* Clear the content of regtable from previous run. */
   1211 	memset(&rt->rt3_cfa_rule, 0, sizeof(Dwarf_Regtable_Entry3));
   1212 	memset(rt->rt3_rules, 0, rt->rt3_reg_table_size *
   1213 	    sizeof(Dwarf_Regtable_Entry3));
   1214 
   1215 	/* Set rules to initial values. */
   1216 	for (i = 0; i < rt->rt3_reg_table_size; i++)
   1217 		rt->rt3_rules[i].dw_regnum = dbg->dbg_frame_rule_initial_value;
   1218 
   1219 	/* Run initial instructions in CIE. */
   1220 	cie = fde->fde_cie;
   1221 	assert(cie != NULL);
   1222 	ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize,
   1223 	    cie->cie_initinst, cie->cie_instlen, cie->cie_caf, cie->cie_daf, 0,
   1224 	    ~0ULL, &row_pc, error);
   1225 	if (ret != DW_DLE_NONE)
   1226 		return (ret);
   1227 
   1228 	/* Run instructions in FDE. */
   1229 	if (pc_req >= fde->fde_initloc) {
   1230 		ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize,
   1231 		    fde->fde_inst, fde->fde_instlen, cie->cie_caf,
   1232 		    cie->cie_daf, fde->fde_initloc, pc_req, &row_pc, error);
   1233 		if (ret != DW_DLE_NONE)
   1234 			return (ret);
   1235 	}
   1236 
   1237 	*ret_rt = rt;
   1238 	*ret_row_pc = row_pc;
   1239 
   1240 	return (DW_DLE_NONE);
   1241 }
   1242 
   1243 void
   1244 _dwarf_frame_cleanup(Dwarf_Debug dbg)
   1245 {
   1246 	Dwarf_Regtable3 *rt;
   1247 
   1248 	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ);
   1249 
   1250 	if (dbg->dbg_internal_reg_table) {
   1251 		rt = dbg->dbg_internal_reg_table;
   1252 		free(rt->rt3_rules);
   1253 		free(rt);
   1254 		dbg->dbg_internal_reg_table = NULL;
   1255 	}
   1256 
   1257 	if (dbg->dbg_frame) {
   1258 		_dwarf_frame_section_cleanup(dbg->dbg_frame);
   1259 		dbg->dbg_frame = NULL;
   1260 	}
   1261 
   1262 	if (dbg->dbg_eh_frame) {
   1263 		_dwarf_frame_section_cleanup(dbg->dbg_eh_frame);
   1264 		dbg->dbg_eh_frame = NULL;
   1265 	}
   1266 }
   1267 
   1268 int
   1269 _dwarf_frame_section_load(Dwarf_Debug dbg, Dwarf_Error *error)
   1270 {
   1271 	Dwarf_Section *ds;
   1272 
   1273 	if ((ds = _dwarf_find_section(dbg, ".debug_frame")) != NULL) {
   1274 		return (_dwarf_frame_section_init(dbg, &dbg->dbg_frame,
   1275 		    ds, 0, error));
   1276 	}
   1277 
   1278 	return (DW_DLE_NONE);
   1279 }
   1280 
   1281 int
   1282 _dwarf_frame_section_load_eh(Dwarf_Debug dbg, Dwarf_Error *error)
   1283 {
   1284 	Dwarf_Section *ds;
   1285 
   1286 	if ((ds = _dwarf_find_section(dbg, ".eh_frame")) != NULL) {
   1287 		return (_dwarf_frame_section_init(dbg, &dbg->dbg_eh_frame,
   1288 		    ds, 1, error));
   1289 	}
   1290 
   1291 	return (DW_DLE_NONE);
   1292 }
   1293 
   1294 void
   1295 _dwarf_frame_params_init(Dwarf_Debug dbg)
   1296 {
   1297 
   1298 	/* Initialise call frame related parameters. */
   1299 	dbg->dbg_frame_rule_table_size = DW_FRAME_LAST_REG_NUM;
   1300 	dbg->dbg_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE;
   1301 	dbg->dbg_frame_cfa_value = DW_FRAME_CFA_COL3;
   1302 	dbg->dbg_frame_same_value = DW_FRAME_SAME_VAL;
   1303 	dbg->dbg_frame_undefined_value = DW_FRAME_UNDEFINED_VAL;
   1304 }
   1305 
   1306 int
   1307 _dwarf_frame_interal_table_init(Dwarf_Debug dbg, Dwarf_Error *error)
   1308 {
   1309 	Dwarf_Regtable3 *rt;
   1310 
   1311 	if (dbg->dbg_internal_reg_table != NULL)
   1312 		return (DW_DLE_NONE);
   1313 
   1314 	/* Initialise internal register table. */
   1315 	if ((rt = calloc(1, sizeof(Dwarf_Regtable3))) == NULL) {
   1316 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
   1317 		return (DW_DLE_MEMORY);
   1318 	}
   1319 
   1320 	rt->rt3_reg_table_size = dbg->dbg_frame_rule_table_size;
   1321 	if ((rt->rt3_rules = calloc(rt->rt3_reg_table_size,
   1322 	    sizeof(Dwarf_Regtable_Entry3))) == NULL) {
   1323 		free(rt);
   1324 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
   1325 		return (DW_DLE_MEMORY);
   1326 	}
   1327 
   1328 	dbg->dbg_internal_reg_table = rt;
   1329 
   1330 	return (DW_DLE_NONE);
   1331 }
   1332 
   1333 #define	_FDE_INST_INIT_SIZE	128
   1334 
   1335 int
   1336 _dwarf_frame_fde_add_inst(Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1,
   1337     Dwarf_Unsigned val2, Dwarf_Error *error)
   1338 {
   1339 	Dwarf_P_Debug dbg;
   1340 	uint8_t high2, low6;
   1341 	int ret;
   1342 
   1343 #define	ds	fde
   1344 #define	ds_data	fde_inst
   1345 #define	ds_cap	fde_instcap
   1346 #define	ds_size	fde_instlen
   1347 
   1348 	assert(fde != NULL && fde->fde_dbg != NULL);
   1349 	dbg = fde->fde_dbg;
   1350 
   1351 	if (fde->fde_inst == NULL) {
   1352 		fde->fde_instcap = _FDE_INST_INIT_SIZE;
   1353 		fde->fde_instlen = 0;
   1354 		if ((fde->fde_inst = malloc((size_t) fde->fde_instcap)) ==
   1355 		    NULL) {
   1356 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
   1357 			return (DW_DLE_MEMORY);
   1358 		}
   1359 	}
   1360 	assert(fde->fde_instcap != 0);
   1361 
   1362 	RCHECK(WRITE_VALUE(op, 1));
   1363 	if (op == DW_CFA_nop)
   1364 		return (DW_DLE_NONE);
   1365 
   1366 	high2 = op & 0xc0;
   1367 	low6 = op & 0x3f;
   1368 
   1369 	if (high2 > 0) {
   1370 		switch (high2) {
   1371 		case DW_CFA_advance_loc:
   1372 		case DW_CFA_restore:
   1373 			break;
   1374 		case DW_CFA_offset:
   1375 			RCHECK(WRITE_ULEB128(val1));
   1376 			break;
   1377 		default:
   1378 			DWARF_SET_ERROR(dbg, error,
   1379 			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
   1380 			return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
   1381 		}
   1382 		return (DW_DLE_NONE);
   1383 	}
   1384 
   1385 	switch (low6) {
   1386 	case DW_CFA_set_loc:
   1387 		RCHECK(WRITE_VALUE(val1, dbg->dbg_pointer_size));
   1388 		break;
   1389 	case DW_CFA_advance_loc1:
   1390 		RCHECK(WRITE_VALUE(val1, 1));
   1391 		break;
   1392 	case DW_CFA_advance_loc2:
   1393 		RCHECK(WRITE_VALUE(val1, 2));
   1394 		break;
   1395 	case DW_CFA_advance_loc4:
   1396 		RCHECK(WRITE_VALUE(val1, 4));
   1397 		break;
   1398 	case DW_CFA_offset_extended:
   1399 	case DW_CFA_def_cfa:
   1400 	case DW_CFA_register:
   1401 		RCHECK(WRITE_ULEB128(val1));
   1402 		RCHECK(WRITE_ULEB128(val2));
   1403 		break;
   1404 	case DW_CFA_restore_extended:
   1405 	case DW_CFA_undefined:
   1406 	case DW_CFA_same_value:
   1407 	case DW_CFA_def_cfa_register:
   1408 	case DW_CFA_def_cfa_offset:
   1409 		RCHECK(WRITE_ULEB128(val1));
   1410 		break;
   1411 	case DW_CFA_remember_state:
   1412 	case DW_CFA_restore_state:
   1413 		break;
   1414 	default:
   1415 		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR);
   1416 		return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
   1417 	}
   1418 
   1419 	return (DW_DLE_NONE);
   1420 
   1421 gen_fail:
   1422 	return (ret);
   1423 
   1424 #undef	ds
   1425 #undef	ds_data
   1426 #undef	ds_cap
   1427 #undef	ds_size
   1428 }
   1429 
   1430 static int
   1431 _dwarf_frame_gen_cie(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_P_Cie cie,
   1432     Dwarf_Error *error)
   1433 {
   1434 	Dwarf_Unsigned len;
   1435 	uint64_t offset;
   1436 	int ret;
   1437 
   1438 	assert(dbg != NULL && ds != NULL && cie != NULL);
   1439 
   1440 	cie->cie_offset = offset = ds->ds_size;
   1441 	cie->cie_length = 0;
   1442 	cie->cie_version = 1;
   1443 
   1444 	/* Length placeholder. */
   1445 	RCHECK(WRITE_VALUE(cie->cie_length, 4));
   1446 
   1447 	/* .debug_frame use CIE id ~0. */
   1448 	RCHECK(WRITE_VALUE(~0U, 4));
   1449 
   1450 	/* .debug_frame version is 1. (DWARF2) */
   1451 	RCHECK(WRITE_VALUE(cie->cie_version, 1));
   1452 
   1453 	/* Write augmentation, if present. */
   1454 	if (cie->cie_augment != NULL)
   1455 		RCHECK(WRITE_BLOCK(cie->cie_augment,
   1456 		    strlen((char *) cie->cie_augment) + 1));
   1457 	else
   1458 		RCHECK(WRITE_VALUE(0, 1));
   1459 
   1460 	/* Write caf, daf and ra. */
   1461 	RCHECK(WRITE_ULEB128(cie->cie_caf));
   1462 	RCHECK(WRITE_SLEB128(cie->cie_daf));
   1463 	RCHECK(WRITE_VALUE(cie->cie_ra, 1));
   1464 
   1465 	/* Write initial instructions, if present. */
   1466 	if (cie->cie_initinst != NULL)
   1467 		RCHECK(WRITE_BLOCK(cie->cie_initinst, cie->cie_instlen));
   1468 
   1469 	/* Add padding. */
   1470 	len = ds->ds_size - cie->cie_offset - 4;
   1471 	cie->cie_length = roundup(len, dbg->dbg_pointer_size);
   1472 	while (len++ < cie->cie_length)
   1473 		RCHECK(WRITE_VALUE(DW_CFA_nop, 1));
   1474 
   1475 	/* Fill in the length field. */
   1476 	dbg->write(ds->ds_data, &offset, cie->cie_length, 4);
   1477 
   1478 	return (DW_DLE_NONE);
   1479 
   1480 gen_fail:
   1481 	return (ret);
   1482 }
   1483 
   1484 static int
   1485 _dwarf_frame_gen_fde(Dwarf_P_Debug dbg, Dwarf_P_Section ds,
   1486     Dwarf_Rel_Section drs, Dwarf_P_Fde fde, Dwarf_Error *error)
   1487 {
   1488 	Dwarf_Unsigned len;
   1489 	uint64_t offset;
   1490 	int ret;
   1491 
   1492 	assert(dbg != NULL && ds != NULL && drs != NULL);
   1493 	assert(fde != NULL && fde->fde_cie != NULL);
   1494 
   1495 	fde->fde_offset = offset = ds->ds_size;
   1496 	fde->fde_length = 0;
   1497 	fde->fde_cieoff = fde->fde_cie->cie_offset;
   1498 
   1499 	/* Length placeholder. */
   1500 	RCHECK(WRITE_VALUE(fde->fde_length, 4));
   1501 
   1502 	/* Write CIE pointer. */
   1503 	RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4,
   1504 	    ds->ds_size, 0, fde->fde_cieoff, ".debug_frame", error));
   1505 
   1506 	/* Write FDE initial location. */
   1507 	RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc,
   1508 	    dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx,
   1509 	    fde->fde_initloc, NULL, error));
   1510 
   1511 	/*
   1512 	 * Write FDE address range. Use a pair of relocation entries if
   1513 	 * application provided end symbol index. Otherwise write the
   1514 	 * length without assoicating any relocation info.
   1515 	 */
   1516 	if (fde->fde_esymndx > 0)
   1517 		RCHECK(_dwarf_reloc_entry_add_pair(dbg, drs, ds,
   1518 		    dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx,
   1519 		    fde->fde_esymndx, fde->fde_initloc, fde->fde_eoff, error));
   1520 	else
   1521 		RCHECK(WRITE_VALUE(fde->fde_adrange, dbg->dbg_pointer_size));
   1522 
   1523 	/* Write FDE frame instructions. */
   1524 	RCHECK(WRITE_BLOCK(fde->fde_inst, fde->fde_instlen));
   1525 
   1526 	/* Add padding. */
   1527 	len = ds->ds_size - fde->fde_offset - 4;
   1528 	fde->fde_length = roundup(len, dbg->dbg_pointer_size);
   1529 	while (len++ < fde->fde_length)
   1530 		RCHECK(WRITE_VALUE(DW_CFA_nop, 1));
   1531 
   1532 	/* Fill in the length field. */
   1533 	dbg->write(ds->ds_data, &offset, fde->fde_length, 4);
   1534 
   1535 	return (DW_DLE_NONE);
   1536 
   1537 gen_fail:
   1538 	return (ret);
   1539 }
   1540 
   1541 int
   1542 _dwarf_frame_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
   1543 {
   1544 	Dwarf_P_Section ds;
   1545 	Dwarf_Rel_Section drs;
   1546 	Dwarf_P_Cie cie;
   1547 	Dwarf_P_Fde fde;
   1548 	int ret;
   1549 
   1550 	if (STAILQ_EMPTY(&dbg->dbgp_cielist))
   1551 		return (DW_DLE_NONE);
   1552 
   1553 	/* Create .debug_frame section. */
   1554 	if ((ret = _dwarf_section_init(dbg, &ds, ".debug_frame", 0, error)) !=
   1555 	    DW_DLE_NONE)
   1556 		goto gen_fail0;
   1557 
   1558 	/* Create relocation section for .debug_frame */
   1559 	RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error));
   1560 
   1561 	/* Generate list of CIE. */
   1562 	STAILQ_FOREACH(cie, &dbg->dbgp_cielist, cie_next)
   1563 		RCHECK(_dwarf_frame_gen_cie(dbg, ds, cie, error));
   1564 
   1565 	/* Generate list of FDE. */
   1566 	STAILQ_FOREACH(fde, &dbg->dbgp_fdelist, fde_next)
   1567 		RCHECK(_dwarf_frame_gen_fde(dbg, ds, drs, fde, error));
   1568 
   1569 	/* Inform application the creation of .debug_frame ELF section. */
   1570 	RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
   1571 
   1572 	/* Finalize relocation section for .debug_frame */
   1573 	RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
   1574 
   1575 	return (DW_DLE_NONE);
   1576 
   1577 gen_fail:
   1578 	_dwarf_reloc_section_free(dbg, &drs);
   1579 
   1580 gen_fail0:
   1581 	_dwarf_section_free(dbg, &ds);
   1582 
   1583 	return (ret);
   1584 }
   1585 
   1586 void
   1587 _dwarf_frame_pro_cleanup(Dwarf_P_Debug dbg)
   1588 {
   1589 	Dwarf_P_Cie cie, tcie;
   1590 	Dwarf_P_Fde fde, tfde;
   1591 
   1592 	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
   1593 
   1594 	STAILQ_FOREACH_SAFE(cie, &dbg->dbgp_cielist, cie_next, tcie) {
   1595 		STAILQ_REMOVE(&dbg->dbgp_cielist, cie, _Dwarf_Cie, cie_next);
   1596 		if (cie->cie_augment)
   1597 			free(cie->cie_augment);
   1598 		if (cie->cie_initinst)
   1599 			free(cie->cie_initinst);
   1600 		free(cie);
   1601 	}
   1602 	dbg->dbgp_cielen = 0;
   1603 
   1604 	STAILQ_FOREACH_SAFE(fde, &dbg->dbgp_fdelist, fde_next, tfde) {
   1605 		STAILQ_REMOVE(&dbg->dbgp_fdelist, fde, _Dwarf_Fde, fde_next);
   1606 		if (fde->fde_inst != NULL)
   1607 			free(fde->fde_inst);
   1608 		free(fde);
   1609 	}
   1610 	dbg->dbgp_fdelen = 0;
   1611 }
   1612