xref: /freebsd-src/contrib/elftoolchain/libdwarf/libdwarf_frame.c (revision ab3b51df280b2d09f7c7b0d3c746535e296d1771)
12de3b87aSKai Wang /*-
2cf781b2eSEd Maste  * Copyright (c) 2009-2011,2014 Kai Wang
32de3b87aSKai Wang  * All rights reserved.
42de3b87aSKai Wang  *
52de3b87aSKai Wang  * Redistribution and use in source and binary forms, with or without
62de3b87aSKai Wang  * modification, are permitted provided that the following conditions
72de3b87aSKai Wang  * are met:
82de3b87aSKai Wang  * 1. Redistributions of source code must retain the above copyright
92de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer.
102de3b87aSKai Wang  * 2. Redistributions in binary form must reproduce the above copyright
112de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer in the
122de3b87aSKai Wang  *    documentation and/or other materials provided with the distribution.
132de3b87aSKai Wang  *
142de3b87aSKai Wang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152de3b87aSKai Wang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162de3b87aSKai Wang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172de3b87aSKai Wang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182de3b87aSKai Wang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192de3b87aSKai Wang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202de3b87aSKai Wang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212de3b87aSKai Wang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222de3b87aSKai Wang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232de3b87aSKai Wang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242de3b87aSKai Wang  * SUCH DAMAGE.
252de3b87aSKai Wang  */
262de3b87aSKai Wang 
272de3b87aSKai Wang #include "_libdwarf.h"
282de3b87aSKai Wang 
29715d1396SEd Maste ELFTC_VCSID("$Id: libdwarf_frame.c 3589 2018-03-13 20:34:33Z kaiwang27 $");
302de3b87aSKai Wang 
312de3b87aSKai Wang static int
322de3b87aSKai Wang _dwarf_frame_find_cie(Dwarf_FrameSec fs, Dwarf_Unsigned offset,
332de3b87aSKai Wang     Dwarf_Cie *ret_cie)
342de3b87aSKai Wang {
352de3b87aSKai Wang 	Dwarf_Cie cie;
362de3b87aSKai Wang 
372de3b87aSKai Wang 	STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) {
382de3b87aSKai Wang 		if (cie->cie_offset == offset)
392de3b87aSKai Wang 			break;
402de3b87aSKai Wang 	}
412de3b87aSKai Wang 
422de3b87aSKai Wang 	if (cie == NULL)
432de3b87aSKai Wang 		return (DW_DLE_NO_ENTRY);
442de3b87aSKai Wang 
452de3b87aSKai Wang 	if (ret_cie != NULL)
462de3b87aSKai Wang 		*ret_cie = cie;
472de3b87aSKai Wang 
482de3b87aSKai Wang 	return (DW_DLE_NONE);
492de3b87aSKai Wang }
502de3b87aSKai Wang 
512de3b87aSKai Wang static int
52cf781b2eSEd Maste _dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg, Dwarf_Cie cie, uint64_t *val,
53cf781b2eSEd Maste     uint8_t *data, uint64_t *offsetp, uint8_t encode, Dwarf_Addr pc,
54cf781b2eSEd Maste     Dwarf_Error *error)
552de3b87aSKai Wang {
562de3b87aSKai Wang 	uint8_t application;
572de3b87aSKai Wang 
582de3b87aSKai Wang 	if (encode == DW_EH_PE_omit)
592de3b87aSKai Wang 		return (DW_DLE_NONE);
602de3b87aSKai Wang 
612de3b87aSKai Wang 	application = encode & 0xf0;
622de3b87aSKai Wang 	encode &= 0x0f;
632de3b87aSKai Wang 
642de3b87aSKai Wang 	switch (encode) {
652de3b87aSKai Wang 	case DW_EH_PE_absptr:
66cf781b2eSEd Maste 		*val = dbg->read(data, offsetp, cie->cie_addrsize);
672de3b87aSKai Wang 		break;
682de3b87aSKai Wang 	case DW_EH_PE_uleb128:
692de3b87aSKai Wang 		*val = _dwarf_read_uleb128(data, offsetp);
702de3b87aSKai Wang 		break;
712de3b87aSKai Wang 	case DW_EH_PE_udata2:
722de3b87aSKai Wang 		*val = dbg->read(data, offsetp, 2);
732de3b87aSKai Wang 		break;
742de3b87aSKai Wang 	case DW_EH_PE_udata4:
752de3b87aSKai Wang 		*val = dbg->read(data, offsetp, 4);
762de3b87aSKai Wang 		break;
772de3b87aSKai Wang 	case DW_EH_PE_udata8:
782de3b87aSKai Wang 		*val = dbg->read(data, offsetp, 8);
792de3b87aSKai Wang 		break;
802de3b87aSKai Wang 	case DW_EH_PE_sleb128:
812de3b87aSKai Wang 		*val = _dwarf_read_sleb128(data, offsetp);
822de3b87aSKai Wang 		break;
832de3b87aSKai Wang 	case DW_EH_PE_sdata2:
842de3b87aSKai Wang 		*val = (int16_t) dbg->read(data, offsetp, 2);
852de3b87aSKai Wang 		break;
862de3b87aSKai Wang 	case DW_EH_PE_sdata4:
872de3b87aSKai Wang 		*val = (int32_t) dbg->read(data, offsetp, 4);
882de3b87aSKai Wang 		break;
892de3b87aSKai Wang 	case DW_EH_PE_sdata8:
902de3b87aSKai Wang 		*val = dbg->read(data, offsetp, 8);
912de3b87aSKai Wang 		break;
922de3b87aSKai Wang 	default:
932de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
942de3b87aSKai Wang 		return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
952de3b87aSKai Wang 	}
962de3b87aSKai Wang 
972de3b87aSKai Wang 	if (application == DW_EH_PE_pcrel) {
982de3b87aSKai Wang 		/*
992de3b87aSKai Wang 		 * Value is relative to .eh_frame section virtual addr.
1002de3b87aSKai Wang 		 */
1012de3b87aSKai Wang 		switch (encode) {
1022de3b87aSKai Wang 		case DW_EH_PE_uleb128:
1032de3b87aSKai Wang 		case DW_EH_PE_udata2:
1042de3b87aSKai Wang 		case DW_EH_PE_udata4:
1052de3b87aSKai Wang 		case DW_EH_PE_udata8:
1062de3b87aSKai Wang 			*val += pc;
1072de3b87aSKai Wang 			break;
1082de3b87aSKai Wang 		case DW_EH_PE_sleb128:
1092de3b87aSKai Wang 		case DW_EH_PE_sdata2:
1102de3b87aSKai Wang 		case DW_EH_PE_sdata4:
1112de3b87aSKai Wang 		case DW_EH_PE_sdata8:
1122de3b87aSKai Wang 			*val = pc + (int64_t) *val;
1132de3b87aSKai Wang 			break;
1142de3b87aSKai Wang 		default:
1152de3b87aSKai Wang 			/* DW_EH_PE_absptr is absolute value. */
1162de3b87aSKai Wang 			break;
1172de3b87aSKai Wang 		}
1182de3b87aSKai Wang 	}
1192de3b87aSKai Wang 
1202de3b87aSKai Wang 	/* XXX Applications other than DW_EH_PE_pcrel are not handled. */
1212de3b87aSKai Wang 
1222de3b87aSKai Wang 	return (DW_DLE_NONE);
1232de3b87aSKai Wang }
1242de3b87aSKai Wang 
1252de3b87aSKai Wang static int
1262de3b87aSKai Wang _dwarf_frame_parse_lsb_cie_augment(Dwarf_Debug dbg, Dwarf_Cie cie,
1272de3b87aSKai Wang     Dwarf_Error *error)
1282de3b87aSKai Wang {
1292de3b87aSKai Wang 	uint8_t *aug_p, *augdata_p;
1302de3b87aSKai Wang 	uint64_t val, offset;
1312de3b87aSKai Wang 	uint8_t encode;
1322de3b87aSKai Wang 	int ret;
1332de3b87aSKai Wang 
1342de3b87aSKai Wang 	assert(cie->cie_augment != NULL && *cie->cie_augment == 'z');
1352de3b87aSKai Wang 
1362de3b87aSKai Wang 	/*
1372de3b87aSKai Wang 	 * Here we're only interested in the presence of augment 'R'
1382de3b87aSKai Wang 	 * and associated CIE augment data, which describes the
1392de3b87aSKai Wang 	 * encoding scheme of FDE PC begin and range.
1402de3b87aSKai Wang 	 */
1412de3b87aSKai Wang 	aug_p = &cie->cie_augment[1];
1422de3b87aSKai Wang 	augdata_p = cie->cie_augdata;
1432de3b87aSKai Wang 	while (*aug_p != '\0') {
1442de3b87aSKai Wang 		switch (*aug_p) {
145715d1396SEd Maste 		case 'S':
146715d1396SEd Maste 			break;
1472de3b87aSKai Wang 		case 'L':
1482de3b87aSKai Wang 			/* Skip one augment in augment data. */
1492de3b87aSKai Wang 			augdata_p++;
1502de3b87aSKai Wang 			break;
1512de3b87aSKai Wang 		case 'P':
1522de3b87aSKai Wang 			/* Skip two augments in augment data. */
1532de3b87aSKai Wang 			encode = *augdata_p++;
1542de3b87aSKai Wang 			offset = 0;
155cf781b2eSEd Maste 			ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
1562de3b87aSKai Wang 			    augdata_p, &offset, encode, 0, error);
1572de3b87aSKai Wang 			if (ret != DW_DLE_NONE)
1582de3b87aSKai Wang 				return (ret);
1592de3b87aSKai Wang 			augdata_p += offset;
1602de3b87aSKai Wang 			break;
1612de3b87aSKai Wang 		case 'R':
1622de3b87aSKai Wang 			cie->cie_fde_encode = *augdata_p++;
1632de3b87aSKai Wang 			break;
1642de3b87aSKai Wang 		default:
1652de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error,
1662de3b87aSKai Wang 			    DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
1672de3b87aSKai Wang 			return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
1682de3b87aSKai Wang 		}
1692de3b87aSKai Wang 		aug_p++;
1702de3b87aSKai Wang 	}
1712de3b87aSKai Wang 
1722de3b87aSKai Wang 	return (DW_DLE_NONE);
1732de3b87aSKai Wang }
1742de3b87aSKai Wang 
1752de3b87aSKai Wang static int
1762de3b87aSKai Wang _dwarf_frame_add_cie(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds,
1772de3b87aSKai Wang     Dwarf_Unsigned *off, Dwarf_Cie *ret_cie, Dwarf_Error *error)
1782de3b87aSKai Wang {
1792de3b87aSKai Wang 	Dwarf_Cie cie;
1802de3b87aSKai Wang 	uint64_t length;
1812de3b87aSKai Wang 	int dwarf_size, ret;
1822de3b87aSKai Wang 	char *p;
1832de3b87aSKai Wang 
1842de3b87aSKai Wang 	/* Check if we already added this CIE. */
1852de3b87aSKai Wang 	if (_dwarf_frame_find_cie(fs, *off, &cie) != DW_DLE_NO_ENTRY) {
1862de3b87aSKai Wang 		*off += cie->cie_length + 4;
1872de3b87aSKai Wang 		return (DW_DLE_NONE);
1882de3b87aSKai Wang 	}
1892de3b87aSKai Wang 
1902de3b87aSKai Wang 	if ((cie = calloc(1, sizeof(struct _Dwarf_Cie))) == NULL) {
1912de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1922de3b87aSKai Wang 		return (DW_DLE_MEMORY);
1932de3b87aSKai Wang 	}
1942de3b87aSKai Wang 	STAILQ_INSERT_TAIL(&fs->fs_cielist, cie, cie_next);
1952de3b87aSKai Wang 
1962de3b87aSKai Wang 	cie->cie_dbg = dbg;
1972de3b87aSKai Wang 	cie->cie_index = fs->fs_cielen;
1982de3b87aSKai Wang 	cie->cie_offset = *off;
1992de3b87aSKai Wang 
2002de3b87aSKai Wang 	length = dbg->read(ds->ds_data, off, 4);
2012de3b87aSKai Wang 	if (length == 0xffffffff) {
2022de3b87aSKai Wang 		dwarf_size = 8;
2032de3b87aSKai Wang 		length = dbg->read(ds->ds_data, off, 8);
2042de3b87aSKai Wang 	} else
2052de3b87aSKai Wang 		dwarf_size = 4;
2062de3b87aSKai Wang 
2072de3b87aSKai Wang 	if (length > ds->ds_size - *off) {
2082de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
2092de3b87aSKai Wang 		return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
2102de3b87aSKai Wang 	}
2112de3b87aSKai Wang 
2122de3b87aSKai Wang 	(void) dbg->read(ds->ds_data, off, dwarf_size); /* Skip CIE id. */
2132de3b87aSKai Wang 	cie->cie_length = length;
2142de3b87aSKai Wang 
2152de3b87aSKai Wang 	cie->cie_version = dbg->read(ds->ds_data, off, 1);
2162de3b87aSKai Wang 	if (cie->cie_version != 1 && cie->cie_version != 3 &&
2172de3b87aSKai Wang 	    cie->cie_version != 4) {
2182de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_VERSION_BAD);
2192de3b87aSKai Wang 		return (DW_DLE_FRAME_VERSION_BAD);
2202de3b87aSKai Wang 	}
2212de3b87aSKai Wang 
2222de3b87aSKai Wang 	cie->cie_augment = ds->ds_data + *off;
2232de3b87aSKai Wang 	p = (char *) ds->ds_data;
2242de3b87aSKai Wang 	while (p[(*off)++] != '\0')
2252de3b87aSKai Wang 		;
2262de3b87aSKai Wang 
2272de3b87aSKai Wang 	/* We only recognize normal .dwarf_frame and GNU .eh_frame sections. */
2282de3b87aSKai Wang 	if (*cie->cie_augment != 0 && *cie->cie_augment != 'z') {
2292de3b87aSKai Wang 		*off = cie->cie_offset + ((dwarf_size == 4) ? 4 : 12) +
2302de3b87aSKai Wang 		    cie->cie_length;
2312de3b87aSKai Wang 		return (DW_DLE_NONE);
2322de3b87aSKai Wang 	}
2332de3b87aSKai Wang 
2342de3b87aSKai Wang 	/* Optional EH Data field for .eh_frame section. */
2352de3b87aSKai Wang 	if (strstr((char *)cie->cie_augment, "eh") != NULL)
2362de3b87aSKai Wang 		cie->cie_ehdata = dbg->read(ds->ds_data, off,
2372de3b87aSKai Wang 		    dbg->dbg_pointer_size);
2382de3b87aSKai Wang 
239cf781b2eSEd Maste 	/* DWARF4 added "address_size" and "segment_size". */
240cf781b2eSEd Maste 	if (cie->cie_version == 4) {
241cf781b2eSEd Maste 		cie->cie_addrsize = dbg->read(ds->ds_data, off, 1);
242cf781b2eSEd Maste 		cie->cie_segmentsize = dbg->read(ds->ds_data, off, 1);
243cf781b2eSEd Maste 	} else {
244cf781b2eSEd Maste 		/*
245cf781b2eSEd Maste 		 * Otherwise (DWARF[23]) we just set CIE addrsize to the
246cf781b2eSEd Maste 		 * debug context pointer size.
247cf781b2eSEd Maste 		 */
248cf781b2eSEd Maste 		cie->cie_addrsize = dbg->dbg_pointer_size;
249cf781b2eSEd Maste 	}
250cf781b2eSEd Maste 
2512de3b87aSKai Wang 	cie->cie_caf = _dwarf_read_uleb128(ds->ds_data, off);
2522de3b87aSKai Wang 	cie->cie_daf = _dwarf_read_sleb128(ds->ds_data, off);
2532de3b87aSKai Wang 
2542de3b87aSKai Wang 	/* Return address register. */
2552de3b87aSKai Wang 	if (cie->cie_version == 1)
2562de3b87aSKai Wang 		cie->cie_ra = dbg->read(ds->ds_data, off, 1);
2572de3b87aSKai Wang 	else
2582de3b87aSKai Wang 		cie->cie_ra = _dwarf_read_uleb128(ds->ds_data, off);
2592de3b87aSKai Wang 
2602de3b87aSKai Wang 	/* Optional CIE augmentation data for .eh_frame section. */
2612de3b87aSKai Wang 	if (*cie->cie_augment == 'z') {
2622de3b87aSKai Wang 		cie->cie_auglen = _dwarf_read_uleb128(ds->ds_data, off);
2632de3b87aSKai Wang 		cie->cie_augdata = ds->ds_data + *off;
2642de3b87aSKai Wang 		*off += cie->cie_auglen;
2652de3b87aSKai Wang 		/*
2662de3b87aSKai Wang 		 * XXX Use DW_EH_PE_absptr for default FDE PC start/range,
2672de3b87aSKai Wang 		 * in case _dwarf_frame_parse_lsb_cie_augment fails to
2682de3b87aSKai Wang 		 * find out the real encode.
2692de3b87aSKai Wang 		 */
2702de3b87aSKai Wang 		cie->cie_fde_encode = DW_EH_PE_absptr;
2712de3b87aSKai Wang 		ret = _dwarf_frame_parse_lsb_cie_augment(dbg, cie, error);
2722de3b87aSKai Wang 		if (ret != DW_DLE_NONE)
2732de3b87aSKai Wang 			return (ret);
2742de3b87aSKai Wang 	}
2752de3b87aSKai Wang 
2762de3b87aSKai Wang 	/* CIE Initial instructions. */
2772de3b87aSKai Wang 	cie->cie_initinst = ds->ds_data + *off;
2782de3b87aSKai Wang 	if (dwarf_size == 4)
2792de3b87aSKai Wang 		cie->cie_instlen = cie->cie_offset + 4 + length - *off;
2802de3b87aSKai Wang 	else
2812de3b87aSKai Wang 		cie->cie_instlen = cie->cie_offset + 12 + length - *off;
2822de3b87aSKai Wang 
2832de3b87aSKai Wang 	*off += cie->cie_instlen;
2842de3b87aSKai Wang 
2852de3b87aSKai Wang #ifdef FRAME_DEBUG
2862de3b87aSKai Wang 	printf("cie:\n");
2872de3b87aSKai Wang 	printf("\tcie_version=%u cie_offset=%ju cie_length=%ju cie_augment=%s"
2882de3b87aSKai Wang 	    " cie_instlen=%ju cie->cie_caf=%ju cie->cie_daf=%jd off=%ju\n",
2892de3b87aSKai Wang 	    cie->cie_version, cie->cie_offset, cie->cie_length,
2902de3b87aSKai Wang 	    (char *)cie->cie_augment, cie->cie_instlen, cie->cie_caf,
2912de3b87aSKai Wang 	    cie->cie_daf, *off);
2922de3b87aSKai Wang #endif
2932de3b87aSKai Wang 
2942de3b87aSKai Wang 	if (ret_cie != NULL)
2952de3b87aSKai Wang 		*ret_cie = cie;
2962de3b87aSKai Wang 
2972de3b87aSKai Wang 	fs->fs_cielen++;
2982de3b87aSKai Wang 
2992de3b87aSKai Wang 	return (DW_DLE_NONE);
3002de3b87aSKai Wang }
3012de3b87aSKai Wang 
3022de3b87aSKai Wang static int
3032de3b87aSKai Wang _dwarf_frame_add_fde(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds,
3042de3b87aSKai Wang     Dwarf_Unsigned *off, int eh_frame, Dwarf_Error *error)
3052de3b87aSKai Wang {
3062de3b87aSKai Wang 	Dwarf_Cie cie;
3072de3b87aSKai Wang 	Dwarf_Fde fde;
3082de3b87aSKai Wang 	Dwarf_Unsigned cieoff;
3092de3b87aSKai Wang 	uint64_t length, val;
3102de3b87aSKai Wang 	int dwarf_size, ret;
3112de3b87aSKai Wang 
3122de3b87aSKai Wang 	if ((fde = calloc(1, sizeof(struct _Dwarf_Fde))) == NULL) {
3132de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
3142de3b87aSKai Wang 		return (DW_DLE_MEMORY);
3152de3b87aSKai Wang 	}
3162de3b87aSKai Wang 	STAILQ_INSERT_TAIL(&fs->fs_fdelist, fde, fde_next);
3172de3b87aSKai Wang 
3182de3b87aSKai Wang 	fde->fde_dbg = dbg;
3192de3b87aSKai Wang 	fde->fde_fs = fs;
3202de3b87aSKai Wang 	fde->fde_addr = ds->ds_data + *off;
3212de3b87aSKai Wang 	fde->fde_offset = *off;
3222de3b87aSKai Wang 
3232de3b87aSKai Wang 	length = dbg->read(ds->ds_data, off, 4);
3242de3b87aSKai Wang 	if (length == 0xffffffff) {
3252de3b87aSKai Wang 		dwarf_size = 8;
3262de3b87aSKai Wang 		length = dbg->read(ds->ds_data, off, 8);
3272de3b87aSKai Wang 	} else
3282de3b87aSKai Wang 		dwarf_size = 4;
3292de3b87aSKai Wang 
3302de3b87aSKai Wang 	if (length > ds->ds_size - *off) {
3312de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
3322de3b87aSKai Wang 		return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
3332de3b87aSKai Wang 	}
3342de3b87aSKai Wang 
3352de3b87aSKai Wang 	fde->fde_length = length;
3362de3b87aSKai Wang 
3372de3b87aSKai Wang 	if (eh_frame) {
3382de3b87aSKai Wang 		fde->fde_cieoff = dbg->read(ds->ds_data, off, 4);
3392de3b87aSKai Wang 		cieoff = *off - (4 + fde->fde_cieoff);
3402de3b87aSKai Wang 		/* This delta should never be 0. */
3412de3b87aSKai Wang 		if (cieoff == fde->fde_offset) {
3422de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error, DW_DLE_NO_CIE_FOR_FDE);
3432de3b87aSKai Wang 			return (DW_DLE_NO_CIE_FOR_FDE);
3442de3b87aSKai Wang 		}
3452de3b87aSKai Wang 	} else {
3462de3b87aSKai Wang 		fde->fde_cieoff = dbg->read(ds->ds_data, off, dwarf_size);
3472de3b87aSKai Wang 		cieoff = fde->fde_cieoff;
3482de3b87aSKai Wang 	}
3492de3b87aSKai Wang 
3502de3b87aSKai Wang 	if (_dwarf_frame_find_cie(fs, cieoff, &cie) ==
3512de3b87aSKai Wang 	    DW_DLE_NO_ENTRY) {
3522de3b87aSKai Wang 		ret = _dwarf_frame_add_cie(dbg, fs, ds, &cieoff, &cie,
3532de3b87aSKai Wang 		    error);
3542de3b87aSKai Wang 		if (ret != DW_DLE_NONE)
3552de3b87aSKai Wang 			return (ret);
3562de3b87aSKai Wang 	}
3572de3b87aSKai Wang 	fde->fde_cie = cie;
3582de3b87aSKai Wang 	if (eh_frame) {
3592de3b87aSKai Wang 		/*
3602de3b87aSKai Wang 		 * The FDE PC start/range for .eh_frame is encoded according
3612de3b87aSKai Wang 		 * to the LSB spec's extension to DWARF2.
3622de3b87aSKai Wang 		 */
363cf781b2eSEd Maste 		ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
364cf781b2eSEd Maste 		    ds->ds_data, off, cie->cie_fde_encode, ds->ds_addr + *off,
365cf781b2eSEd Maste 		    error);
3662de3b87aSKai Wang 		if (ret != DW_DLE_NONE)
3672de3b87aSKai Wang 			return (ret);
3682de3b87aSKai Wang 		fde->fde_initloc = val;
3692de3b87aSKai Wang 		/*
3702de3b87aSKai Wang 		 * FDE PC range should not be relative value to anything.
3712de3b87aSKai Wang 		 * So pass 0 for pc value.
3722de3b87aSKai Wang 		 */
373cf781b2eSEd Maste 		ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
374cf781b2eSEd Maste 		    ds->ds_data, off, cie->cie_fde_encode, 0, error);
3752de3b87aSKai Wang 		if (ret != DW_DLE_NONE)
3762de3b87aSKai Wang 			return (ret);
3772de3b87aSKai Wang 		fde->fde_adrange = val;
3782de3b87aSKai Wang 	} else {
3792de3b87aSKai Wang 		fde->fde_initloc = dbg->read(ds->ds_data, off,
380cf781b2eSEd Maste 		    cie->cie_addrsize);
3812de3b87aSKai Wang 		fde->fde_adrange = dbg->read(ds->ds_data, off,
382cf781b2eSEd Maste 		    cie->cie_addrsize);
3832de3b87aSKai Wang 	}
3842de3b87aSKai Wang 
3852de3b87aSKai Wang 	/* Optional FDE augmentation data for .eh_frame section. (ignored) */
3862de3b87aSKai Wang 	if (eh_frame && *cie->cie_augment == 'z') {
3872de3b87aSKai Wang 		fde->fde_auglen = _dwarf_read_uleb128(ds->ds_data, off);
3882de3b87aSKai Wang 		fde->fde_augdata = ds->ds_data + *off;
3892de3b87aSKai Wang 		*off += fde->fde_auglen;
3902de3b87aSKai Wang 	}
3912de3b87aSKai Wang 
3922de3b87aSKai Wang 	fde->fde_inst = ds->ds_data + *off;
3932de3b87aSKai Wang 	if (dwarf_size == 4)
3942de3b87aSKai Wang 		fde->fde_instlen = fde->fde_offset + 4 + length - *off;
3952de3b87aSKai Wang 	else
3962de3b87aSKai Wang 		fde->fde_instlen = fde->fde_offset + 12 + length - *off;
3972de3b87aSKai Wang 
3982de3b87aSKai Wang 	*off += fde->fde_instlen;
3992de3b87aSKai Wang 
4002de3b87aSKai Wang #ifdef FRAME_DEBUG
4012de3b87aSKai Wang 	printf("fde:");
4022de3b87aSKai Wang 	if (eh_frame)
4032de3b87aSKai Wang 		printf("(eh_frame)");
4042de3b87aSKai Wang 	putchar('\n');
4052de3b87aSKai Wang 	printf("\tfde_offset=%ju fde_length=%ju fde_cieoff=%ju"
4062de3b87aSKai Wang 	    " fde_instlen=%ju off=%ju\n", fde->fde_offset, fde->fde_length,
4072de3b87aSKai Wang 	    fde->fde_cieoff, fde->fde_instlen, *off);
4082de3b87aSKai Wang #endif
4092de3b87aSKai Wang 
4102de3b87aSKai Wang 	fs->fs_fdelen++;
4112de3b87aSKai Wang 
4122de3b87aSKai Wang 	return (DW_DLE_NONE);
4132de3b87aSKai Wang }
4142de3b87aSKai Wang 
4152de3b87aSKai Wang static void
4162de3b87aSKai Wang _dwarf_frame_section_cleanup(Dwarf_FrameSec fs)
4172de3b87aSKai Wang {
4182de3b87aSKai Wang 	Dwarf_Cie cie, tcie;
4192de3b87aSKai Wang 	Dwarf_Fde fde, tfde;
4202de3b87aSKai Wang 
4212de3b87aSKai Wang 	STAILQ_FOREACH_SAFE(cie, &fs->fs_cielist, cie_next, tcie) {
4222de3b87aSKai Wang 		STAILQ_REMOVE(&fs->fs_cielist, cie, _Dwarf_Cie, cie_next);
4232de3b87aSKai Wang 		free(cie);
4242de3b87aSKai Wang 	}
4252de3b87aSKai Wang 
4262de3b87aSKai Wang 	STAILQ_FOREACH_SAFE(fde, &fs->fs_fdelist, fde_next, tfde) {
4272de3b87aSKai Wang 		STAILQ_REMOVE(&fs->fs_fdelist, fde, _Dwarf_Fde, fde_next);
4282de3b87aSKai Wang 		free(fde);
4292de3b87aSKai Wang 	}
4302de3b87aSKai Wang 
4312de3b87aSKai Wang 	if (fs->fs_ciearray != NULL)
4322de3b87aSKai Wang 		free(fs->fs_ciearray);
4332de3b87aSKai Wang 	if (fs->fs_fdearray != NULL)
4342de3b87aSKai Wang 		free(fs->fs_fdearray);
4352de3b87aSKai Wang 
4362de3b87aSKai Wang 	free(fs);
4372de3b87aSKai Wang }
4382de3b87aSKai Wang 
4392de3b87aSKai Wang static int
4402de3b87aSKai Wang _dwarf_frame_section_init(Dwarf_Debug dbg, Dwarf_FrameSec *frame_sec,
4412de3b87aSKai Wang     Dwarf_Section *ds, int eh_frame, Dwarf_Error *error)
4422de3b87aSKai Wang {
4432de3b87aSKai Wang 	Dwarf_FrameSec fs;
4442de3b87aSKai Wang 	Dwarf_Cie cie;
4452de3b87aSKai Wang 	Dwarf_Fde fde;
4462de3b87aSKai Wang 	uint64_t length, offset, cie_id, entry_off;
4472de3b87aSKai Wang 	int dwarf_size, i, ret;
4482de3b87aSKai Wang 
4492de3b87aSKai Wang 	assert(frame_sec != NULL);
4502de3b87aSKai Wang 	assert(*frame_sec == NULL);
4512de3b87aSKai Wang 
4522de3b87aSKai Wang 	if ((fs = calloc(1, sizeof(struct _Dwarf_FrameSec))) == NULL) {
4532de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
4542de3b87aSKai Wang 		return (DW_DLE_MEMORY);
4552de3b87aSKai Wang 	}
4562de3b87aSKai Wang 	STAILQ_INIT(&fs->fs_cielist);
4572de3b87aSKai Wang 	STAILQ_INIT(&fs->fs_fdelist);
4582de3b87aSKai Wang 
4592de3b87aSKai Wang 	offset = 0;
4602de3b87aSKai Wang 	while (offset < ds->ds_size) {
4612de3b87aSKai Wang 		entry_off = offset;
4622de3b87aSKai Wang 		length = dbg->read(ds->ds_data, &offset, 4);
4632de3b87aSKai Wang 		if (length == 0xffffffff) {
4642de3b87aSKai Wang 			dwarf_size = 8;
4652de3b87aSKai Wang 			length = dbg->read(ds->ds_data, &offset, 8);
4662de3b87aSKai Wang 		} else
4672de3b87aSKai Wang 			dwarf_size = 4;
4682de3b87aSKai Wang 
4692de3b87aSKai Wang 		if (length > ds->ds_size - offset ||
4702de3b87aSKai Wang 		    (length == 0 && !eh_frame)) {
471*ab3b51dfSMark Johnston 			ret = DW_DLE_DEBUG_FRAME_LENGTH_BAD;
472*ab3b51dfSMark Johnston 			DWARF_SET_ERROR(dbg, error, ret);
473*ab3b51dfSMark Johnston 			goto fail_cleanup;
4742de3b87aSKai Wang 		}
4752de3b87aSKai Wang 
4762de3b87aSKai Wang 		/* Check terminator for .eh_frame */
4772de3b87aSKai Wang 		if (eh_frame && length == 0)
4782de3b87aSKai Wang 			break;
4792de3b87aSKai Wang 
4802de3b87aSKai Wang 		cie_id = dbg->read(ds->ds_data, &offset, dwarf_size);
4812de3b87aSKai Wang 
4822de3b87aSKai Wang 		if (eh_frame) {
4832de3b87aSKai Wang 			/* GNU .eh_frame use CIE id 0. */
4842de3b87aSKai Wang 			if (cie_id == 0)
4852de3b87aSKai Wang 				ret = _dwarf_frame_add_cie(dbg, fs, ds,
4862de3b87aSKai Wang 				    &entry_off, NULL, error);
4872de3b87aSKai Wang 			else
4882de3b87aSKai Wang 				ret = _dwarf_frame_add_fde(dbg, fs, ds,
4892de3b87aSKai Wang 				    &entry_off, 1, error);
4902de3b87aSKai Wang 		} else {
4912de3b87aSKai Wang 			/* .dwarf_frame use CIE id ~0 */
4922de3b87aSKai Wang 			if ((dwarf_size == 4 && cie_id == ~0U) ||
4932de3b87aSKai Wang 			    (dwarf_size == 8 && cie_id == ~0ULL))
4942de3b87aSKai Wang 				ret = _dwarf_frame_add_cie(dbg, fs, ds,
4952de3b87aSKai Wang 				    &entry_off, NULL, error);
4962de3b87aSKai Wang 			else
4972de3b87aSKai Wang 				ret = _dwarf_frame_add_fde(dbg, fs, ds,
4982de3b87aSKai Wang 				    &entry_off, 0, error);
4992de3b87aSKai Wang 		}
5002de3b87aSKai Wang 
5012de3b87aSKai Wang 		if (ret != DW_DLE_NONE)
5022de3b87aSKai Wang 			goto fail_cleanup;
5032de3b87aSKai Wang 
5042de3b87aSKai Wang 		offset = entry_off;
5052de3b87aSKai Wang 	}
5062de3b87aSKai Wang 
5072de3b87aSKai Wang 	/* Create CIE array. */
5082de3b87aSKai Wang 	if (fs->fs_cielen > 0) {
5092de3b87aSKai Wang 		if ((fs->fs_ciearray = malloc(sizeof(Dwarf_Cie) *
5102de3b87aSKai Wang 		    fs->fs_cielen)) == NULL) {
5112de3b87aSKai Wang 			ret = DW_DLE_MEMORY;
5122de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error, ret);
5132de3b87aSKai Wang 			goto fail_cleanup;
5142de3b87aSKai Wang 		}
5152de3b87aSKai Wang 		i = 0;
5162de3b87aSKai Wang 		STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) {
5172de3b87aSKai Wang 			fs->fs_ciearray[i++] = cie;
5182de3b87aSKai Wang 		}
5192de3b87aSKai Wang 		assert((Dwarf_Unsigned)i == fs->fs_cielen);
5202de3b87aSKai Wang 	}
5212de3b87aSKai Wang 
5222de3b87aSKai Wang 	/* Create FDE array. */
5232de3b87aSKai Wang 	if (fs->fs_fdelen > 0) {
5242de3b87aSKai Wang 		if ((fs->fs_fdearray = malloc(sizeof(Dwarf_Fde) *
5252de3b87aSKai Wang 		    fs->fs_fdelen)) == NULL) {
5262de3b87aSKai Wang 			ret = DW_DLE_MEMORY;
5272de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error, ret);
5282de3b87aSKai Wang 			goto fail_cleanup;
5292de3b87aSKai Wang 		}
5302de3b87aSKai Wang 		i = 0;
5312de3b87aSKai Wang 		STAILQ_FOREACH(fde, &fs->fs_fdelist, fde_next) {
5322de3b87aSKai Wang 			fs->fs_fdearray[i++] = fde;
5332de3b87aSKai Wang 		}
5342de3b87aSKai Wang 		assert((Dwarf_Unsigned)i == fs->fs_fdelen);
5352de3b87aSKai Wang 	}
5362de3b87aSKai Wang 
5372de3b87aSKai Wang 	*frame_sec = fs;
5382de3b87aSKai Wang 
5392de3b87aSKai Wang 	return (DW_DLE_NONE);
5402de3b87aSKai Wang 
5412de3b87aSKai Wang fail_cleanup:
5422de3b87aSKai Wang 
5432de3b87aSKai Wang 	_dwarf_frame_section_cleanup(fs);
5442de3b87aSKai Wang 
5452de3b87aSKai Wang 	return (ret);
5462de3b87aSKai Wang }
5472de3b87aSKai Wang 
5482de3b87aSKai Wang static int
549cf781b2eSEd Maste _dwarf_frame_run_inst(Dwarf_Debug dbg, Dwarf_Regtable3 *rt, uint8_t addr_size,
550cf781b2eSEd Maste     uint8_t *insts, Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf,
551cf781b2eSEd Maste     Dwarf_Addr pc, Dwarf_Addr pc_req, Dwarf_Addr *row_pc, Dwarf_Error *error)
5522de3b87aSKai Wang {
5532de3b87aSKai Wang 	Dwarf_Regtable3 *init_rt, *saved_rt;
5542de3b87aSKai Wang 	uint8_t *p, *pe;
5552de3b87aSKai Wang 	uint8_t high2, low6;
5562de3b87aSKai Wang 	uint64_t reg, reg2, uoff, soff;
5572de3b87aSKai Wang 	int ret;
5582de3b87aSKai Wang 
5592de3b87aSKai Wang #define	CFA	rt->rt3_cfa_rule
5602de3b87aSKai Wang #define	INITCFA	init_rt->rt3_cfa_rule
5612de3b87aSKai Wang #define	RL	rt->rt3_rules
5622de3b87aSKai Wang #define	INITRL	init_rt->rt3_rules
5632de3b87aSKai Wang 
5642de3b87aSKai Wang #define CHECK_TABLE_SIZE(x)						\
5652de3b87aSKai Wang 	do {								\
5662de3b87aSKai Wang 		if ((x) >= rt->rt3_reg_table_size) {			\
5672de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error,			\
5682de3b87aSKai Wang 			    DW_DLE_DF_REG_NUM_TOO_HIGH);		\
5692de3b87aSKai Wang 			ret = DW_DLE_DF_REG_NUM_TOO_HIGH;		\
5702de3b87aSKai Wang 			goto program_done;				\
5712de3b87aSKai Wang 		}							\
5722de3b87aSKai Wang 	} while(0)
5732de3b87aSKai Wang 
5742de3b87aSKai Wang #ifdef FRAME_DEBUG
5752de3b87aSKai Wang 	printf("frame_run_inst: (caf=%ju, daf=%jd)\n", caf, daf);
5762de3b87aSKai Wang #endif
5772de3b87aSKai Wang 
5782de3b87aSKai Wang 	ret = DW_DLE_NONE;
5792de3b87aSKai Wang 	init_rt = saved_rt = NULL;
5802de3b87aSKai Wang 	*row_pc = pc;
5812de3b87aSKai Wang 
5822de3b87aSKai Wang 	/* Save a copy of the table as initial state. */
5832de3b87aSKai Wang 	_dwarf_frame_regtable_copy(dbg, &init_rt, rt, error);
5842de3b87aSKai Wang 
5852de3b87aSKai Wang 	p = insts;
5862de3b87aSKai Wang 	pe = p + len;
5872de3b87aSKai Wang 
5882de3b87aSKai Wang 	while (p < pe) {
5892de3b87aSKai Wang 
5902de3b87aSKai Wang #ifdef FRAME_DEBUG
5912de3b87aSKai Wang 		printf("p=%p pe=%p pc=%#jx pc_req=%#jx\n", p, pe, pc, pc_req);
5922de3b87aSKai Wang #endif
5932de3b87aSKai Wang 
5942de3b87aSKai Wang 		if (*p == DW_CFA_nop) {
5952de3b87aSKai Wang #ifdef FRAME_DEBUG
5962de3b87aSKai Wang 			printf("DW_CFA_nop\n");
5972de3b87aSKai Wang #endif
5982de3b87aSKai Wang 			p++;
5992de3b87aSKai Wang 			continue;
6002de3b87aSKai Wang 		}
6012de3b87aSKai Wang 
6022de3b87aSKai Wang 		high2 = *p & 0xc0;
6032de3b87aSKai Wang 		low6 = *p & 0x3f;
6042de3b87aSKai Wang 		p++;
6052de3b87aSKai Wang 
6062de3b87aSKai Wang 		if (high2 > 0) {
6072de3b87aSKai Wang 			switch (high2) {
6082de3b87aSKai Wang 			case DW_CFA_advance_loc:
6092de3b87aSKai Wang 				pc += low6 * caf;
6102de3b87aSKai Wang #ifdef FRAME_DEBUG
6112de3b87aSKai Wang 				printf("DW_CFA_advance_loc(%#jx(%u))\n", pc,
6122de3b87aSKai Wang 				    low6);
6132de3b87aSKai Wang #endif
6142de3b87aSKai Wang 				if (pc_req < pc)
6152de3b87aSKai Wang 					goto program_done;
6162de3b87aSKai Wang 				break;
6172de3b87aSKai Wang 			case DW_CFA_offset:
6182de3b87aSKai Wang 				*row_pc = pc;
6192de3b87aSKai Wang 				CHECK_TABLE_SIZE(low6);
6202de3b87aSKai Wang 				RL[low6].dw_offset_relevant = 1;
6212de3b87aSKai Wang 				RL[low6].dw_value_type = DW_EXPR_OFFSET;
6222de3b87aSKai Wang 				RL[low6].dw_regnum = dbg->dbg_frame_cfa_value;
6232de3b87aSKai Wang 				RL[low6].dw_offset_or_block_len =
6242de3b87aSKai Wang 				    _dwarf_decode_uleb128(&p) * daf;
6252de3b87aSKai Wang #ifdef FRAME_DEBUG
6262de3b87aSKai Wang 				printf("DW_CFA_offset(%jd)\n",
6272de3b87aSKai Wang 				    RL[low6].dw_offset_or_block_len);
6282de3b87aSKai Wang #endif
6292de3b87aSKai Wang 				break;
6302de3b87aSKai Wang 			case DW_CFA_restore:
6312de3b87aSKai Wang 				*row_pc = pc;
6322de3b87aSKai Wang 				CHECK_TABLE_SIZE(low6);
6332de3b87aSKai Wang 				memcpy(&RL[low6], &INITRL[low6],
6342de3b87aSKai Wang 				    sizeof(Dwarf_Regtable_Entry3));
6352de3b87aSKai Wang #ifdef FRAME_DEBUG
6362de3b87aSKai Wang 				printf("DW_CFA_restore(%u)\n", low6);
6372de3b87aSKai Wang #endif
6382de3b87aSKai Wang 				break;
6392de3b87aSKai Wang 			default:
6402de3b87aSKai Wang 				DWARF_SET_ERROR(dbg, error,
6412de3b87aSKai Wang 				    DW_DLE_FRAME_INSTR_EXEC_ERROR);
6422de3b87aSKai Wang 				ret = DW_DLE_FRAME_INSTR_EXEC_ERROR;
6432de3b87aSKai Wang 				goto program_done;
6442de3b87aSKai Wang 			}
6452de3b87aSKai Wang 
6462de3b87aSKai Wang 			continue;
6472de3b87aSKai Wang 		}
6482de3b87aSKai Wang 
6492de3b87aSKai Wang 		switch (low6) {
6502de3b87aSKai Wang 		case DW_CFA_set_loc:
651cf781b2eSEd Maste 			pc = dbg->decode(&p, addr_size);
6522de3b87aSKai Wang #ifdef FRAME_DEBUG
6532de3b87aSKai Wang 			printf("DW_CFA_set_loc(pc=%#jx)\n", pc);
6542de3b87aSKai Wang #endif
6552de3b87aSKai Wang 			if (pc_req < pc)
6562de3b87aSKai Wang 				goto program_done;
6572de3b87aSKai Wang 			break;
6582de3b87aSKai Wang 		case DW_CFA_advance_loc1:
6592de3b87aSKai Wang 			pc += dbg->decode(&p, 1) * caf;
6602de3b87aSKai Wang #ifdef FRAME_DEBUG
6612de3b87aSKai Wang 			printf("DW_CFA_set_loc1(pc=%#jx)\n", pc);
6622de3b87aSKai Wang #endif
6632de3b87aSKai Wang 			if (pc_req < pc)
6642de3b87aSKai Wang 				goto program_done;
6652de3b87aSKai Wang 			break;
6662de3b87aSKai Wang 		case DW_CFA_advance_loc2:
6672de3b87aSKai Wang 			pc += dbg->decode(&p, 2) * caf;
6682de3b87aSKai Wang #ifdef FRAME_DEBUG
6692de3b87aSKai Wang 			printf("DW_CFA_set_loc2(pc=%#jx)\n", pc);
6702de3b87aSKai Wang #endif
6712de3b87aSKai Wang 			if (pc_req < pc)
6722de3b87aSKai Wang 				goto program_done;
6732de3b87aSKai Wang 			break;
6742de3b87aSKai Wang 		case DW_CFA_advance_loc4:
6752de3b87aSKai Wang 			pc += dbg->decode(&p, 4) * caf;
6762de3b87aSKai Wang #ifdef FRAME_DEBUG
6772de3b87aSKai Wang 			printf("DW_CFA_set_loc4(pc=%#jx)\n", pc);
6782de3b87aSKai Wang #endif
6792de3b87aSKai Wang 			if (pc_req < pc)
6802de3b87aSKai Wang 				goto program_done;
6812de3b87aSKai Wang 			break;
6822de3b87aSKai Wang 		case DW_CFA_offset_extended:
6832de3b87aSKai Wang 			*row_pc = pc;
6842de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
6852de3b87aSKai Wang 			uoff = _dwarf_decode_uleb128(&p);
6862de3b87aSKai Wang 			CHECK_TABLE_SIZE(reg);
6872de3b87aSKai Wang 			RL[reg].dw_offset_relevant = 1;
6882de3b87aSKai Wang 			RL[reg].dw_value_type = DW_EXPR_OFFSET;
6892de3b87aSKai Wang 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
6902de3b87aSKai Wang 			RL[reg].dw_offset_or_block_len = uoff * daf;
6912de3b87aSKai Wang #ifdef FRAME_DEBUG
6922de3b87aSKai Wang 			printf("DW_CFA_offset_extended(reg=%ju,uoff=%ju)\n",
6932de3b87aSKai Wang 			    reg, uoff);
6942de3b87aSKai Wang #endif
6952de3b87aSKai Wang 			break;
6962de3b87aSKai Wang 		case DW_CFA_restore_extended:
6972de3b87aSKai Wang 			*row_pc = pc;
6982de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
6992de3b87aSKai Wang 			CHECK_TABLE_SIZE(reg);
7002de3b87aSKai Wang 			memcpy(&RL[reg], &INITRL[reg],
7012de3b87aSKai Wang 			    sizeof(Dwarf_Regtable_Entry3));
7022de3b87aSKai Wang #ifdef FRAME_DEBUG
7032de3b87aSKai Wang 			printf("DW_CFA_restore_extended(%ju)\n", reg);
7042de3b87aSKai Wang #endif
7052de3b87aSKai Wang 			break;
7062de3b87aSKai Wang 		case DW_CFA_undefined:
7072de3b87aSKai Wang 			*row_pc = pc;
7082de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
7092de3b87aSKai Wang 			CHECK_TABLE_SIZE(reg);
7102de3b87aSKai Wang 			RL[reg].dw_offset_relevant = 0;
7112de3b87aSKai Wang 			RL[reg].dw_regnum = dbg->dbg_frame_undefined_value;
7122de3b87aSKai Wang #ifdef FRAME_DEBUG
7132de3b87aSKai Wang 			printf("DW_CFA_undefined(%ju)\n", reg);
7142de3b87aSKai Wang #endif
7152de3b87aSKai Wang 			break;
7162de3b87aSKai Wang 		case DW_CFA_same_value:
7172de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
7182de3b87aSKai Wang 			CHECK_TABLE_SIZE(reg);
7192de3b87aSKai Wang 			RL[reg].dw_offset_relevant = 0;
7202de3b87aSKai Wang 			RL[reg].dw_regnum = dbg->dbg_frame_same_value;
7212de3b87aSKai Wang #ifdef FRAME_DEBUG
7222de3b87aSKai Wang 			printf("DW_CFA_same_value(%ju)\n", reg);
7232de3b87aSKai Wang #endif
7242de3b87aSKai Wang 			break;
7252de3b87aSKai Wang 		case DW_CFA_register:
7262de3b87aSKai Wang 			*row_pc = pc;
7272de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
7282de3b87aSKai Wang 			reg2 = _dwarf_decode_uleb128(&p);
7292de3b87aSKai Wang 			CHECK_TABLE_SIZE(reg);
7302de3b87aSKai Wang 			RL[reg].dw_offset_relevant = 0;
7312de3b87aSKai Wang 			RL[reg].dw_regnum = reg2;
7322de3b87aSKai Wang #ifdef FRAME_DEBUG
7332de3b87aSKai Wang 			printf("DW_CFA_register(reg=%ju,reg2=%ju)\n", reg,
7342de3b87aSKai Wang 			    reg2);
7352de3b87aSKai Wang #endif
7362de3b87aSKai Wang 			break;
7372de3b87aSKai Wang 		case DW_CFA_remember_state:
7382de3b87aSKai Wang 			_dwarf_frame_regtable_copy(dbg, &saved_rt, rt, error);
7392de3b87aSKai Wang #ifdef FRAME_DEBUG
7402de3b87aSKai Wang 			printf("DW_CFA_remember_state\n");
7412de3b87aSKai Wang #endif
7422de3b87aSKai Wang 			break;
7432de3b87aSKai Wang 		case DW_CFA_restore_state:
7442de3b87aSKai Wang 			*row_pc = pc;
7452de3b87aSKai Wang 			_dwarf_frame_regtable_copy(dbg, &rt, saved_rt, error);
7462de3b87aSKai Wang #ifdef FRAME_DEBUG
7472de3b87aSKai Wang 			printf("DW_CFA_restore_state\n");
7482de3b87aSKai Wang #endif
7492de3b87aSKai Wang 			break;
7502de3b87aSKai Wang 		case DW_CFA_def_cfa:
7512de3b87aSKai Wang 			*row_pc = pc;
7522de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
7532de3b87aSKai Wang 			uoff = _dwarf_decode_uleb128(&p);
7542de3b87aSKai Wang 			CFA.dw_offset_relevant = 1;
7552de3b87aSKai Wang 			CFA.dw_value_type = DW_EXPR_OFFSET;
7562de3b87aSKai Wang 			CFA.dw_regnum = reg;
7572de3b87aSKai Wang 			CFA.dw_offset_or_block_len = uoff;
7582de3b87aSKai Wang #ifdef FRAME_DEBUG
7592de3b87aSKai Wang 			printf("DW_CFA_def_cfa(reg=%ju,uoff=%ju)\n", reg, uoff);
7602de3b87aSKai Wang #endif
7612de3b87aSKai Wang 			break;
7622de3b87aSKai Wang 		case DW_CFA_def_cfa_register:
7632de3b87aSKai Wang 			*row_pc = pc;
7642de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
7652de3b87aSKai Wang 			CFA.dw_regnum = reg;
7662de3b87aSKai Wang 			/*
7672de3b87aSKai Wang 			 * Note that DW_CFA_def_cfa_register change the CFA
7682de3b87aSKai Wang 			 * rule register while keep the old offset. So we
7692de3b87aSKai Wang 			 * should not touch the CFA.dw_offset_relevant flag
7702de3b87aSKai Wang 			 * here.
7712de3b87aSKai Wang 			 */
7722de3b87aSKai Wang #ifdef FRAME_DEBUG
7732de3b87aSKai Wang 			printf("DW_CFA_def_cfa_register(%ju)\n", reg);
7742de3b87aSKai Wang #endif
7752de3b87aSKai Wang 			break;
7762de3b87aSKai Wang 		case DW_CFA_def_cfa_offset:
7772de3b87aSKai Wang 			*row_pc = pc;
7782de3b87aSKai Wang 			uoff = _dwarf_decode_uleb128(&p);
7792de3b87aSKai Wang 			CFA.dw_offset_relevant = 1;
7802de3b87aSKai Wang 			CFA.dw_value_type = DW_EXPR_OFFSET;
7812de3b87aSKai Wang 			CFA.dw_offset_or_block_len = uoff;
7822de3b87aSKai Wang #ifdef FRAME_DEBUG
7832de3b87aSKai Wang 			printf("DW_CFA_def_cfa_offset(%ju)\n", uoff);
7842de3b87aSKai Wang #endif
7852de3b87aSKai Wang 			break;
7862de3b87aSKai Wang 		case DW_CFA_def_cfa_expression:
7872de3b87aSKai Wang 			*row_pc = pc;
7882de3b87aSKai Wang 			CFA.dw_offset_relevant = 0;
7892de3b87aSKai Wang 			CFA.dw_value_type = DW_EXPR_EXPRESSION;
7902de3b87aSKai Wang 			CFA.dw_offset_or_block_len = _dwarf_decode_uleb128(&p);
7912de3b87aSKai Wang 			CFA.dw_block_ptr = p;
7922de3b87aSKai Wang 			p += CFA.dw_offset_or_block_len;
7932de3b87aSKai Wang #ifdef FRAME_DEBUG
7942de3b87aSKai Wang 			printf("DW_CFA_def_cfa_expression\n");
7952de3b87aSKai Wang #endif
7962de3b87aSKai Wang 			break;
7972de3b87aSKai Wang 		case DW_CFA_expression:
7982de3b87aSKai Wang 			*row_pc = pc;
7992de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
8002de3b87aSKai Wang 			CHECK_TABLE_SIZE(reg);
8012de3b87aSKai Wang 			RL[reg].dw_offset_relevant = 0;
8022de3b87aSKai Wang 			RL[reg].dw_value_type = DW_EXPR_EXPRESSION;
8032de3b87aSKai Wang 			RL[reg].dw_offset_or_block_len =
8042de3b87aSKai Wang 			    _dwarf_decode_uleb128(&p);
8052de3b87aSKai Wang 			RL[reg].dw_block_ptr = p;
8062de3b87aSKai Wang 			p += RL[reg].dw_offset_or_block_len;
8072de3b87aSKai Wang #ifdef FRAME_DEBUG
8082de3b87aSKai Wang 			printf("DW_CFA_expression\n");
8092de3b87aSKai Wang #endif
8102de3b87aSKai Wang 			break;
8112de3b87aSKai Wang 		case DW_CFA_offset_extended_sf:
8122de3b87aSKai Wang 			*row_pc = pc;
8132de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
8142de3b87aSKai Wang 			soff = _dwarf_decode_sleb128(&p);
8152de3b87aSKai Wang 			CHECK_TABLE_SIZE(reg);
8162de3b87aSKai Wang 			RL[reg].dw_offset_relevant = 1;
8172de3b87aSKai Wang 			RL[reg].dw_value_type = DW_EXPR_OFFSET;
8182de3b87aSKai Wang 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
8192de3b87aSKai Wang 			RL[reg].dw_offset_or_block_len = soff * daf;
8202de3b87aSKai Wang #ifdef FRAME_DEBUG
8212de3b87aSKai Wang 			printf("DW_CFA_offset_extended_sf(reg=%ju,soff=%jd)\n",
8222de3b87aSKai Wang 			    reg, soff);
8232de3b87aSKai Wang #endif
8242de3b87aSKai Wang 			break;
8252de3b87aSKai Wang 		case DW_CFA_def_cfa_sf:
8262de3b87aSKai Wang 			*row_pc = pc;
8272de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
8282de3b87aSKai Wang 			soff = _dwarf_decode_sleb128(&p);
8292de3b87aSKai Wang 			CFA.dw_offset_relevant = 1;
8302de3b87aSKai Wang 			CFA.dw_value_type = DW_EXPR_OFFSET;
8312de3b87aSKai Wang 			CFA.dw_regnum = reg;
8322de3b87aSKai Wang 			CFA.dw_offset_or_block_len = soff * daf;
8332de3b87aSKai Wang #ifdef FRAME_DEBUG
8342de3b87aSKai Wang 			printf("DW_CFA_def_cfa_sf(reg=%ju,soff=%jd)\n", reg,
8352de3b87aSKai Wang 			    soff);
8362de3b87aSKai Wang #endif
8372de3b87aSKai Wang 			break;
8382de3b87aSKai Wang 		case DW_CFA_def_cfa_offset_sf:
8392de3b87aSKai Wang 			*row_pc = pc;
8402de3b87aSKai Wang 			soff = _dwarf_decode_sleb128(&p);
8412de3b87aSKai Wang 			CFA.dw_offset_relevant = 1;
8422de3b87aSKai Wang 			CFA.dw_value_type = DW_EXPR_OFFSET;
8432de3b87aSKai Wang 			CFA.dw_offset_or_block_len = soff * daf;
8442de3b87aSKai Wang #ifdef FRAME_DEBUG
8452de3b87aSKai Wang 			printf("DW_CFA_def_cfa_offset_sf(soff=%jd)\n", soff);
8462de3b87aSKai Wang #endif
8472de3b87aSKai Wang 			break;
8482de3b87aSKai Wang 		case DW_CFA_val_offset:
8492de3b87aSKai Wang 			*row_pc = pc;
8502de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
8512de3b87aSKai Wang 			uoff = _dwarf_decode_uleb128(&p);
8522de3b87aSKai Wang 			CHECK_TABLE_SIZE(reg);
8532de3b87aSKai Wang 			RL[reg].dw_offset_relevant = 1;
8542de3b87aSKai Wang 			RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET;
8552de3b87aSKai Wang 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
8562de3b87aSKai Wang 			RL[reg].dw_offset_or_block_len = uoff * daf;
8572de3b87aSKai Wang #ifdef FRAME_DEBUG
8582de3b87aSKai Wang 			printf("DW_CFA_val_offset(reg=%ju,uoff=%ju)\n", reg,
8592de3b87aSKai Wang 			    uoff);
8602de3b87aSKai Wang #endif
8612de3b87aSKai Wang 			break;
8622de3b87aSKai Wang 		case DW_CFA_val_offset_sf:
8632de3b87aSKai Wang 			*row_pc = pc;
8642de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
8652de3b87aSKai Wang 			soff = _dwarf_decode_sleb128(&p);
8662de3b87aSKai Wang 			CHECK_TABLE_SIZE(reg);
8672de3b87aSKai Wang 			RL[reg].dw_offset_relevant = 1;
8682de3b87aSKai Wang 			RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET;
8692de3b87aSKai Wang 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
8702de3b87aSKai Wang 			RL[reg].dw_offset_or_block_len = soff * daf;
8712de3b87aSKai Wang #ifdef FRAME_DEBUG
8722de3b87aSKai Wang 			printf("DW_CFA_val_offset_sf(reg=%ju,soff=%jd)\n", reg,
8732de3b87aSKai Wang 			    soff);
8742de3b87aSKai Wang #endif
8752de3b87aSKai Wang 			break;
8762de3b87aSKai Wang 		case DW_CFA_val_expression:
8772de3b87aSKai Wang 			*row_pc = pc;
8782de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
8792de3b87aSKai Wang 			CHECK_TABLE_SIZE(reg);
8802de3b87aSKai Wang 			RL[reg].dw_offset_relevant = 0;
8812de3b87aSKai Wang 			RL[reg].dw_value_type = DW_EXPR_VAL_EXPRESSION;
8822de3b87aSKai Wang 			RL[reg].dw_offset_or_block_len =
8832de3b87aSKai Wang 			    _dwarf_decode_uleb128(&p);
8842de3b87aSKai Wang 			RL[reg].dw_block_ptr = p;
8852de3b87aSKai Wang 			p += RL[reg].dw_offset_or_block_len;
8862de3b87aSKai Wang #ifdef FRAME_DEBUG
8872de3b87aSKai Wang 			printf("DW_CFA_val_expression\n");
8882de3b87aSKai Wang #endif
8892de3b87aSKai Wang 			break;
8902de3b87aSKai Wang 		default:
8912de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error,
8922de3b87aSKai Wang 			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
8932de3b87aSKai Wang 			ret = DW_DLE_FRAME_INSTR_EXEC_ERROR;
8942de3b87aSKai Wang 			goto program_done;
8952de3b87aSKai Wang 		}
8962de3b87aSKai Wang 	}
8972de3b87aSKai Wang 
8982de3b87aSKai Wang program_done:
8992de3b87aSKai Wang 
9002de3b87aSKai Wang 	free(init_rt->rt3_rules);
9012de3b87aSKai Wang 	free(init_rt);
9022de3b87aSKai Wang 	if (saved_rt) {
9032de3b87aSKai Wang 		free(saved_rt->rt3_rules);
9042de3b87aSKai Wang 		free(saved_rt);
9052de3b87aSKai Wang 	}
9062de3b87aSKai Wang 
9072de3b87aSKai Wang 	return (ret);
9082de3b87aSKai Wang 
9092de3b87aSKai Wang #undef	CFA
9102de3b87aSKai Wang #undef	INITCFA
9112de3b87aSKai Wang #undef	RL
9122de3b87aSKai Wang #undef	INITRL
9132de3b87aSKai Wang #undef	CHECK_TABLE_SIZE
9142de3b87aSKai Wang }
9152de3b87aSKai Wang 
9162de3b87aSKai Wang static int
917cf781b2eSEd Maste _dwarf_frame_convert_inst(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts,
918cf781b2eSEd Maste     Dwarf_Unsigned len, Dwarf_Unsigned *count, Dwarf_Frame_Op *fop,
919cf781b2eSEd Maste     Dwarf_Frame_Op3 *fop3, Dwarf_Error *error)
9202de3b87aSKai Wang {
9212de3b87aSKai Wang 	uint8_t *p, *pe;
9222de3b87aSKai Wang 	uint8_t high2, low6;
9232de3b87aSKai Wang 	uint64_t reg, reg2, uoff, soff, blen;
9242de3b87aSKai Wang 
9252de3b87aSKai Wang #define	SET_BASE_OP(x)						\
9262de3b87aSKai Wang 	do {							\
9272de3b87aSKai Wang 		if (fop != NULL)				\
9282de3b87aSKai Wang 			fop[*count].fp_base_op = (x) >> 6;	\
9292de3b87aSKai Wang 		if (fop3 != NULL)				\
9302de3b87aSKai Wang 			fop3[*count].fp_base_op = (x) >> 6;	\
9312de3b87aSKai Wang 	} while(0)
9322de3b87aSKai Wang 
9332de3b87aSKai Wang #define	SET_EXTENDED_OP(x)					\
9342de3b87aSKai Wang 	do {							\
9352de3b87aSKai Wang 		if (fop != NULL)				\
9362de3b87aSKai Wang 			fop[*count].fp_extended_op = (x);	\
9372de3b87aSKai Wang 		if (fop3 != NULL)				\
9382de3b87aSKai Wang 			fop3[*count].fp_extended_op = (x);	\
9392de3b87aSKai Wang 	} while(0)
9402de3b87aSKai Wang 
9412de3b87aSKai Wang #define	SET_REGISTER(x)						\
9422de3b87aSKai Wang 	do {							\
9432de3b87aSKai Wang 		if (fop != NULL)				\
9442de3b87aSKai Wang 			fop[*count].fp_register = (x);		\
9452de3b87aSKai Wang 		if (fop3 != NULL)				\
9462de3b87aSKai Wang 			fop3[*count].fp_register = (x);		\
9472de3b87aSKai Wang 	} while(0)
9482de3b87aSKai Wang 
9492de3b87aSKai Wang #define	SET_OFFSET(x)						\
9502de3b87aSKai Wang 	do {							\
9512de3b87aSKai Wang 		if (fop != NULL)				\
9522de3b87aSKai Wang 			fop[*count].fp_offset = (x);		\
9532de3b87aSKai Wang 		if (fop3 != NULL)				\
9542de3b87aSKai Wang 			fop3[*count].fp_offset_or_block_len =	\
9552de3b87aSKai Wang 			    (x);				\
9562de3b87aSKai Wang 	} while(0)
9572de3b87aSKai Wang 
9582de3b87aSKai Wang #define	SET_INSTR_OFFSET(x)					\
9592de3b87aSKai Wang 	do {							\
9602de3b87aSKai Wang 		if (fop != NULL)				\
9612de3b87aSKai Wang 			fop[*count].fp_instr_offset = (x);	\
9622de3b87aSKai Wang 		if (fop3 != NULL)				\
9632de3b87aSKai Wang 			fop3[*count].fp_instr_offset = (x);	\
9642de3b87aSKai Wang 	} while(0)
9652de3b87aSKai Wang 
9662de3b87aSKai Wang #define	SET_BLOCK_LEN(x)					\
9672de3b87aSKai Wang 	do {							\
9682de3b87aSKai Wang 		if (fop3 != NULL)				\
9692de3b87aSKai Wang 			fop3[*count].fp_offset_or_block_len =	\
9702de3b87aSKai Wang 			    (x);				\
9712de3b87aSKai Wang 	} while(0)
9722de3b87aSKai Wang 
9732de3b87aSKai Wang #define	SET_EXPR_BLOCK(addr, len)					\
9742de3b87aSKai Wang 	do {								\
9752de3b87aSKai Wang 		if (fop3 != NULL) {					\
9762de3b87aSKai Wang 			fop3[*count].fp_expr_block =			\
9772de3b87aSKai Wang 			    malloc((size_t) (len));			\
9782de3b87aSKai Wang 			if (fop3[*count].fp_expr_block == NULL)	{	\
9792de3b87aSKai Wang 				DWARF_SET_ERROR(dbg, error,		\
9802de3b87aSKai Wang 				    DW_DLE_MEMORY);			\
9812de3b87aSKai Wang 				return (DW_DLE_MEMORY);			\
9822de3b87aSKai Wang 			}						\
9832de3b87aSKai Wang 			memcpy(&fop3[*count].fp_expr_block,		\
9842de3b87aSKai Wang 			    (addr), (len));				\
9852de3b87aSKai Wang 		}							\
9862de3b87aSKai Wang 	} while(0)
9872de3b87aSKai Wang 
9882de3b87aSKai Wang 	*count = 0;
9892de3b87aSKai Wang 
9902de3b87aSKai Wang 	p = insts;
9912de3b87aSKai Wang 	pe = p + len;
9922de3b87aSKai Wang 
9932de3b87aSKai Wang 	while (p < pe) {
9942de3b87aSKai Wang 
9952de3b87aSKai Wang 		SET_INSTR_OFFSET(p - insts);
9962de3b87aSKai Wang 
9972de3b87aSKai Wang 		if (*p == DW_CFA_nop) {
9982de3b87aSKai Wang 			p++;
9992de3b87aSKai Wang 			(*count)++;
10002de3b87aSKai Wang 			continue;
10012de3b87aSKai Wang 		}
10022de3b87aSKai Wang 
10032de3b87aSKai Wang 		high2 = *p & 0xc0;
10042de3b87aSKai Wang 		low6 = *p & 0x3f;
10052de3b87aSKai Wang 		p++;
10062de3b87aSKai Wang 
10072de3b87aSKai Wang 		if (high2 > 0) {
10082de3b87aSKai Wang 			switch (high2) {
10092de3b87aSKai Wang 			case DW_CFA_advance_loc:
10102de3b87aSKai Wang 				SET_BASE_OP(high2);
10112de3b87aSKai Wang 				SET_OFFSET(low6);
10122de3b87aSKai Wang 				break;
10132de3b87aSKai Wang 			case DW_CFA_offset:
10142de3b87aSKai Wang 				SET_BASE_OP(high2);
10152de3b87aSKai Wang 				SET_REGISTER(low6);
10162de3b87aSKai Wang 				uoff = _dwarf_decode_uleb128(&p);
10172de3b87aSKai Wang 				SET_OFFSET(uoff);
10182de3b87aSKai Wang 				break;
10192de3b87aSKai Wang 			case DW_CFA_restore:
10202de3b87aSKai Wang 				SET_BASE_OP(high2);
10212de3b87aSKai Wang 				SET_REGISTER(low6);
10222de3b87aSKai Wang 				break;
10232de3b87aSKai Wang 			default:
10242de3b87aSKai Wang 				DWARF_SET_ERROR(dbg, error,
10252de3b87aSKai Wang 				    DW_DLE_FRAME_INSTR_EXEC_ERROR);
10262de3b87aSKai Wang 				return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
10272de3b87aSKai Wang 			}
10282de3b87aSKai Wang 
10292de3b87aSKai Wang 			(*count)++;
10302de3b87aSKai Wang 			continue;
10312de3b87aSKai Wang 		}
10322de3b87aSKai Wang 
10332de3b87aSKai Wang 		SET_EXTENDED_OP(low6);
10342de3b87aSKai Wang 
10352de3b87aSKai Wang 		switch (low6) {
10362de3b87aSKai Wang 		case DW_CFA_set_loc:
1037cf781b2eSEd Maste 			uoff = dbg->decode(&p, addr_size);
10382de3b87aSKai Wang 			SET_OFFSET(uoff);
10392de3b87aSKai Wang 			break;
10402de3b87aSKai Wang 		case DW_CFA_advance_loc1:
10412de3b87aSKai Wang 			uoff = dbg->decode(&p, 1);
10422de3b87aSKai Wang 			SET_OFFSET(uoff);
10432de3b87aSKai Wang 			break;
10442de3b87aSKai Wang 		case DW_CFA_advance_loc2:
10452de3b87aSKai Wang 			uoff = dbg->decode(&p, 2);
10462de3b87aSKai Wang 			SET_OFFSET(uoff);
10472de3b87aSKai Wang 			break;
10482de3b87aSKai Wang 		case DW_CFA_advance_loc4:
10492de3b87aSKai Wang 			uoff = dbg->decode(&p, 4);
10502de3b87aSKai Wang 			SET_OFFSET(uoff);
10512de3b87aSKai Wang 			break;
10522de3b87aSKai Wang 		case DW_CFA_offset_extended:
10532de3b87aSKai Wang 		case DW_CFA_def_cfa:
10542de3b87aSKai Wang 		case DW_CFA_val_offset:
10552de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
10562de3b87aSKai Wang 			uoff = _dwarf_decode_uleb128(&p);
10572de3b87aSKai Wang 			SET_REGISTER(reg);
10582de3b87aSKai Wang 			SET_OFFSET(uoff);
10592de3b87aSKai Wang 			break;
10602de3b87aSKai Wang 		case DW_CFA_restore_extended:
10612de3b87aSKai Wang 		case DW_CFA_undefined:
10622de3b87aSKai Wang 		case DW_CFA_same_value:
10632de3b87aSKai Wang 		case DW_CFA_def_cfa_register:
10642de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
10652de3b87aSKai Wang 			SET_REGISTER(reg);
10662de3b87aSKai Wang 			break;
10672de3b87aSKai Wang 		case DW_CFA_register:
10682de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
10692de3b87aSKai Wang 			reg2 = _dwarf_decode_uleb128(&p);
10702de3b87aSKai Wang 			SET_REGISTER(reg);
10712de3b87aSKai Wang 			SET_OFFSET(reg2);
10722de3b87aSKai Wang 			break;
10732de3b87aSKai Wang 		case DW_CFA_remember_state:
10742de3b87aSKai Wang 		case DW_CFA_restore_state:
10752de3b87aSKai Wang 			break;
10762de3b87aSKai Wang 		case DW_CFA_def_cfa_offset:
10772de3b87aSKai Wang 			uoff = _dwarf_decode_uleb128(&p);
10782de3b87aSKai Wang 			SET_OFFSET(uoff);
10792de3b87aSKai Wang 			break;
10802de3b87aSKai Wang 		case DW_CFA_def_cfa_expression:
10812de3b87aSKai Wang 			blen = _dwarf_decode_uleb128(&p);
10822de3b87aSKai Wang 			SET_BLOCK_LEN(blen);
10832de3b87aSKai Wang 			SET_EXPR_BLOCK(p, blen);
10842de3b87aSKai Wang 			p += blen;
10852de3b87aSKai Wang 			break;
10862de3b87aSKai Wang 		case DW_CFA_expression:
10872de3b87aSKai Wang 		case DW_CFA_val_expression:
10882de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
10892de3b87aSKai Wang 			blen = _dwarf_decode_uleb128(&p);
10902de3b87aSKai Wang 			SET_REGISTER(reg);
10912de3b87aSKai Wang 			SET_BLOCK_LEN(blen);
10922de3b87aSKai Wang 			SET_EXPR_BLOCK(p, blen);
10932de3b87aSKai Wang 			p += blen;
10942de3b87aSKai Wang 			break;
10952de3b87aSKai Wang 		case DW_CFA_offset_extended_sf:
10962de3b87aSKai Wang 		case DW_CFA_def_cfa_sf:
10972de3b87aSKai Wang 		case DW_CFA_val_offset_sf:
10982de3b87aSKai Wang 			reg = _dwarf_decode_uleb128(&p);
10992de3b87aSKai Wang 			soff = _dwarf_decode_sleb128(&p);
11002de3b87aSKai Wang 			SET_REGISTER(reg);
11012de3b87aSKai Wang 			SET_OFFSET(soff);
11022de3b87aSKai Wang 			break;
11032de3b87aSKai Wang 		case DW_CFA_def_cfa_offset_sf:
11042de3b87aSKai Wang 			soff = _dwarf_decode_sleb128(&p);
11052de3b87aSKai Wang 			SET_OFFSET(soff);
11062de3b87aSKai Wang 			break;
11072de3b87aSKai Wang 		default:
11082de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error,
11092de3b87aSKai Wang 			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
11102de3b87aSKai Wang 			return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
11112de3b87aSKai Wang 		}
11122de3b87aSKai Wang 
11132de3b87aSKai Wang 		(*count)++;
11142de3b87aSKai Wang 	}
11152de3b87aSKai Wang 
11162de3b87aSKai Wang 	return (DW_DLE_NONE);
11172de3b87aSKai Wang }
11182de3b87aSKai Wang 
11192de3b87aSKai Wang int
1120cf781b2eSEd Maste _dwarf_frame_get_fop(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts,
1121cf781b2eSEd Maste     Dwarf_Unsigned len, Dwarf_Frame_Op **ret_oplist, Dwarf_Signed *ret_opcnt,
1122cf781b2eSEd Maste     Dwarf_Error *error)
11232de3b87aSKai Wang {
11242de3b87aSKai Wang 	Dwarf_Frame_Op *oplist;
11252de3b87aSKai Wang 	Dwarf_Unsigned count;
11262de3b87aSKai Wang 	int ret;
11272de3b87aSKai Wang 
1128cf781b2eSEd Maste 	ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count,
1129cf781b2eSEd Maste 	    NULL, NULL, error);
11302de3b87aSKai Wang 	if (ret != DW_DLE_NONE)
11312de3b87aSKai Wang 		return (ret);
11322de3b87aSKai Wang 
11332de3b87aSKai Wang 	if ((oplist = calloc(count, sizeof(Dwarf_Frame_Op))) == NULL) {
11342de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
11352de3b87aSKai Wang 		return (DW_DLE_MEMORY);
11362de3b87aSKai Wang 	}
11372de3b87aSKai Wang 
1138cf781b2eSEd Maste 	ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count,
1139cf781b2eSEd Maste 	    oplist, NULL, error);
11402de3b87aSKai Wang 	if (ret != DW_DLE_NONE) {
11412de3b87aSKai Wang 		free(oplist);
11422de3b87aSKai Wang 		return (ret);
11432de3b87aSKai Wang 	}
11442de3b87aSKai Wang 
11452de3b87aSKai Wang 	*ret_oplist = oplist;
11462de3b87aSKai Wang 	*ret_opcnt = count;
11472de3b87aSKai Wang 
11482de3b87aSKai Wang 	return (DW_DLE_NONE);
11492de3b87aSKai Wang }
11502de3b87aSKai Wang 
11512de3b87aSKai Wang int
11522de3b87aSKai Wang _dwarf_frame_regtable_copy(Dwarf_Debug dbg, Dwarf_Regtable3 **dest,
11532de3b87aSKai Wang     Dwarf_Regtable3 *src, Dwarf_Error *error)
11542de3b87aSKai Wang {
11552de3b87aSKai Wang 	int i;
11562de3b87aSKai Wang 
11572de3b87aSKai Wang 	assert(dest != NULL);
11582de3b87aSKai Wang 	assert(src != NULL);
11592de3b87aSKai Wang 
11602de3b87aSKai Wang 	if (*dest == NULL) {
11612de3b87aSKai Wang 		if ((*dest = malloc(sizeof(Dwarf_Regtable3))) == NULL) {
11622de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
11632de3b87aSKai Wang 			return (DW_DLE_MEMORY);
11642de3b87aSKai Wang 		}
11652de3b87aSKai Wang 		(*dest)->rt3_reg_table_size = src->rt3_reg_table_size;
11662de3b87aSKai Wang 		(*dest)->rt3_rules = malloc(src->rt3_reg_table_size *
11672de3b87aSKai Wang 		    sizeof(Dwarf_Regtable_Entry3));
11682de3b87aSKai Wang 		if ((*dest)->rt3_rules == NULL) {
11692de3b87aSKai Wang 			free(*dest);
11702de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
11712de3b87aSKai Wang 			return (DW_DLE_MEMORY);
11722de3b87aSKai Wang 		}
11732de3b87aSKai Wang 	}
11742de3b87aSKai Wang 
11752de3b87aSKai Wang 	memcpy(&(*dest)->rt3_cfa_rule, &src->rt3_cfa_rule,
11762de3b87aSKai Wang 	    sizeof(Dwarf_Regtable_Entry3));
11772de3b87aSKai Wang 
11782de3b87aSKai Wang 	for (i = 0; i < (*dest)->rt3_reg_table_size &&
11792de3b87aSKai Wang 	     i < src->rt3_reg_table_size; i++)
11802de3b87aSKai Wang 		memcpy(&(*dest)->rt3_rules[i], &src->rt3_rules[i],
11812de3b87aSKai Wang 		    sizeof(Dwarf_Regtable_Entry3));
11822de3b87aSKai Wang 
11832de3b87aSKai Wang 	for (; i < (*dest)->rt3_reg_table_size; i++)
11842de3b87aSKai Wang 		(*dest)->rt3_rules[i].dw_regnum =
11852de3b87aSKai Wang 		    dbg->dbg_frame_undefined_value;
11862de3b87aSKai Wang 
11872de3b87aSKai Wang 	return (DW_DLE_NONE);
11882de3b87aSKai Wang }
11892de3b87aSKai Wang 
11902de3b87aSKai Wang int
11912de3b87aSKai Wang _dwarf_frame_get_internal_table(Dwarf_Fde fde, Dwarf_Addr pc_req,
11922de3b87aSKai Wang     Dwarf_Regtable3 **ret_rt, Dwarf_Addr *ret_row_pc, Dwarf_Error *error)
11932de3b87aSKai Wang {
11942de3b87aSKai Wang 	Dwarf_Debug dbg;
11952de3b87aSKai Wang 	Dwarf_Cie cie;
11962de3b87aSKai Wang 	Dwarf_Regtable3 *rt;
11972de3b87aSKai Wang 	Dwarf_Addr row_pc;
11982de3b87aSKai Wang 	int i, ret;
11992de3b87aSKai Wang 
12002de3b87aSKai Wang 	assert(ret_rt != NULL);
12012de3b87aSKai Wang 
12022de3b87aSKai Wang 	dbg = fde->fde_dbg;
12032de3b87aSKai Wang 	assert(dbg != NULL);
12042de3b87aSKai Wang 
12052de3b87aSKai Wang 	rt = dbg->dbg_internal_reg_table;
12062de3b87aSKai Wang 
12072de3b87aSKai Wang 	/* Clear the content of regtable from previous run. */
12082de3b87aSKai Wang 	memset(&rt->rt3_cfa_rule, 0, sizeof(Dwarf_Regtable_Entry3));
12092de3b87aSKai Wang 	memset(rt->rt3_rules, 0, rt->rt3_reg_table_size *
12102de3b87aSKai Wang 	    sizeof(Dwarf_Regtable_Entry3));
12112de3b87aSKai Wang 
12122de3b87aSKai Wang 	/* Set rules to initial values. */
12132de3b87aSKai Wang 	for (i = 0; i < rt->rt3_reg_table_size; i++)
12142de3b87aSKai Wang 		rt->rt3_rules[i].dw_regnum = dbg->dbg_frame_rule_initial_value;
12152de3b87aSKai Wang 
12162de3b87aSKai Wang 	/* Run initial instructions in CIE. */
12172de3b87aSKai Wang 	cie = fde->fde_cie;
12182de3b87aSKai Wang 	assert(cie != NULL);
1219cf781b2eSEd Maste 	ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize,
1220cf781b2eSEd Maste 	    cie->cie_initinst, cie->cie_instlen, cie->cie_caf, cie->cie_daf, 0,
1221cf781b2eSEd Maste 	    ~0ULL, &row_pc, error);
12222de3b87aSKai Wang 	if (ret != DW_DLE_NONE)
12232de3b87aSKai Wang 		return (ret);
12242de3b87aSKai Wang 
12252de3b87aSKai Wang 	/* Run instructions in FDE. */
12262de3b87aSKai Wang 	if (pc_req >= fde->fde_initloc) {
1227cf781b2eSEd Maste 		ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize,
1228cf781b2eSEd Maste 		    fde->fde_inst, fde->fde_instlen, cie->cie_caf,
1229cf781b2eSEd Maste 		    cie->cie_daf, fde->fde_initloc, pc_req, &row_pc, error);
12302de3b87aSKai Wang 		if (ret != DW_DLE_NONE)
12312de3b87aSKai Wang 			return (ret);
12322de3b87aSKai Wang 	}
12332de3b87aSKai Wang 
12342de3b87aSKai Wang 	*ret_rt = rt;
12352de3b87aSKai Wang 	*ret_row_pc = row_pc;
12362de3b87aSKai Wang 
12372de3b87aSKai Wang 	return (DW_DLE_NONE);
12382de3b87aSKai Wang }
12392de3b87aSKai Wang 
12402de3b87aSKai Wang void
12412de3b87aSKai Wang _dwarf_frame_cleanup(Dwarf_Debug dbg)
12422de3b87aSKai Wang {
12432de3b87aSKai Wang 	Dwarf_Regtable3 *rt;
12442de3b87aSKai Wang 
12452de3b87aSKai Wang 	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ);
12462de3b87aSKai Wang 
12472de3b87aSKai Wang 	if (dbg->dbg_internal_reg_table) {
12482de3b87aSKai Wang 		rt = dbg->dbg_internal_reg_table;
12492de3b87aSKai Wang 		free(rt->rt3_rules);
12502de3b87aSKai Wang 		free(rt);
12512de3b87aSKai Wang 		dbg->dbg_internal_reg_table = NULL;
12522de3b87aSKai Wang 	}
12532de3b87aSKai Wang 
12542de3b87aSKai Wang 	if (dbg->dbg_frame) {
12552de3b87aSKai Wang 		_dwarf_frame_section_cleanup(dbg->dbg_frame);
12562de3b87aSKai Wang 		dbg->dbg_frame = NULL;
12572de3b87aSKai Wang 	}
12582de3b87aSKai Wang 
12592de3b87aSKai Wang 	if (dbg->dbg_eh_frame) {
12602de3b87aSKai Wang 		_dwarf_frame_section_cleanup(dbg->dbg_eh_frame);
12612de3b87aSKai Wang 		dbg->dbg_eh_frame = NULL;
12622de3b87aSKai Wang 	}
12632de3b87aSKai Wang }
12642de3b87aSKai Wang 
12652de3b87aSKai Wang int
12662de3b87aSKai Wang _dwarf_frame_section_load(Dwarf_Debug dbg, Dwarf_Error *error)
12672de3b87aSKai Wang {
12682de3b87aSKai Wang 	Dwarf_Section *ds;
12692de3b87aSKai Wang 
12702de3b87aSKai Wang 	if ((ds = _dwarf_find_section(dbg, ".debug_frame")) != NULL) {
12712de3b87aSKai Wang 		return (_dwarf_frame_section_init(dbg, &dbg->dbg_frame,
12722de3b87aSKai Wang 		    ds, 0, error));
12732de3b87aSKai Wang 	}
12742de3b87aSKai Wang 
12752de3b87aSKai Wang 	return (DW_DLE_NONE);
12762de3b87aSKai Wang }
12772de3b87aSKai Wang 
12782de3b87aSKai Wang int
12792de3b87aSKai Wang _dwarf_frame_section_load_eh(Dwarf_Debug dbg, Dwarf_Error *error)
12802de3b87aSKai Wang {
12812de3b87aSKai Wang 	Dwarf_Section *ds;
12822de3b87aSKai Wang 
12832de3b87aSKai Wang 	if ((ds = _dwarf_find_section(dbg, ".eh_frame")) != NULL) {
12842de3b87aSKai Wang 		return (_dwarf_frame_section_init(dbg, &dbg->dbg_eh_frame,
12852de3b87aSKai Wang 		    ds, 1, error));
12862de3b87aSKai Wang 	}
12872de3b87aSKai Wang 
12882de3b87aSKai Wang 	return (DW_DLE_NONE);
12892de3b87aSKai Wang }
12902de3b87aSKai Wang 
12912de3b87aSKai Wang void
12922de3b87aSKai Wang _dwarf_frame_params_init(Dwarf_Debug dbg)
12932de3b87aSKai Wang {
12942de3b87aSKai Wang 
12952de3b87aSKai Wang 	/* Initialise call frame related parameters. */
12962de3b87aSKai Wang 	dbg->dbg_frame_rule_table_size = DW_FRAME_LAST_REG_NUM;
12972de3b87aSKai Wang 	dbg->dbg_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE;
12982de3b87aSKai Wang 	dbg->dbg_frame_cfa_value = DW_FRAME_CFA_COL3;
12992de3b87aSKai Wang 	dbg->dbg_frame_same_value = DW_FRAME_SAME_VAL;
13002de3b87aSKai Wang 	dbg->dbg_frame_undefined_value = DW_FRAME_UNDEFINED_VAL;
13012de3b87aSKai Wang }
13022de3b87aSKai Wang 
13032de3b87aSKai Wang int
13042de3b87aSKai Wang _dwarf_frame_interal_table_init(Dwarf_Debug dbg, Dwarf_Error *error)
13052de3b87aSKai Wang {
13062de3b87aSKai Wang 	Dwarf_Regtable3 *rt;
13072de3b87aSKai Wang 
13082de3b87aSKai Wang 	if (dbg->dbg_internal_reg_table != NULL)
13092de3b87aSKai Wang 		return (DW_DLE_NONE);
13102de3b87aSKai Wang 
13112de3b87aSKai Wang 	/* Initialise internal register table. */
13122de3b87aSKai Wang 	if ((rt = calloc(1, sizeof(Dwarf_Regtable3))) == NULL) {
13132de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
13142de3b87aSKai Wang 		return (DW_DLE_MEMORY);
13152de3b87aSKai Wang 	}
13162de3b87aSKai Wang 
13172de3b87aSKai Wang 	rt->rt3_reg_table_size = dbg->dbg_frame_rule_table_size;
13182de3b87aSKai Wang 	if ((rt->rt3_rules = calloc(rt->rt3_reg_table_size,
13192de3b87aSKai Wang 	    sizeof(Dwarf_Regtable_Entry3))) == NULL) {
13202de3b87aSKai Wang 		free(rt);
13212de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
13222de3b87aSKai Wang 		return (DW_DLE_MEMORY);
13232de3b87aSKai Wang 	}
13242de3b87aSKai Wang 
13252de3b87aSKai Wang 	dbg->dbg_internal_reg_table = rt;
13262de3b87aSKai Wang 
13272de3b87aSKai Wang 	return (DW_DLE_NONE);
13282de3b87aSKai Wang }
13292de3b87aSKai Wang 
13302de3b87aSKai Wang #define	_FDE_INST_INIT_SIZE	128
13312de3b87aSKai Wang 
13322de3b87aSKai Wang int
13332de3b87aSKai Wang _dwarf_frame_fde_add_inst(Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1,
13342de3b87aSKai Wang     Dwarf_Unsigned val2, Dwarf_Error *error)
13352de3b87aSKai Wang {
13362de3b87aSKai Wang 	Dwarf_P_Debug dbg;
13372de3b87aSKai Wang 	uint8_t high2, low6;
13382de3b87aSKai Wang 	int ret;
13392de3b87aSKai Wang 
13402de3b87aSKai Wang #define	ds	fde
13412de3b87aSKai Wang #define	ds_data	fde_inst
13422de3b87aSKai Wang #define	ds_cap	fde_instcap
13432de3b87aSKai Wang #define	ds_size	fde_instlen
13442de3b87aSKai Wang 
13452de3b87aSKai Wang 	assert(fde != NULL && fde->fde_dbg != NULL);
13462de3b87aSKai Wang 	dbg = fde->fde_dbg;
13472de3b87aSKai Wang 
13482de3b87aSKai Wang 	if (fde->fde_inst == NULL) {
13492de3b87aSKai Wang 		fde->fde_instcap = _FDE_INST_INIT_SIZE;
13502de3b87aSKai Wang 		fde->fde_instlen = 0;
13512de3b87aSKai Wang 		if ((fde->fde_inst = malloc((size_t) fde->fde_instcap)) ==
13522de3b87aSKai Wang 		    NULL) {
13532de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
13542de3b87aSKai Wang 			return (DW_DLE_MEMORY);
13552de3b87aSKai Wang 		}
13562de3b87aSKai Wang 	}
13572de3b87aSKai Wang 	assert(fde->fde_instcap != 0);
13582de3b87aSKai Wang 
13592de3b87aSKai Wang 	RCHECK(WRITE_VALUE(op, 1));
13602de3b87aSKai Wang 	if (op == DW_CFA_nop)
13612de3b87aSKai Wang 		return (DW_DLE_NONE);
13622de3b87aSKai Wang 
13632de3b87aSKai Wang 	high2 = op & 0xc0;
13642de3b87aSKai Wang 	low6 = op & 0x3f;
13652de3b87aSKai Wang 
13662de3b87aSKai Wang 	if (high2 > 0) {
13672de3b87aSKai Wang 		switch (high2) {
13682de3b87aSKai Wang 		case DW_CFA_advance_loc:
13692de3b87aSKai Wang 		case DW_CFA_restore:
13702de3b87aSKai Wang 			break;
13712de3b87aSKai Wang 		case DW_CFA_offset:
13722de3b87aSKai Wang 			RCHECK(WRITE_ULEB128(val1));
13732de3b87aSKai Wang 			break;
13742de3b87aSKai Wang 		default:
13752de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error,
13762de3b87aSKai Wang 			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
13772de3b87aSKai Wang 			return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
13782de3b87aSKai Wang 		}
13792de3b87aSKai Wang 		return (DW_DLE_NONE);
13802de3b87aSKai Wang 	}
13812de3b87aSKai Wang 
13822de3b87aSKai Wang 	switch (low6) {
13832de3b87aSKai Wang 	case DW_CFA_set_loc:
13842de3b87aSKai Wang 		RCHECK(WRITE_VALUE(val1, dbg->dbg_pointer_size));
13852de3b87aSKai Wang 		break;
13862de3b87aSKai Wang 	case DW_CFA_advance_loc1:
13872de3b87aSKai Wang 		RCHECK(WRITE_VALUE(val1, 1));
13882de3b87aSKai Wang 		break;
13892de3b87aSKai Wang 	case DW_CFA_advance_loc2:
13902de3b87aSKai Wang 		RCHECK(WRITE_VALUE(val1, 2));
13912de3b87aSKai Wang 		break;
13922de3b87aSKai Wang 	case DW_CFA_advance_loc4:
13932de3b87aSKai Wang 		RCHECK(WRITE_VALUE(val1, 4));
13942de3b87aSKai Wang 		break;
13952de3b87aSKai Wang 	case DW_CFA_offset_extended:
13962de3b87aSKai Wang 	case DW_CFA_def_cfa:
13972de3b87aSKai Wang 	case DW_CFA_register:
13982de3b87aSKai Wang 		RCHECK(WRITE_ULEB128(val1));
13992de3b87aSKai Wang 		RCHECK(WRITE_ULEB128(val2));
14002de3b87aSKai Wang 		break;
14012de3b87aSKai Wang 	case DW_CFA_restore_extended:
14022de3b87aSKai Wang 	case DW_CFA_undefined:
14032de3b87aSKai Wang 	case DW_CFA_same_value:
14042de3b87aSKai Wang 	case DW_CFA_def_cfa_register:
14052de3b87aSKai Wang 	case DW_CFA_def_cfa_offset:
14062de3b87aSKai Wang 		RCHECK(WRITE_ULEB128(val1));
14072de3b87aSKai Wang 		break;
14082de3b87aSKai Wang 	case DW_CFA_remember_state:
14092de3b87aSKai Wang 	case DW_CFA_restore_state:
14102de3b87aSKai Wang 		break;
14112de3b87aSKai Wang 	default:
14122de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR);
14132de3b87aSKai Wang 		return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
14142de3b87aSKai Wang 	}
14152de3b87aSKai Wang 
14162de3b87aSKai Wang 	return (DW_DLE_NONE);
14172de3b87aSKai Wang 
14182de3b87aSKai Wang gen_fail:
14192de3b87aSKai Wang 	return (ret);
14202de3b87aSKai Wang 
14212de3b87aSKai Wang #undef	ds
14222de3b87aSKai Wang #undef	ds_data
14232de3b87aSKai Wang #undef	ds_cap
14242de3b87aSKai Wang #undef	ds_size
14252de3b87aSKai Wang }
14262de3b87aSKai Wang 
14272de3b87aSKai Wang static int
14282de3b87aSKai Wang _dwarf_frame_gen_cie(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_P_Cie cie,
14292de3b87aSKai Wang     Dwarf_Error *error)
14302de3b87aSKai Wang {
14312de3b87aSKai Wang 	Dwarf_Unsigned len;
14322de3b87aSKai Wang 	uint64_t offset;
14332de3b87aSKai Wang 	int ret;
14342de3b87aSKai Wang 
14352de3b87aSKai Wang 	assert(dbg != NULL && ds != NULL && cie != NULL);
14362de3b87aSKai Wang 
14372de3b87aSKai Wang 	cie->cie_offset = offset = ds->ds_size;
14382de3b87aSKai Wang 	cie->cie_length = 0;
14392de3b87aSKai Wang 	cie->cie_version = 1;
14402de3b87aSKai Wang 
14412de3b87aSKai Wang 	/* Length placeholder. */
14422de3b87aSKai Wang 	RCHECK(WRITE_VALUE(cie->cie_length, 4));
14432de3b87aSKai Wang 
14442de3b87aSKai Wang 	/* .debug_frame use CIE id ~0. */
14452de3b87aSKai Wang 	RCHECK(WRITE_VALUE(~0U, 4));
14462de3b87aSKai Wang 
14472de3b87aSKai Wang 	/* .debug_frame version is 1. (DWARF2) */
14482de3b87aSKai Wang 	RCHECK(WRITE_VALUE(cie->cie_version, 1));
14492de3b87aSKai Wang 
14502de3b87aSKai Wang 	/* Write augmentation, if present. */
14512de3b87aSKai Wang 	if (cie->cie_augment != NULL)
14522de3b87aSKai Wang 		RCHECK(WRITE_BLOCK(cie->cie_augment,
14532de3b87aSKai Wang 		    strlen((char *) cie->cie_augment) + 1));
14542de3b87aSKai Wang 	else
14552de3b87aSKai Wang 		RCHECK(WRITE_VALUE(0, 1));
14562de3b87aSKai Wang 
14572de3b87aSKai Wang 	/* Write caf, daf and ra. */
14582de3b87aSKai Wang 	RCHECK(WRITE_ULEB128(cie->cie_caf));
14592de3b87aSKai Wang 	RCHECK(WRITE_SLEB128(cie->cie_daf));
14602de3b87aSKai Wang 	RCHECK(WRITE_VALUE(cie->cie_ra, 1));
14612de3b87aSKai Wang 
14622de3b87aSKai Wang 	/* Write initial instructions, if present. */
14632de3b87aSKai Wang 	if (cie->cie_initinst != NULL)
14642de3b87aSKai Wang 		RCHECK(WRITE_BLOCK(cie->cie_initinst, cie->cie_instlen));
14652de3b87aSKai Wang 
14662de3b87aSKai Wang 	/* Add padding. */
14672de3b87aSKai Wang 	len = ds->ds_size - cie->cie_offset - 4;
14682de3b87aSKai Wang 	cie->cie_length = roundup(len, dbg->dbg_pointer_size);
14692de3b87aSKai Wang 	while (len++ < cie->cie_length)
14702de3b87aSKai Wang 		RCHECK(WRITE_VALUE(DW_CFA_nop, 1));
14712de3b87aSKai Wang 
14722de3b87aSKai Wang 	/* Fill in the length field. */
14732de3b87aSKai Wang 	dbg->write(ds->ds_data, &offset, cie->cie_length, 4);
14742de3b87aSKai Wang 
14752de3b87aSKai Wang 	return (DW_DLE_NONE);
14762de3b87aSKai Wang 
14772de3b87aSKai Wang gen_fail:
14782de3b87aSKai Wang 	return (ret);
14792de3b87aSKai Wang }
14802de3b87aSKai Wang 
14812de3b87aSKai Wang static int
14822de3b87aSKai Wang _dwarf_frame_gen_fde(Dwarf_P_Debug dbg, Dwarf_P_Section ds,
14832de3b87aSKai Wang     Dwarf_Rel_Section drs, Dwarf_P_Fde fde, Dwarf_Error *error)
14842de3b87aSKai Wang {
14852de3b87aSKai Wang 	Dwarf_Unsigned len;
14862de3b87aSKai Wang 	uint64_t offset;
14872de3b87aSKai Wang 	int ret;
14882de3b87aSKai Wang 
14892de3b87aSKai Wang 	assert(dbg != NULL && ds != NULL && drs != NULL);
14902de3b87aSKai Wang 	assert(fde != NULL && fde->fde_cie != NULL);
14912de3b87aSKai Wang 
14922de3b87aSKai Wang 	fde->fde_offset = offset = ds->ds_size;
14932de3b87aSKai Wang 	fde->fde_length = 0;
14942de3b87aSKai Wang 	fde->fde_cieoff = fde->fde_cie->cie_offset;
14952de3b87aSKai Wang 
14962de3b87aSKai Wang 	/* Length placeholder. */
14972de3b87aSKai Wang 	RCHECK(WRITE_VALUE(fde->fde_length, 4));
14982de3b87aSKai Wang 
14992de3b87aSKai Wang 	/* Write CIE pointer. */
15002de3b87aSKai Wang 	RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4,
15012de3b87aSKai Wang 	    ds->ds_size, 0, fde->fde_cieoff, ".debug_frame", error));
15022de3b87aSKai Wang 
15032de3b87aSKai Wang 	/* Write FDE initial location. */
15042de3b87aSKai Wang 	RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc,
15052de3b87aSKai Wang 	    dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx,
15062de3b87aSKai Wang 	    fde->fde_initloc, NULL, error));
15072de3b87aSKai Wang 
15082de3b87aSKai Wang 	/*
15092de3b87aSKai Wang 	 * Write FDE address range. Use a pair of relocation entries if
15102de3b87aSKai Wang 	 * application provided end symbol index. Otherwise write the
15112de3b87aSKai Wang 	 * length without assoicating any relocation info.
15122de3b87aSKai Wang 	 */
15132de3b87aSKai Wang 	if (fde->fde_esymndx > 0)
15142de3b87aSKai Wang 		RCHECK(_dwarf_reloc_entry_add_pair(dbg, drs, ds,
15152de3b87aSKai Wang 		    dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx,
15162de3b87aSKai Wang 		    fde->fde_esymndx, fde->fde_initloc, fde->fde_eoff, error));
15172de3b87aSKai Wang 	else
15182de3b87aSKai Wang 		RCHECK(WRITE_VALUE(fde->fde_adrange, dbg->dbg_pointer_size));
15192de3b87aSKai Wang 
15202de3b87aSKai Wang 	/* Write FDE frame instructions. */
15212de3b87aSKai Wang 	RCHECK(WRITE_BLOCK(fde->fde_inst, fde->fde_instlen));
15222de3b87aSKai Wang 
15232de3b87aSKai Wang 	/* Add padding. */
15242de3b87aSKai Wang 	len = ds->ds_size - fde->fde_offset - 4;
15252de3b87aSKai Wang 	fde->fde_length = roundup(len, dbg->dbg_pointer_size);
15262de3b87aSKai Wang 	while (len++ < fde->fde_length)
15272de3b87aSKai Wang 		RCHECK(WRITE_VALUE(DW_CFA_nop, 1));
15282de3b87aSKai Wang 
15292de3b87aSKai Wang 	/* Fill in the length field. */
15302de3b87aSKai Wang 	dbg->write(ds->ds_data, &offset, fde->fde_length, 4);
15312de3b87aSKai Wang 
15322de3b87aSKai Wang 	return (DW_DLE_NONE);
15332de3b87aSKai Wang 
15342de3b87aSKai Wang gen_fail:
15352de3b87aSKai Wang 	return (ret);
15362de3b87aSKai Wang }
15372de3b87aSKai Wang 
15382de3b87aSKai Wang int
15392de3b87aSKai Wang _dwarf_frame_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
15402de3b87aSKai Wang {
15412de3b87aSKai Wang 	Dwarf_P_Section ds;
15422de3b87aSKai Wang 	Dwarf_Rel_Section drs;
15432de3b87aSKai Wang 	Dwarf_P_Cie cie;
15442de3b87aSKai Wang 	Dwarf_P_Fde fde;
15452de3b87aSKai Wang 	int ret;
15462de3b87aSKai Wang 
15472de3b87aSKai Wang 	if (STAILQ_EMPTY(&dbg->dbgp_cielist))
15482de3b87aSKai Wang 		return (DW_DLE_NONE);
15492de3b87aSKai Wang 
15502de3b87aSKai Wang 	/* Create .debug_frame section. */
15512de3b87aSKai Wang 	if ((ret = _dwarf_section_init(dbg, &ds, ".debug_frame", 0, error)) !=
15522de3b87aSKai Wang 	    DW_DLE_NONE)
15532de3b87aSKai Wang 		goto gen_fail0;
15542de3b87aSKai Wang 
15552de3b87aSKai Wang 	/* Create relocation section for .debug_frame */
15562de3b87aSKai Wang 	RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error));
15572de3b87aSKai Wang 
15582de3b87aSKai Wang 	/* Generate list of CIE. */
15592de3b87aSKai Wang 	STAILQ_FOREACH(cie, &dbg->dbgp_cielist, cie_next)
15602de3b87aSKai Wang 		RCHECK(_dwarf_frame_gen_cie(dbg, ds, cie, error));
15612de3b87aSKai Wang 
15622de3b87aSKai Wang 	/* Generate list of FDE. */
15632de3b87aSKai Wang 	STAILQ_FOREACH(fde, &dbg->dbgp_fdelist, fde_next)
15642de3b87aSKai Wang 		RCHECK(_dwarf_frame_gen_fde(dbg, ds, drs, fde, error));
15652de3b87aSKai Wang 
15662de3b87aSKai Wang 	/* Inform application the creation of .debug_frame ELF section. */
15672de3b87aSKai Wang 	RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
15682de3b87aSKai Wang 
15692de3b87aSKai Wang 	/* Finalize relocation section for .debug_frame */
15702de3b87aSKai Wang 	RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
15712de3b87aSKai Wang 
15722de3b87aSKai Wang 	return (DW_DLE_NONE);
15732de3b87aSKai Wang 
15742de3b87aSKai Wang gen_fail:
15752de3b87aSKai Wang 	_dwarf_reloc_section_free(dbg, &drs);
15762de3b87aSKai Wang 
15772de3b87aSKai Wang gen_fail0:
15782de3b87aSKai Wang 	_dwarf_section_free(dbg, &ds);
15792de3b87aSKai Wang 
15802de3b87aSKai Wang 	return (ret);
15812de3b87aSKai Wang }
15822de3b87aSKai Wang 
15832de3b87aSKai Wang void
15842de3b87aSKai Wang _dwarf_frame_pro_cleanup(Dwarf_P_Debug dbg)
15852de3b87aSKai Wang {
15862de3b87aSKai Wang 	Dwarf_P_Cie cie, tcie;
15872de3b87aSKai Wang 	Dwarf_P_Fde fde, tfde;
15882de3b87aSKai Wang 
15892de3b87aSKai Wang 	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
15902de3b87aSKai Wang 
15912de3b87aSKai Wang 	STAILQ_FOREACH_SAFE(cie, &dbg->dbgp_cielist, cie_next, tcie) {
15922de3b87aSKai Wang 		STAILQ_REMOVE(&dbg->dbgp_cielist, cie, _Dwarf_Cie, cie_next);
15932de3b87aSKai Wang 		if (cie->cie_augment)
15942de3b87aSKai Wang 			free(cie->cie_augment);
15952de3b87aSKai Wang 		if (cie->cie_initinst)
15962de3b87aSKai Wang 			free(cie->cie_initinst);
15972de3b87aSKai Wang 		free(cie);
15982de3b87aSKai Wang 	}
15992de3b87aSKai Wang 	dbg->dbgp_cielen = 0;
16002de3b87aSKai Wang 
16012de3b87aSKai Wang 	STAILQ_FOREACH_SAFE(fde, &dbg->dbgp_fdelist, fde_next, tfde) {
16022de3b87aSKai Wang 		STAILQ_REMOVE(&dbg->dbgp_fdelist, fde, _Dwarf_Fde, fde_next);
16032de3b87aSKai Wang 		if (fde->fde_inst != NULL)
16042de3b87aSKai Wang 			free(fde->fde_inst);
16052de3b87aSKai Wang 		free(fde);
16062de3b87aSKai Wang 	}
16072de3b87aSKai Wang 	dbg->dbgp_fdelen = 0;
16082de3b87aSKai Wang }
1609