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
_dwarf_frame_find_cie(Dwarf_FrameSec fs,Dwarf_Unsigned offset,Dwarf_Cie * ret_cie)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
_dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg,Dwarf_Cie cie,uint64_t * val,uint8_t * data,uint64_t * offsetp,uint8_t encode,Dwarf_Addr pc,Dwarf_Error * error)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
_dwarf_frame_parse_lsb_cie_augment(Dwarf_Debug dbg,Dwarf_Cie cie,Dwarf_Error * error)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
_dwarf_frame_add_cie(Dwarf_Debug dbg,Dwarf_FrameSec fs,Dwarf_Section * ds,Dwarf_Unsigned * off,Dwarf_Cie * ret_cie,Dwarf_Error * error)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
_dwarf_frame_add_fde(Dwarf_Debug dbg,Dwarf_FrameSec fs,Dwarf_Section * ds,Dwarf_Unsigned * off,int eh_frame,Dwarf_Error * error)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
_dwarf_frame_section_cleanup(Dwarf_FrameSec fs)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
_dwarf_frame_section_init(Dwarf_Debug dbg,Dwarf_FrameSec * frame_sec,Dwarf_Section * ds,int eh_frame,Dwarf_Error * error)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
_dwarf_frame_run_inst(Dwarf_Debug dbg,Dwarf_Regtable3 * rt,uint8_t addr_size,uint8_t * insts,Dwarf_Unsigned len,Dwarf_Unsigned caf,Dwarf_Signed daf,Dwarf_Addr pc,Dwarf_Addr pc_req,Dwarf_Addr * row_pc,Dwarf_Error * error)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
_dwarf_frame_convert_inst(Dwarf_Debug dbg,uint8_t addr_size,uint8_t * insts,Dwarf_Unsigned len,Dwarf_Unsigned * count,Dwarf_Frame_Op * fop,Dwarf_Frame_Op3 * fop3,Dwarf_Error * error)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
_dwarf_frame_get_fop(Dwarf_Debug dbg,uint8_t addr_size,uint8_t * insts,Dwarf_Unsigned len,Dwarf_Frame_Op ** ret_oplist,Dwarf_Signed * ret_opcnt,Dwarf_Error * error)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
_dwarf_frame_regtable_copy(Dwarf_Debug dbg,Dwarf_Regtable3 ** dest,Dwarf_Regtable3 * src,Dwarf_Error * error)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
_dwarf_frame_get_internal_table(Dwarf_Fde fde,Dwarf_Addr pc_req,Dwarf_Regtable3 ** ret_rt,Dwarf_Addr * ret_row_pc,Dwarf_Error * error)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
_dwarf_frame_cleanup(Dwarf_Debug dbg)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
_dwarf_frame_section_load(Dwarf_Debug dbg,Dwarf_Error * error)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
_dwarf_frame_section_load_eh(Dwarf_Debug dbg,Dwarf_Error * error)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
_dwarf_frame_params_init(Dwarf_Debug dbg)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
_dwarf_frame_interal_table_init(Dwarf_Debug dbg,Dwarf_Error * error)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
_dwarf_frame_fde_add_inst(Dwarf_P_Fde fde,Dwarf_Small op,Dwarf_Unsigned val1,Dwarf_Unsigned val2,Dwarf_Error * error)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
_dwarf_frame_gen_cie(Dwarf_P_Debug dbg,Dwarf_P_Section ds,Dwarf_P_Cie cie,Dwarf_Error * error)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
_dwarf_frame_gen_fde(Dwarf_P_Debug dbg,Dwarf_P_Section ds,Dwarf_Rel_Section drs,Dwarf_P_Fde fde,Dwarf_Error * error)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
_dwarf_frame_gen(Dwarf_P_Debug dbg,Dwarf_Error * error)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
_dwarf_frame_pro_cleanup(Dwarf_P_Debug dbg)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