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