1260684Skaiw/*- 2276371Semaste * Copyright (c) 2009-2011,2014 Kai Wang 3260684Skaiw * All rights reserved. 4260684Skaiw * 5260684Skaiw * Redistribution and use in source and binary forms, with or without 6260684Skaiw * modification, are permitted provided that the following conditions 7260684Skaiw * are met: 8260684Skaiw * 1. Redistributions of source code must retain the above copyright 9260684Skaiw * notice, this list of conditions and the following disclaimer. 10260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright 11260684Skaiw * notice, this list of conditions and the following disclaimer in the 12260684Skaiw * documentation and/or other materials provided with the distribution. 13260684Skaiw * 14260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15260684Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16260684Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17260684Skaiw * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18260684Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19260684Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20260684Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21260684Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22260684Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23260684Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24260684Skaiw * SUCH DAMAGE. 25260684Skaiw */ 26260684Skaiw 27260684Skaiw#include "_libdwarf.h" 28260684Skaiw 29338414SemasteELFTC_VCSID("$Id: libdwarf_frame.c 3589 2018-03-13 20:34:33Z kaiwang27 $"); 30260684Skaiw 31260684Skaiwstatic int 32260684Skaiw_dwarf_frame_find_cie(Dwarf_FrameSec fs, Dwarf_Unsigned offset, 33260684Skaiw Dwarf_Cie *ret_cie) 34260684Skaiw{ 35260684Skaiw Dwarf_Cie cie; 36260684Skaiw 37260684Skaiw STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) { 38260684Skaiw if (cie->cie_offset == offset) 39260684Skaiw break; 40260684Skaiw } 41260684Skaiw 42260684Skaiw if (cie == NULL) 43260684Skaiw return (DW_DLE_NO_ENTRY); 44260684Skaiw 45260684Skaiw if (ret_cie != NULL) 46260684Skaiw *ret_cie = cie; 47260684Skaiw 48260684Skaiw return (DW_DLE_NONE); 49260684Skaiw} 50260684Skaiw 51260684Skaiwstatic int 52276371Semaste_dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg, Dwarf_Cie cie, uint64_t *val, 53276371Semaste uint8_t *data, uint64_t *offsetp, uint8_t encode, Dwarf_Addr pc, 54276371Semaste Dwarf_Error *error) 55260684Skaiw{ 56260684Skaiw uint8_t application; 57260684Skaiw 58260684Skaiw if (encode == DW_EH_PE_omit) 59260684Skaiw return (DW_DLE_NONE); 60260684Skaiw 61260684Skaiw application = encode & 0xf0; 62260684Skaiw encode &= 0x0f; 63260684Skaiw 64260684Skaiw switch (encode) { 65260684Skaiw case DW_EH_PE_absptr: 66276371Semaste *val = dbg->read(data, offsetp, cie->cie_addrsize); 67260684Skaiw break; 68260684Skaiw case DW_EH_PE_uleb128: 69260684Skaiw *val = _dwarf_read_uleb128(data, offsetp); 70260684Skaiw break; 71260684Skaiw case DW_EH_PE_udata2: 72260684Skaiw *val = dbg->read(data, offsetp, 2); 73260684Skaiw break; 74260684Skaiw case DW_EH_PE_udata4: 75260684Skaiw *val = dbg->read(data, offsetp, 4); 76260684Skaiw break; 77260684Skaiw case DW_EH_PE_udata8: 78260684Skaiw *val = dbg->read(data, offsetp, 8); 79260684Skaiw break; 80260684Skaiw case DW_EH_PE_sleb128: 81260684Skaiw *val = _dwarf_read_sleb128(data, offsetp); 82260684Skaiw break; 83260684Skaiw case DW_EH_PE_sdata2: 84260684Skaiw *val = (int16_t) dbg->read(data, offsetp, 2); 85260684Skaiw break; 86260684Skaiw case DW_EH_PE_sdata4: 87260684Skaiw *val = (int32_t) dbg->read(data, offsetp, 4); 88260684Skaiw break; 89260684Skaiw case DW_EH_PE_sdata8: 90260684Skaiw *val = dbg->read(data, offsetp, 8); 91260684Skaiw break; 92260684Skaiw default: 93260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN); 94260684Skaiw return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN); 95260684Skaiw } 96260684Skaiw 97260684Skaiw if (application == DW_EH_PE_pcrel) { 98260684Skaiw /* 99260684Skaiw * Value is relative to .eh_frame section virtual addr. 100260684Skaiw */ 101260684Skaiw switch (encode) { 102260684Skaiw case DW_EH_PE_uleb128: 103260684Skaiw case DW_EH_PE_udata2: 104260684Skaiw case DW_EH_PE_udata4: 105260684Skaiw case DW_EH_PE_udata8: 106260684Skaiw *val += pc; 107260684Skaiw break; 108260684Skaiw case DW_EH_PE_sleb128: 109260684Skaiw case DW_EH_PE_sdata2: 110260684Skaiw case DW_EH_PE_sdata4: 111260684Skaiw case DW_EH_PE_sdata8: 112260684Skaiw *val = pc + (int64_t) *val; 113260684Skaiw break; 114260684Skaiw default: 115260684Skaiw /* DW_EH_PE_absptr is absolute value. */ 116260684Skaiw break; 117260684Skaiw } 118260684Skaiw } 119260684Skaiw 120260684Skaiw /* XXX Applications other than DW_EH_PE_pcrel are not handled. */ 121260684Skaiw 122260684Skaiw return (DW_DLE_NONE); 123260684Skaiw} 124260684Skaiw 125260684Skaiwstatic int 126260684Skaiw_dwarf_frame_parse_lsb_cie_augment(Dwarf_Debug dbg, Dwarf_Cie cie, 127260684Skaiw Dwarf_Error *error) 128260684Skaiw{ 129260684Skaiw uint8_t *aug_p, *augdata_p; 130260684Skaiw uint64_t val, offset; 131260684Skaiw uint8_t encode; 132260684Skaiw int ret; 133260684Skaiw 134260684Skaiw assert(cie->cie_augment != NULL && *cie->cie_augment == 'z'); 135260684Skaiw 136260684Skaiw /* 137260684Skaiw * Here we're only interested in the presence of augment 'R' 138260684Skaiw * and associated CIE augment data, which describes the 139260684Skaiw * encoding scheme of FDE PC begin and range. 140260684Skaiw */ 141260684Skaiw aug_p = &cie->cie_augment[1]; 142260684Skaiw augdata_p = cie->cie_augdata; 143260684Skaiw while (*aug_p != '\0') { 144260684Skaiw switch (*aug_p) { 145338414Semaste case 'S': 146338414Semaste break; 147260684Skaiw case 'L': 148260684Skaiw /* Skip one augment in augment data. */ 149260684Skaiw augdata_p++; 150260684Skaiw break; 151260684Skaiw case 'P': 152260684Skaiw /* Skip two augments in augment data. */ 153260684Skaiw encode = *augdata_p++; 154260684Skaiw offset = 0; 155276371Semaste ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val, 156260684Skaiw augdata_p, &offset, encode, 0, error); 157260684Skaiw if (ret != DW_DLE_NONE) 158260684Skaiw return (ret); 159260684Skaiw augdata_p += offset; 160260684Skaiw break; 161260684Skaiw case 'R': 162260684Skaiw cie->cie_fde_encode = *augdata_p++; 163260684Skaiw break; 164260684Skaiw default: 165260684Skaiw DWARF_SET_ERROR(dbg, error, 166260684Skaiw DW_DLE_FRAME_AUGMENTATION_UNKNOWN); 167260684Skaiw return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN); 168260684Skaiw } 169260684Skaiw aug_p++; 170260684Skaiw } 171260684Skaiw 172260684Skaiw return (DW_DLE_NONE); 173260684Skaiw} 174260684Skaiw 175260684Skaiwstatic int 176260684Skaiw_dwarf_frame_add_cie(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds, 177260684Skaiw Dwarf_Unsigned *off, Dwarf_Cie *ret_cie, Dwarf_Error *error) 178260684Skaiw{ 179260684Skaiw Dwarf_Cie cie; 180260684Skaiw uint64_t length; 181260684Skaiw int dwarf_size, ret; 182260684Skaiw char *p; 183260684Skaiw 184260684Skaiw /* Check if we already added this CIE. */ 185260684Skaiw if (_dwarf_frame_find_cie(fs, *off, &cie) != DW_DLE_NO_ENTRY) { 186260684Skaiw *off += cie->cie_length + 4; 187260684Skaiw return (DW_DLE_NONE); 188260684Skaiw } 189260684Skaiw 190260684Skaiw if ((cie = calloc(1, sizeof(struct _Dwarf_Cie))) == NULL) { 191260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 192260684Skaiw return (DW_DLE_MEMORY); 193260684Skaiw } 194260684Skaiw STAILQ_INSERT_TAIL(&fs->fs_cielist, cie, cie_next); 195260684Skaiw 196260684Skaiw cie->cie_dbg = dbg; 197260684Skaiw cie->cie_index = fs->fs_cielen; 198260684Skaiw cie->cie_offset = *off; 199260684Skaiw 200260684Skaiw length = dbg->read(ds->ds_data, off, 4); 201260684Skaiw if (length == 0xffffffff) { 202260684Skaiw dwarf_size = 8; 203260684Skaiw length = dbg->read(ds->ds_data, off, 8); 204260684Skaiw } else 205260684Skaiw dwarf_size = 4; 206260684Skaiw 207260684Skaiw if (length > ds->ds_size - *off) { 208260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD); 209260684Skaiw return (DW_DLE_DEBUG_FRAME_LENGTH_BAD); 210260684Skaiw } 211260684Skaiw 212260684Skaiw (void) dbg->read(ds->ds_data, off, dwarf_size); /* Skip CIE id. */ 213260684Skaiw cie->cie_length = length; 214260684Skaiw 215260684Skaiw cie->cie_version = dbg->read(ds->ds_data, off, 1); 216260684Skaiw if (cie->cie_version != 1 && cie->cie_version != 3 && 217260684Skaiw cie->cie_version != 4) { 218260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_VERSION_BAD); 219260684Skaiw return (DW_DLE_FRAME_VERSION_BAD); 220260684Skaiw } 221260684Skaiw 222260684Skaiw cie->cie_augment = ds->ds_data + *off; 223260684Skaiw p = (char *) ds->ds_data; 224260684Skaiw while (p[(*off)++] != '\0') 225260684Skaiw ; 226260684Skaiw 227260684Skaiw /* We only recognize normal .dwarf_frame and GNU .eh_frame sections. */ 228260684Skaiw if (*cie->cie_augment != 0 && *cie->cie_augment != 'z') { 229260684Skaiw *off = cie->cie_offset + ((dwarf_size == 4) ? 4 : 12) + 230260684Skaiw cie->cie_length; 231260684Skaiw return (DW_DLE_NONE); 232260684Skaiw } 233260684Skaiw 234260684Skaiw /* Optional EH Data field for .eh_frame section. */ 235260684Skaiw if (strstr((char *)cie->cie_augment, "eh") != NULL) 236260684Skaiw cie->cie_ehdata = dbg->read(ds->ds_data, off, 237260684Skaiw dbg->dbg_pointer_size); 238260684Skaiw 239276371Semaste /* DWARF4 added "address_size" and "segment_size". */ 240276371Semaste if (cie->cie_version == 4) { 241276371Semaste cie->cie_addrsize = dbg->read(ds->ds_data, off, 1); 242276371Semaste cie->cie_segmentsize = dbg->read(ds->ds_data, off, 1); 243276371Semaste } else { 244276371Semaste /* 245276371Semaste * Otherwise (DWARF[23]) we just set CIE addrsize to the 246276371Semaste * debug context pointer size. 247276371Semaste */ 248276371Semaste cie->cie_addrsize = dbg->dbg_pointer_size; 249276371Semaste } 250276371Semaste 251260684Skaiw cie->cie_caf = _dwarf_read_uleb128(ds->ds_data, off); 252260684Skaiw cie->cie_daf = _dwarf_read_sleb128(ds->ds_data, off); 253260684Skaiw 254260684Skaiw /* Return address register. */ 255260684Skaiw if (cie->cie_version == 1) 256260684Skaiw cie->cie_ra = dbg->read(ds->ds_data, off, 1); 257260684Skaiw else 258260684Skaiw cie->cie_ra = _dwarf_read_uleb128(ds->ds_data, off); 259260684Skaiw 260260684Skaiw /* Optional CIE augmentation data for .eh_frame section. */ 261260684Skaiw if (*cie->cie_augment == 'z') { 262260684Skaiw cie->cie_auglen = _dwarf_read_uleb128(ds->ds_data, off); 263260684Skaiw cie->cie_augdata = ds->ds_data + *off; 264260684Skaiw *off += cie->cie_auglen; 265260684Skaiw /* 266260684Skaiw * XXX Use DW_EH_PE_absptr for default FDE PC start/range, 267260684Skaiw * in case _dwarf_frame_parse_lsb_cie_augment fails to 268260684Skaiw * find out the real encode. 269260684Skaiw */ 270260684Skaiw cie->cie_fde_encode = DW_EH_PE_absptr; 271260684Skaiw ret = _dwarf_frame_parse_lsb_cie_augment(dbg, cie, error); 272260684Skaiw if (ret != DW_DLE_NONE) 273260684Skaiw return (ret); 274260684Skaiw } 275260684Skaiw 276260684Skaiw /* CIE Initial instructions. */ 277260684Skaiw cie->cie_initinst = ds->ds_data + *off; 278260684Skaiw if (dwarf_size == 4) 279260684Skaiw cie->cie_instlen = cie->cie_offset + 4 + length - *off; 280260684Skaiw else 281260684Skaiw cie->cie_instlen = cie->cie_offset + 12 + length - *off; 282260684Skaiw 283260684Skaiw *off += cie->cie_instlen; 284260684Skaiw 285260684Skaiw#ifdef FRAME_DEBUG 286260684Skaiw printf("cie:\n"); 287260684Skaiw printf("\tcie_version=%u cie_offset=%ju cie_length=%ju cie_augment=%s" 288260684Skaiw " cie_instlen=%ju cie->cie_caf=%ju cie->cie_daf=%jd off=%ju\n", 289260684Skaiw cie->cie_version, cie->cie_offset, cie->cie_length, 290260684Skaiw (char *)cie->cie_augment, cie->cie_instlen, cie->cie_caf, 291260684Skaiw cie->cie_daf, *off); 292260684Skaiw#endif 293260684Skaiw 294260684Skaiw if (ret_cie != NULL) 295260684Skaiw *ret_cie = cie; 296260684Skaiw 297260684Skaiw fs->fs_cielen++; 298260684Skaiw 299260684Skaiw return (DW_DLE_NONE); 300260684Skaiw} 301260684Skaiw 302260684Skaiwstatic int 303260684Skaiw_dwarf_frame_add_fde(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds, 304260684Skaiw Dwarf_Unsigned *off, int eh_frame, Dwarf_Error *error) 305260684Skaiw{ 306260684Skaiw Dwarf_Cie cie; 307260684Skaiw Dwarf_Fde fde; 308260684Skaiw Dwarf_Unsigned cieoff; 309260684Skaiw uint64_t length, val; 310260684Skaiw int dwarf_size, ret; 311260684Skaiw 312260684Skaiw if ((fde = calloc(1, sizeof(struct _Dwarf_Fde))) == NULL) { 313260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 314260684Skaiw return (DW_DLE_MEMORY); 315260684Skaiw } 316260684Skaiw STAILQ_INSERT_TAIL(&fs->fs_fdelist, fde, fde_next); 317260684Skaiw 318260684Skaiw fde->fde_dbg = dbg; 319260684Skaiw fde->fde_fs = fs; 320260684Skaiw fde->fde_addr = ds->ds_data + *off; 321260684Skaiw fde->fde_offset = *off; 322260684Skaiw 323260684Skaiw length = dbg->read(ds->ds_data, off, 4); 324260684Skaiw if (length == 0xffffffff) { 325260684Skaiw dwarf_size = 8; 326260684Skaiw length = dbg->read(ds->ds_data, off, 8); 327260684Skaiw } else 328260684Skaiw dwarf_size = 4; 329260684Skaiw 330260684Skaiw if (length > ds->ds_size - *off) { 331260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD); 332260684Skaiw return (DW_DLE_DEBUG_FRAME_LENGTH_BAD); 333260684Skaiw } 334260684Skaiw 335260684Skaiw fde->fde_length = length; 336260684Skaiw 337260684Skaiw if (eh_frame) { 338260684Skaiw fde->fde_cieoff = dbg->read(ds->ds_data, off, 4); 339260684Skaiw cieoff = *off - (4 + fde->fde_cieoff); 340260684Skaiw /* This delta should never be 0. */ 341260684Skaiw if (cieoff == fde->fde_offset) { 342260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_NO_CIE_FOR_FDE); 343260684Skaiw return (DW_DLE_NO_CIE_FOR_FDE); 344260684Skaiw } 345260684Skaiw } else { 346260684Skaiw fde->fde_cieoff = dbg->read(ds->ds_data, off, dwarf_size); 347260684Skaiw cieoff = fde->fde_cieoff; 348260684Skaiw } 349260684Skaiw 350260684Skaiw if (_dwarf_frame_find_cie(fs, cieoff, &cie) == 351260684Skaiw DW_DLE_NO_ENTRY) { 352260684Skaiw ret = _dwarf_frame_add_cie(dbg, fs, ds, &cieoff, &cie, 353260684Skaiw error); 354260684Skaiw if (ret != DW_DLE_NONE) 355260684Skaiw return (ret); 356260684Skaiw } 357260684Skaiw fde->fde_cie = cie; 358260684Skaiw if (eh_frame) { 359260684Skaiw /* 360260684Skaiw * The FDE PC start/range for .eh_frame is encoded according 361260684Skaiw * to the LSB spec's extension to DWARF2. 362260684Skaiw */ 363276371Semaste ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val, 364276371Semaste ds->ds_data, off, cie->cie_fde_encode, ds->ds_addr + *off, 365276371Semaste error); 366260684Skaiw if (ret != DW_DLE_NONE) 367260684Skaiw return (ret); 368260684Skaiw fde->fde_initloc = val; 369260684Skaiw /* 370260684Skaiw * FDE PC range should not be relative value to anything. 371260684Skaiw * So pass 0 for pc value. 372260684Skaiw */ 373276371Semaste ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val, 374276371Semaste ds->ds_data, off, cie->cie_fde_encode, 0, error); 375260684Skaiw if (ret != DW_DLE_NONE) 376260684Skaiw return (ret); 377260684Skaiw fde->fde_adrange = val; 378260684Skaiw } else { 379260684Skaiw fde->fde_initloc = dbg->read(ds->ds_data, off, 380276371Semaste cie->cie_addrsize); 381260684Skaiw fde->fde_adrange = dbg->read(ds->ds_data, off, 382276371Semaste cie->cie_addrsize); 383260684Skaiw } 384260684Skaiw 385260684Skaiw /* Optional FDE augmentation data for .eh_frame section. (ignored) */ 386260684Skaiw if (eh_frame && *cie->cie_augment == 'z') { 387260684Skaiw fde->fde_auglen = _dwarf_read_uleb128(ds->ds_data, off); 388260684Skaiw fde->fde_augdata = ds->ds_data + *off; 389260684Skaiw *off += fde->fde_auglen; 390260684Skaiw } 391260684Skaiw 392260684Skaiw fde->fde_inst = ds->ds_data + *off; 393260684Skaiw if (dwarf_size == 4) 394260684Skaiw fde->fde_instlen = fde->fde_offset + 4 + length - *off; 395260684Skaiw else 396260684Skaiw fde->fde_instlen = fde->fde_offset + 12 + length - *off; 397260684Skaiw 398260684Skaiw *off += fde->fde_instlen; 399260684Skaiw 400260684Skaiw#ifdef FRAME_DEBUG 401260684Skaiw printf("fde:"); 402260684Skaiw if (eh_frame) 403260684Skaiw printf("(eh_frame)"); 404260684Skaiw putchar('\n'); 405260684Skaiw printf("\tfde_offset=%ju fde_length=%ju fde_cieoff=%ju" 406260684Skaiw " fde_instlen=%ju off=%ju\n", fde->fde_offset, fde->fde_length, 407260684Skaiw fde->fde_cieoff, fde->fde_instlen, *off); 408260684Skaiw#endif 409260684Skaiw 410260684Skaiw fs->fs_fdelen++; 411260684Skaiw 412260684Skaiw return (DW_DLE_NONE); 413260684Skaiw} 414260684Skaiw 415260684Skaiwstatic void 416260684Skaiw_dwarf_frame_section_cleanup(Dwarf_FrameSec fs) 417260684Skaiw{ 418260684Skaiw Dwarf_Cie cie, tcie; 419260684Skaiw Dwarf_Fde fde, tfde; 420260684Skaiw 421260684Skaiw STAILQ_FOREACH_SAFE(cie, &fs->fs_cielist, cie_next, tcie) { 422260684Skaiw STAILQ_REMOVE(&fs->fs_cielist, cie, _Dwarf_Cie, cie_next); 423260684Skaiw free(cie); 424260684Skaiw } 425260684Skaiw 426260684Skaiw STAILQ_FOREACH_SAFE(fde, &fs->fs_fdelist, fde_next, tfde) { 427260684Skaiw STAILQ_REMOVE(&fs->fs_fdelist, fde, _Dwarf_Fde, fde_next); 428260684Skaiw free(fde); 429260684Skaiw } 430260684Skaiw 431260684Skaiw if (fs->fs_ciearray != NULL) 432260684Skaiw free(fs->fs_ciearray); 433260684Skaiw if (fs->fs_fdearray != NULL) 434260684Skaiw free(fs->fs_fdearray); 435260684Skaiw 436260684Skaiw free(fs); 437260684Skaiw} 438260684Skaiw 439260684Skaiwstatic int 440260684Skaiw_dwarf_frame_section_init(Dwarf_Debug dbg, Dwarf_FrameSec *frame_sec, 441260684Skaiw Dwarf_Section *ds, int eh_frame, Dwarf_Error *error) 442260684Skaiw{ 443260684Skaiw Dwarf_FrameSec fs; 444260684Skaiw Dwarf_Cie cie; 445260684Skaiw Dwarf_Fde fde; 446260684Skaiw uint64_t length, offset, cie_id, entry_off; 447260684Skaiw int dwarf_size, i, ret; 448260684Skaiw 449260684Skaiw assert(frame_sec != NULL); 450260684Skaiw assert(*frame_sec == NULL); 451260684Skaiw 452260684Skaiw if ((fs = calloc(1, sizeof(struct _Dwarf_FrameSec))) == NULL) { 453260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 454260684Skaiw return (DW_DLE_MEMORY); 455260684Skaiw } 456260684Skaiw STAILQ_INIT(&fs->fs_cielist); 457260684Skaiw STAILQ_INIT(&fs->fs_fdelist); 458260684Skaiw 459260684Skaiw offset = 0; 460260684Skaiw while (offset < ds->ds_size) { 461260684Skaiw entry_off = offset; 462260684Skaiw length = dbg->read(ds->ds_data, &offset, 4); 463260684Skaiw if (length == 0xffffffff) { 464260684Skaiw dwarf_size = 8; 465260684Skaiw length = dbg->read(ds->ds_data, &offset, 8); 466260684Skaiw } else 467260684Skaiw dwarf_size = 4; 468260684Skaiw 469260684Skaiw if (length > ds->ds_size - offset || 470260684Skaiw (length == 0 && !eh_frame)) { 471367466Sdim ret = DW_DLE_DEBUG_FRAME_LENGTH_BAD; 472367466Sdim DWARF_SET_ERROR(dbg, error, ret); 473367466Sdim goto fail_cleanup; 474260684Skaiw } 475260684Skaiw 476260684Skaiw /* Check terminator for .eh_frame */ 477260684Skaiw if (eh_frame && length == 0) 478260684Skaiw break; 479260684Skaiw 480260684Skaiw cie_id = dbg->read(ds->ds_data, &offset, dwarf_size); 481260684Skaiw 482260684Skaiw if (eh_frame) { 483260684Skaiw /* GNU .eh_frame use CIE id 0. */ 484260684Skaiw if (cie_id == 0) 485260684Skaiw ret = _dwarf_frame_add_cie(dbg, fs, ds, 486260684Skaiw &entry_off, NULL, error); 487260684Skaiw else 488260684Skaiw ret = _dwarf_frame_add_fde(dbg, fs, ds, 489260684Skaiw &entry_off, 1, error); 490260684Skaiw } else { 491260684Skaiw /* .dwarf_frame use CIE id ~0 */ 492260684Skaiw if ((dwarf_size == 4 && cie_id == ~0U) || 493260684Skaiw (dwarf_size == 8 && cie_id == ~0ULL)) 494260684Skaiw ret = _dwarf_frame_add_cie(dbg, fs, ds, 495260684Skaiw &entry_off, NULL, error); 496260684Skaiw else 497260684Skaiw ret = _dwarf_frame_add_fde(dbg, fs, ds, 498260684Skaiw &entry_off, 0, error); 499260684Skaiw } 500260684Skaiw 501260684Skaiw if (ret != DW_DLE_NONE) 502260684Skaiw goto fail_cleanup; 503260684Skaiw 504260684Skaiw offset = entry_off; 505260684Skaiw } 506260684Skaiw 507260684Skaiw /* Create CIE array. */ 508260684Skaiw if (fs->fs_cielen > 0) { 509260684Skaiw if ((fs->fs_ciearray = malloc(sizeof(Dwarf_Cie) * 510260684Skaiw fs->fs_cielen)) == NULL) { 511260684Skaiw ret = DW_DLE_MEMORY; 512260684Skaiw DWARF_SET_ERROR(dbg, error, ret); 513260684Skaiw goto fail_cleanup; 514260684Skaiw } 515260684Skaiw i = 0; 516260684Skaiw STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) { 517260684Skaiw fs->fs_ciearray[i++] = cie; 518260684Skaiw } 519260684Skaiw assert((Dwarf_Unsigned)i == fs->fs_cielen); 520260684Skaiw } 521260684Skaiw 522260684Skaiw /* Create FDE array. */ 523260684Skaiw if (fs->fs_fdelen > 0) { 524260684Skaiw if ((fs->fs_fdearray = malloc(sizeof(Dwarf_Fde) * 525260684Skaiw fs->fs_fdelen)) == NULL) { 526260684Skaiw ret = DW_DLE_MEMORY; 527260684Skaiw DWARF_SET_ERROR(dbg, error, ret); 528260684Skaiw goto fail_cleanup; 529260684Skaiw } 530260684Skaiw i = 0; 531260684Skaiw STAILQ_FOREACH(fde, &fs->fs_fdelist, fde_next) { 532260684Skaiw fs->fs_fdearray[i++] = fde; 533260684Skaiw } 534260684Skaiw assert((Dwarf_Unsigned)i == fs->fs_fdelen); 535260684Skaiw } 536260684Skaiw 537260684Skaiw *frame_sec = fs; 538260684Skaiw 539260684Skaiw return (DW_DLE_NONE); 540260684Skaiw 541260684Skaiwfail_cleanup: 542260684Skaiw 543260684Skaiw _dwarf_frame_section_cleanup(fs); 544260684Skaiw 545260684Skaiw return (ret); 546260684Skaiw} 547260684Skaiw 548260684Skaiwstatic int 549276371Semaste_dwarf_frame_run_inst(Dwarf_Debug dbg, Dwarf_Regtable3 *rt, uint8_t addr_size, 550276371Semaste uint8_t *insts, Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf, 551276371Semaste Dwarf_Addr pc, Dwarf_Addr pc_req, Dwarf_Addr *row_pc, Dwarf_Error *error) 552260684Skaiw{ 553260684Skaiw Dwarf_Regtable3 *init_rt, *saved_rt; 554260684Skaiw uint8_t *p, *pe; 555260684Skaiw uint8_t high2, low6; 556260684Skaiw uint64_t reg, reg2, uoff, soff; 557260684Skaiw int ret; 558260684Skaiw 559260684Skaiw#define CFA rt->rt3_cfa_rule 560260684Skaiw#define INITCFA init_rt->rt3_cfa_rule 561260684Skaiw#define RL rt->rt3_rules 562260684Skaiw#define INITRL init_rt->rt3_rules 563260684Skaiw 564260684Skaiw#define CHECK_TABLE_SIZE(x) \ 565260684Skaiw do { \ 566260684Skaiw if ((x) >= rt->rt3_reg_table_size) { \ 567260684Skaiw DWARF_SET_ERROR(dbg, error, \ 568260684Skaiw DW_DLE_DF_REG_NUM_TOO_HIGH); \ 569260684Skaiw ret = DW_DLE_DF_REG_NUM_TOO_HIGH; \ 570260684Skaiw goto program_done; \ 571260684Skaiw } \ 572260684Skaiw } while(0) 573260684Skaiw 574260684Skaiw#ifdef FRAME_DEBUG 575260684Skaiw printf("frame_run_inst: (caf=%ju, daf=%jd)\n", caf, daf); 576260684Skaiw#endif 577260684Skaiw 578260684Skaiw ret = DW_DLE_NONE; 579260684Skaiw init_rt = saved_rt = NULL; 580260684Skaiw *row_pc = pc; 581260684Skaiw 582260684Skaiw /* Save a copy of the table as initial state. */ 583260684Skaiw _dwarf_frame_regtable_copy(dbg, &init_rt, rt, error); 584260684Skaiw 585260684Skaiw p = insts; 586260684Skaiw pe = p + len; 587260684Skaiw 588260684Skaiw while (p < pe) { 589260684Skaiw 590260684Skaiw#ifdef FRAME_DEBUG 591260684Skaiw printf("p=%p pe=%p pc=%#jx pc_req=%#jx\n", p, pe, pc, pc_req); 592260684Skaiw#endif 593260684Skaiw 594260684Skaiw if (*p == DW_CFA_nop) { 595260684Skaiw#ifdef FRAME_DEBUG 596260684Skaiw printf("DW_CFA_nop\n"); 597260684Skaiw#endif 598260684Skaiw p++; 599260684Skaiw continue; 600260684Skaiw } 601260684Skaiw 602260684Skaiw high2 = *p & 0xc0; 603260684Skaiw low6 = *p & 0x3f; 604260684Skaiw p++; 605260684Skaiw 606260684Skaiw if (high2 > 0) { 607260684Skaiw switch (high2) { 608260684Skaiw case DW_CFA_advance_loc: 609260684Skaiw pc += low6 * caf; 610260684Skaiw#ifdef FRAME_DEBUG 611260684Skaiw printf("DW_CFA_advance_loc(%#jx(%u))\n", pc, 612260684Skaiw low6); 613260684Skaiw#endif 614260684Skaiw if (pc_req < pc) 615260684Skaiw goto program_done; 616260684Skaiw break; 617260684Skaiw case DW_CFA_offset: 618260684Skaiw *row_pc = pc; 619260684Skaiw CHECK_TABLE_SIZE(low6); 620260684Skaiw RL[low6].dw_offset_relevant = 1; 621260684Skaiw RL[low6].dw_value_type = DW_EXPR_OFFSET; 622260684Skaiw RL[low6].dw_regnum = dbg->dbg_frame_cfa_value; 623260684Skaiw RL[low6].dw_offset_or_block_len = 624260684Skaiw _dwarf_decode_uleb128(&p) * daf; 625260684Skaiw#ifdef FRAME_DEBUG 626260684Skaiw printf("DW_CFA_offset(%jd)\n", 627260684Skaiw RL[low6].dw_offset_or_block_len); 628260684Skaiw#endif 629260684Skaiw break; 630260684Skaiw case DW_CFA_restore: 631260684Skaiw *row_pc = pc; 632260684Skaiw CHECK_TABLE_SIZE(low6); 633260684Skaiw memcpy(&RL[low6], &INITRL[low6], 634260684Skaiw sizeof(Dwarf_Regtable_Entry3)); 635260684Skaiw#ifdef FRAME_DEBUG 636260684Skaiw printf("DW_CFA_restore(%u)\n", low6); 637260684Skaiw#endif 638260684Skaiw break; 639260684Skaiw default: 640260684Skaiw DWARF_SET_ERROR(dbg, error, 641260684Skaiw DW_DLE_FRAME_INSTR_EXEC_ERROR); 642260684Skaiw ret = DW_DLE_FRAME_INSTR_EXEC_ERROR; 643260684Skaiw goto program_done; 644260684Skaiw } 645260684Skaiw 646260684Skaiw continue; 647260684Skaiw } 648260684Skaiw 649260684Skaiw switch (low6) { 650260684Skaiw case DW_CFA_set_loc: 651276371Semaste pc = dbg->decode(&p, addr_size); 652260684Skaiw#ifdef FRAME_DEBUG 653260684Skaiw printf("DW_CFA_set_loc(pc=%#jx)\n", pc); 654260684Skaiw#endif 655260684Skaiw if (pc_req < pc) 656260684Skaiw goto program_done; 657260684Skaiw break; 658260684Skaiw case DW_CFA_advance_loc1: 659260684Skaiw pc += dbg->decode(&p, 1) * caf; 660260684Skaiw#ifdef FRAME_DEBUG 661260684Skaiw printf("DW_CFA_set_loc1(pc=%#jx)\n", pc); 662260684Skaiw#endif 663260684Skaiw if (pc_req < pc) 664260684Skaiw goto program_done; 665260684Skaiw break; 666260684Skaiw case DW_CFA_advance_loc2: 667260684Skaiw pc += dbg->decode(&p, 2) * caf; 668260684Skaiw#ifdef FRAME_DEBUG 669260684Skaiw printf("DW_CFA_set_loc2(pc=%#jx)\n", pc); 670260684Skaiw#endif 671260684Skaiw if (pc_req < pc) 672260684Skaiw goto program_done; 673260684Skaiw break; 674260684Skaiw case DW_CFA_advance_loc4: 675260684Skaiw pc += dbg->decode(&p, 4) * caf; 676260684Skaiw#ifdef FRAME_DEBUG 677260684Skaiw printf("DW_CFA_set_loc4(pc=%#jx)\n", pc); 678260684Skaiw#endif 679260684Skaiw if (pc_req < pc) 680260684Skaiw goto program_done; 681260684Skaiw break; 682260684Skaiw case DW_CFA_offset_extended: 683260684Skaiw *row_pc = pc; 684260684Skaiw reg = _dwarf_decode_uleb128(&p); 685260684Skaiw uoff = _dwarf_decode_uleb128(&p); 686260684Skaiw CHECK_TABLE_SIZE(reg); 687260684Skaiw RL[reg].dw_offset_relevant = 1; 688260684Skaiw RL[reg].dw_value_type = DW_EXPR_OFFSET; 689260684Skaiw RL[reg].dw_regnum = dbg->dbg_frame_cfa_value; 690260684Skaiw RL[reg].dw_offset_or_block_len = uoff * daf; 691260684Skaiw#ifdef FRAME_DEBUG 692260684Skaiw printf("DW_CFA_offset_extended(reg=%ju,uoff=%ju)\n", 693260684Skaiw reg, uoff); 694260684Skaiw#endif 695260684Skaiw break; 696260684Skaiw case DW_CFA_restore_extended: 697260684Skaiw *row_pc = pc; 698260684Skaiw reg = _dwarf_decode_uleb128(&p); 699260684Skaiw CHECK_TABLE_SIZE(reg); 700260684Skaiw memcpy(&RL[reg], &INITRL[reg], 701260684Skaiw sizeof(Dwarf_Regtable_Entry3)); 702260684Skaiw#ifdef FRAME_DEBUG 703260684Skaiw printf("DW_CFA_restore_extended(%ju)\n", reg); 704260684Skaiw#endif 705260684Skaiw break; 706260684Skaiw case DW_CFA_undefined: 707260684Skaiw *row_pc = pc; 708260684Skaiw reg = _dwarf_decode_uleb128(&p); 709260684Skaiw CHECK_TABLE_SIZE(reg); 710260684Skaiw RL[reg].dw_offset_relevant = 0; 711260684Skaiw RL[reg].dw_regnum = dbg->dbg_frame_undefined_value; 712260684Skaiw#ifdef FRAME_DEBUG 713260684Skaiw printf("DW_CFA_undefined(%ju)\n", reg); 714260684Skaiw#endif 715260684Skaiw break; 716260684Skaiw case DW_CFA_same_value: 717260684Skaiw reg = _dwarf_decode_uleb128(&p); 718260684Skaiw CHECK_TABLE_SIZE(reg); 719260684Skaiw RL[reg].dw_offset_relevant = 0; 720260684Skaiw RL[reg].dw_regnum = dbg->dbg_frame_same_value; 721260684Skaiw#ifdef FRAME_DEBUG 722260684Skaiw printf("DW_CFA_same_value(%ju)\n", reg); 723260684Skaiw#endif 724260684Skaiw break; 725260684Skaiw case DW_CFA_register: 726260684Skaiw *row_pc = pc; 727260684Skaiw reg = _dwarf_decode_uleb128(&p); 728260684Skaiw reg2 = _dwarf_decode_uleb128(&p); 729260684Skaiw CHECK_TABLE_SIZE(reg); 730260684Skaiw RL[reg].dw_offset_relevant = 0; 731260684Skaiw RL[reg].dw_regnum = reg2; 732260684Skaiw#ifdef FRAME_DEBUG 733260684Skaiw printf("DW_CFA_register(reg=%ju,reg2=%ju)\n", reg, 734260684Skaiw reg2); 735260684Skaiw#endif 736260684Skaiw break; 737260684Skaiw case DW_CFA_remember_state: 738260684Skaiw _dwarf_frame_regtable_copy(dbg, &saved_rt, rt, error); 739260684Skaiw#ifdef FRAME_DEBUG 740260684Skaiw printf("DW_CFA_remember_state\n"); 741260684Skaiw#endif 742260684Skaiw break; 743260684Skaiw case DW_CFA_restore_state: 744260684Skaiw *row_pc = pc; 745260684Skaiw _dwarf_frame_regtable_copy(dbg, &rt, saved_rt, error); 746260684Skaiw#ifdef FRAME_DEBUG 747260684Skaiw printf("DW_CFA_restore_state\n"); 748260684Skaiw#endif 749260684Skaiw break; 750260684Skaiw case DW_CFA_def_cfa: 751260684Skaiw *row_pc = pc; 752260684Skaiw reg = _dwarf_decode_uleb128(&p); 753260684Skaiw uoff = _dwarf_decode_uleb128(&p); 754260684Skaiw CFA.dw_offset_relevant = 1; 755260684Skaiw CFA.dw_value_type = DW_EXPR_OFFSET; 756260684Skaiw CFA.dw_regnum = reg; 757260684Skaiw CFA.dw_offset_or_block_len = uoff; 758260684Skaiw#ifdef FRAME_DEBUG 759260684Skaiw printf("DW_CFA_def_cfa(reg=%ju,uoff=%ju)\n", reg, uoff); 760260684Skaiw#endif 761260684Skaiw break; 762260684Skaiw case DW_CFA_def_cfa_register: 763260684Skaiw *row_pc = pc; 764260684Skaiw reg = _dwarf_decode_uleb128(&p); 765260684Skaiw CFA.dw_regnum = reg; 766260684Skaiw /* 767260684Skaiw * Note that DW_CFA_def_cfa_register change the CFA 768260684Skaiw * rule register while keep the old offset. So we 769260684Skaiw * should not touch the CFA.dw_offset_relevant flag 770260684Skaiw * here. 771260684Skaiw */ 772260684Skaiw#ifdef FRAME_DEBUG 773260684Skaiw printf("DW_CFA_def_cfa_register(%ju)\n", reg); 774260684Skaiw#endif 775260684Skaiw break; 776260684Skaiw case DW_CFA_def_cfa_offset: 777260684Skaiw *row_pc = pc; 778260684Skaiw uoff = _dwarf_decode_uleb128(&p); 779260684Skaiw CFA.dw_offset_relevant = 1; 780260684Skaiw CFA.dw_value_type = DW_EXPR_OFFSET; 781260684Skaiw CFA.dw_offset_or_block_len = uoff; 782260684Skaiw#ifdef FRAME_DEBUG 783260684Skaiw printf("DW_CFA_def_cfa_offset(%ju)\n", uoff); 784260684Skaiw#endif 785260684Skaiw break; 786260684Skaiw case DW_CFA_def_cfa_expression: 787260684Skaiw *row_pc = pc; 788260684Skaiw CFA.dw_offset_relevant = 0; 789260684Skaiw CFA.dw_value_type = DW_EXPR_EXPRESSION; 790260684Skaiw CFA.dw_offset_or_block_len = _dwarf_decode_uleb128(&p); 791260684Skaiw CFA.dw_block_ptr = p; 792260684Skaiw p += CFA.dw_offset_or_block_len; 793260684Skaiw#ifdef FRAME_DEBUG 794260684Skaiw printf("DW_CFA_def_cfa_expression\n"); 795260684Skaiw#endif 796260684Skaiw break; 797260684Skaiw case DW_CFA_expression: 798260684Skaiw *row_pc = pc; 799260684Skaiw reg = _dwarf_decode_uleb128(&p); 800260684Skaiw CHECK_TABLE_SIZE(reg); 801260684Skaiw RL[reg].dw_offset_relevant = 0; 802260684Skaiw RL[reg].dw_value_type = DW_EXPR_EXPRESSION; 803260684Skaiw RL[reg].dw_offset_or_block_len = 804260684Skaiw _dwarf_decode_uleb128(&p); 805260684Skaiw RL[reg].dw_block_ptr = p; 806260684Skaiw p += RL[reg].dw_offset_or_block_len; 807260684Skaiw#ifdef FRAME_DEBUG 808260684Skaiw printf("DW_CFA_expression\n"); 809260684Skaiw#endif 810260684Skaiw break; 811260684Skaiw case DW_CFA_offset_extended_sf: 812260684Skaiw *row_pc = pc; 813260684Skaiw reg = _dwarf_decode_uleb128(&p); 814260684Skaiw soff = _dwarf_decode_sleb128(&p); 815260684Skaiw CHECK_TABLE_SIZE(reg); 816260684Skaiw RL[reg].dw_offset_relevant = 1; 817260684Skaiw RL[reg].dw_value_type = DW_EXPR_OFFSET; 818260684Skaiw RL[reg].dw_regnum = dbg->dbg_frame_cfa_value; 819260684Skaiw RL[reg].dw_offset_or_block_len = soff * daf; 820260684Skaiw#ifdef FRAME_DEBUG 821260684Skaiw printf("DW_CFA_offset_extended_sf(reg=%ju,soff=%jd)\n", 822260684Skaiw reg, soff); 823260684Skaiw#endif 824260684Skaiw break; 825260684Skaiw case DW_CFA_def_cfa_sf: 826260684Skaiw *row_pc = pc; 827260684Skaiw reg = _dwarf_decode_uleb128(&p); 828260684Skaiw soff = _dwarf_decode_sleb128(&p); 829260684Skaiw CFA.dw_offset_relevant = 1; 830260684Skaiw CFA.dw_value_type = DW_EXPR_OFFSET; 831260684Skaiw CFA.dw_regnum = reg; 832260684Skaiw CFA.dw_offset_or_block_len = soff * daf; 833260684Skaiw#ifdef FRAME_DEBUG 834260684Skaiw printf("DW_CFA_def_cfa_sf(reg=%ju,soff=%jd)\n", reg, 835260684Skaiw soff); 836260684Skaiw#endif 837260684Skaiw break; 838260684Skaiw case DW_CFA_def_cfa_offset_sf: 839260684Skaiw *row_pc = pc; 840260684Skaiw soff = _dwarf_decode_sleb128(&p); 841260684Skaiw CFA.dw_offset_relevant = 1; 842260684Skaiw CFA.dw_value_type = DW_EXPR_OFFSET; 843260684Skaiw CFA.dw_offset_or_block_len = soff * daf; 844260684Skaiw#ifdef FRAME_DEBUG 845260684Skaiw printf("DW_CFA_def_cfa_offset_sf(soff=%jd)\n", soff); 846260684Skaiw#endif 847260684Skaiw break; 848260684Skaiw case DW_CFA_val_offset: 849260684Skaiw *row_pc = pc; 850260684Skaiw reg = _dwarf_decode_uleb128(&p); 851260684Skaiw uoff = _dwarf_decode_uleb128(&p); 852260684Skaiw CHECK_TABLE_SIZE(reg); 853260684Skaiw RL[reg].dw_offset_relevant = 1; 854260684Skaiw RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET; 855260684Skaiw RL[reg].dw_regnum = dbg->dbg_frame_cfa_value; 856260684Skaiw RL[reg].dw_offset_or_block_len = uoff * daf; 857260684Skaiw#ifdef FRAME_DEBUG 858260684Skaiw printf("DW_CFA_val_offset(reg=%ju,uoff=%ju)\n", reg, 859260684Skaiw uoff); 860260684Skaiw#endif 861260684Skaiw break; 862260684Skaiw case DW_CFA_val_offset_sf: 863260684Skaiw *row_pc = pc; 864260684Skaiw reg = _dwarf_decode_uleb128(&p); 865260684Skaiw soff = _dwarf_decode_sleb128(&p); 866260684Skaiw CHECK_TABLE_SIZE(reg); 867260684Skaiw RL[reg].dw_offset_relevant = 1; 868260684Skaiw RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET; 869260684Skaiw RL[reg].dw_regnum = dbg->dbg_frame_cfa_value; 870260684Skaiw RL[reg].dw_offset_or_block_len = soff * daf; 871260684Skaiw#ifdef FRAME_DEBUG 872260684Skaiw printf("DW_CFA_val_offset_sf(reg=%ju,soff=%jd)\n", reg, 873260684Skaiw soff); 874260684Skaiw#endif 875260684Skaiw break; 876260684Skaiw case DW_CFA_val_expression: 877260684Skaiw *row_pc = pc; 878260684Skaiw reg = _dwarf_decode_uleb128(&p); 879260684Skaiw CHECK_TABLE_SIZE(reg); 880260684Skaiw RL[reg].dw_offset_relevant = 0; 881260684Skaiw RL[reg].dw_value_type = DW_EXPR_VAL_EXPRESSION; 882260684Skaiw RL[reg].dw_offset_or_block_len = 883260684Skaiw _dwarf_decode_uleb128(&p); 884260684Skaiw RL[reg].dw_block_ptr = p; 885260684Skaiw p += RL[reg].dw_offset_or_block_len; 886260684Skaiw#ifdef FRAME_DEBUG 887260684Skaiw printf("DW_CFA_val_expression\n"); 888260684Skaiw#endif 889260684Skaiw break; 890260684Skaiw default: 891260684Skaiw DWARF_SET_ERROR(dbg, error, 892260684Skaiw DW_DLE_FRAME_INSTR_EXEC_ERROR); 893260684Skaiw ret = DW_DLE_FRAME_INSTR_EXEC_ERROR; 894260684Skaiw goto program_done; 895260684Skaiw } 896260684Skaiw } 897260684Skaiw 898260684Skaiwprogram_done: 899260684Skaiw 900260684Skaiw free(init_rt->rt3_rules); 901260684Skaiw free(init_rt); 902260684Skaiw if (saved_rt) { 903260684Skaiw free(saved_rt->rt3_rules); 904260684Skaiw free(saved_rt); 905260684Skaiw } 906260684Skaiw 907260684Skaiw return (ret); 908260684Skaiw 909260684Skaiw#undef CFA 910260684Skaiw#undef INITCFA 911260684Skaiw#undef RL 912260684Skaiw#undef INITRL 913260684Skaiw#undef CHECK_TABLE_SIZE 914260684Skaiw} 915260684Skaiw 916260684Skaiwstatic int 917276371Semaste_dwarf_frame_convert_inst(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts, 918276371Semaste Dwarf_Unsigned len, Dwarf_Unsigned *count, Dwarf_Frame_Op *fop, 919276371Semaste Dwarf_Frame_Op3 *fop3, Dwarf_Error *error) 920260684Skaiw{ 921260684Skaiw uint8_t *p, *pe; 922260684Skaiw uint8_t high2, low6; 923260684Skaiw uint64_t reg, reg2, uoff, soff, blen; 924260684Skaiw 925260684Skaiw#define SET_BASE_OP(x) \ 926260684Skaiw do { \ 927260684Skaiw if (fop != NULL) \ 928260684Skaiw fop[*count].fp_base_op = (x) >> 6; \ 929260684Skaiw if (fop3 != NULL) \ 930260684Skaiw fop3[*count].fp_base_op = (x) >> 6; \ 931260684Skaiw } while(0) 932260684Skaiw 933260684Skaiw#define SET_EXTENDED_OP(x) \ 934260684Skaiw do { \ 935260684Skaiw if (fop != NULL) \ 936260684Skaiw fop[*count].fp_extended_op = (x); \ 937260684Skaiw if (fop3 != NULL) \ 938260684Skaiw fop3[*count].fp_extended_op = (x); \ 939260684Skaiw } while(0) 940260684Skaiw 941260684Skaiw#define SET_REGISTER(x) \ 942260684Skaiw do { \ 943260684Skaiw if (fop != NULL) \ 944260684Skaiw fop[*count].fp_register = (x); \ 945260684Skaiw if (fop3 != NULL) \ 946260684Skaiw fop3[*count].fp_register = (x); \ 947260684Skaiw } while(0) 948260684Skaiw 949260684Skaiw#define SET_OFFSET(x) \ 950260684Skaiw do { \ 951260684Skaiw if (fop != NULL) \ 952260684Skaiw fop[*count].fp_offset = (x); \ 953260684Skaiw if (fop3 != NULL) \ 954260684Skaiw fop3[*count].fp_offset_or_block_len = \ 955260684Skaiw (x); \ 956260684Skaiw } while(0) 957260684Skaiw 958260684Skaiw#define SET_INSTR_OFFSET(x) \ 959260684Skaiw do { \ 960260684Skaiw if (fop != NULL) \ 961260684Skaiw fop[*count].fp_instr_offset = (x); \ 962260684Skaiw if (fop3 != NULL) \ 963260684Skaiw fop3[*count].fp_instr_offset = (x); \ 964260684Skaiw } while(0) 965260684Skaiw 966260684Skaiw#define SET_BLOCK_LEN(x) \ 967260684Skaiw do { \ 968260684Skaiw if (fop3 != NULL) \ 969260684Skaiw fop3[*count].fp_offset_or_block_len = \ 970260684Skaiw (x); \ 971260684Skaiw } while(0) 972260684Skaiw 973260684Skaiw#define SET_EXPR_BLOCK(addr, len) \ 974260684Skaiw do { \ 975260684Skaiw if (fop3 != NULL) { \ 976260684Skaiw fop3[*count].fp_expr_block = \ 977260684Skaiw malloc((size_t) (len)); \ 978260684Skaiw if (fop3[*count].fp_expr_block == NULL) { \ 979260684Skaiw DWARF_SET_ERROR(dbg, error, \ 980260684Skaiw DW_DLE_MEMORY); \ 981260684Skaiw return (DW_DLE_MEMORY); \ 982260684Skaiw } \ 983260684Skaiw memcpy(&fop3[*count].fp_expr_block, \ 984260684Skaiw (addr), (len)); \ 985260684Skaiw } \ 986260684Skaiw } while(0) 987260684Skaiw 988260684Skaiw *count = 0; 989260684Skaiw 990260684Skaiw p = insts; 991260684Skaiw pe = p + len; 992260684Skaiw 993260684Skaiw while (p < pe) { 994260684Skaiw 995260684Skaiw SET_INSTR_OFFSET(p - insts); 996260684Skaiw 997260684Skaiw if (*p == DW_CFA_nop) { 998260684Skaiw p++; 999260684Skaiw (*count)++; 1000260684Skaiw continue; 1001260684Skaiw } 1002260684Skaiw 1003260684Skaiw high2 = *p & 0xc0; 1004260684Skaiw low6 = *p & 0x3f; 1005260684Skaiw p++; 1006260684Skaiw 1007260684Skaiw if (high2 > 0) { 1008260684Skaiw switch (high2) { 1009260684Skaiw case DW_CFA_advance_loc: 1010260684Skaiw SET_BASE_OP(high2); 1011260684Skaiw SET_OFFSET(low6); 1012260684Skaiw break; 1013260684Skaiw case DW_CFA_offset: 1014260684Skaiw SET_BASE_OP(high2); 1015260684Skaiw SET_REGISTER(low6); 1016260684Skaiw uoff = _dwarf_decode_uleb128(&p); 1017260684Skaiw SET_OFFSET(uoff); 1018260684Skaiw break; 1019260684Skaiw case DW_CFA_restore: 1020260684Skaiw SET_BASE_OP(high2); 1021260684Skaiw SET_REGISTER(low6); 1022260684Skaiw break; 1023260684Skaiw default: 1024260684Skaiw DWARF_SET_ERROR(dbg, error, 1025260684Skaiw DW_DLE_FRAME_INSTR_EXEC_ERROR); 1026260684Skaiw return (DW_DLE_FRAME_INSTR_EXEC_ERROR); 1027260684Skaiw } 1028260684Skaiw 1029260684Skaiw (*count)++; 1030260684Skaiw continue; 1031260684Skaiw } 1032260684Skaiw 1033260684Skaiw SET_EXTENDED_OP(low6); 1034260684Skaiw 1035260684Skaiw switch (low6) { 1036260684Skaiw case DW_CFA_set_loc: 1037276371Semaste uoff = dbg->decode(&p, addr_size); 1038260684Skaiw SET_OFFSET(uoff); 1039260684Skaiw break; 1040260684Skaiw case DW_CFA_advance_loc1: 1041260684Skaiw uoff = dbg->decode(&p, 1); 1042260684Skaiw SET_OFFSET(uoff); 1043260684Skaiw break; 1044260684Skaiw case DW_CFA_advance_loc2: 1045260684Skaiw uoff = dbg->decode(&p, 2); 1046260684Skaiw SET_OFFSET(uoff); 1047260684Skaiw break; 1048260684Skaiw case DW_CFA_advance_loc4: 1049260684Skaiw uoff = dbg->decode(&p, 4); 1050260684Skaiw SET_OFFSET(uoff); 1051260684Skaiw break; 1052260684Skaiw case DW_CFA_offset_extended: 1053260684Skaiw case DW_CFA_def_cfa: 1054260684Skaiw case DW_CFA_val_offset: 1055260684Skaiw reg = _dwarf_decode_uleb128(&p); 1056260684Skaiw uoff = _dwarf_decode_uleb128(&p); 1057260684Skaiw SET_REGISTER(reg); 1058260684Skaiw SET_OFFSET(uoff); 1059260684Skaiw break; 1060260684Skaiw case DW_CFA_restore_extended: 1061260684Skaiw case DW_CFA_undefined: 1062260684Skaiw case DW_CFA_same_value: 1063260684Skaiw case DW_CFA_def_cfa_register: 1064260684Skaiw reg = _dwarf_decode_uleb128(&p); 1065260684Skaiw SET_REGISTER(reg); 1066260684Skaiw break; 1067260684Skaiw case DW_CFA_register: 1068260684Skaiw reg = _dwarf_decode_uleb128(&p); 1069260684Skaiw reg2 = _dwarf_decode_uleb128(&p); 1070260684Skaiw SET_REGISTER(reg); 1071260684Skaiw SET_OFFSET(reg2); 1072260684Skaiw break; 1073260684Skaiw case DW_CFA_remember_state: 1074260684Skaiw case DW_CFA_restore_state: 1075260684Skaiw break; 1076260684Skaiw case DW_CFA_def_cfa_offset: 1077260684Skaiw uoff = _dwarf_decode_uleb128(&p); 1078260684Skaiw SET_OFFSET(uoff); 1079260684Skaiw break; 1080260684Skaiw case DW_CFA_def_cfa_expression: 1081260684Skaiw blen = _dwarf_decode_uleb128(&p); 1082260684Skaiw SET_BLOCK_LEN(blen); 1083260684Skaiw SET_EXPR_BLOCK(p, blen); 1084260684Skaiw p += blen; 1085260684Skaiw break; 1086260684Skaiw case DW_CFA_expression: 1087260684Skaiw case DW_CFA_val_expression: 1088260684Skaiw reg = _dwarf_decode_uleb128(&p); 1089260684Skaiw blen = _dwarf_decode_uleb128(&p); 1090260684Skaiw SET_REGISTER(reg); 1091260684Skaiw SET_BLOCK_LEN(blen); 1092260684Skaiw SET_EXPR_BLOCK(p, blen); 1093260684Skaiw p += blen; 1094260684Skaiw break; 1095260684Skaiw case DW_CFA_offset_extended_sf: 1096260684Skaiw case DW_CFA_def_cfa_sf: 1097260684Skaiw case DW_CFA_val_offset_sf: 1098260684Skaiw reg = _dwarf_decode_uleb128(&p); 1099260684Skaiw soff = _dwarf_decode_sleb128(&p); 1100260684Skaiw SET_REGISTER(reg); 1101260684Skaiw SET_OFFSET(soff); 1102260684Skaiw break; 1103260684Skaiw case DW_CFA_def_cfa_offset_sf: 1104260684Skaiw soff = _dwarf_decode_sleb128(&p); 1105260684Skaiw SET_OFFSET(soff); 1106260684Skaiw break; 1107260684Skaiw default: 1108260684Skaiw DWARF_SET_ERROR(dbg, error, 1109260684Skaiw DW_DLE_FRAME_INSTR_EXEC_ERROR); 1110260684Skaiw return (DW_DLE_FRAME_INSTR_EXEC_ERROR); 1111260684Skaiw } 1112260684Skaiw 1113260684Skaiw (*count)++; 1114260684Skaiw } 1115260684Skaiw 1116260684Skaiw return (DW_DLE_NONE); 1117260684Skaiw} 1118260684Skaiw 1119260684Skaiwint 1120276371Semaste_dwarf_frame_get_fop(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts, 1121276371Semaste Dwarf_Unsigned len, Dwarf_Frame_Op **ret_oplist, Dwarf_Signed *ret_opcnt, 1122276371Semaste Dwarf_Error *error) 1123260684Skaiw{ 1124260684Skaiw Dwarf_Frame_Op *oplist; 1125260684Skaiw Dwarf_Unsigned count; 1126260684Skaiw int ret; 1127260684Skaiw 1128276371Semaste ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count, 1129276371Semaste NULL, NULL, error); 1130260684Skaiw if (ret != DW_DLE_NONE) 1131260684Skaiw return (ret); 1132260684Skaiw 1133260684Skaiw if ((oplist = calloc(count, sizeof(Dwarf_Frame_Op))) == NULL) { 1134260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 1135260684Skaiw return (DW_DLE_MEMORY); 1136260684Skaiw } 1137260684Skaiw 1138276371Semaste ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count, 1139276371Semaste oplist, NULL, error); 1140260684Skaiw if (ret != DW_DLE_NONE) { 1141260684Skaiw free(oplist); 1142260684Skaiw return (ret); 1143260684Skaiw } 1144260684Skaiw 1145260684Skaiw *ret_oplist = oplist; 1146260684Skaiw *ret_opcnt = count; 1147260684Skaiw 1148260684Skaiw return (DW_DLE_NONE); 1149260684Skaiw} 1150260684Skaiw 1151260684Skaiwint 1152260684Skaiw_dwarf_frame_regtable_copy(Dwarf_Debug dbg, Dwarf_Regtable3 **dest, 1153260684Skaiw Dwarf_Regtable3 *src, Dwarf_Error *error) 1154260684Skaiw{ 1155260684Skaiw int i; 1156260684Skaiw 1157260684Skaiw assert(dest != NULL); 1158260684Skaiw assert(src != NULL); 1159260684Skaiw 1160260684Skaiw if (*dest == NULL) { 1161260684Skaiw if ((*dest = malloc(sizeof(Dwarf_Regtable3))) == NULL) { 1162260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 1163260684Skaiw return (DW_DLE_MEMORY); 1164260684Skaiw } 1165260684Skaiw (*dest)->rt3_reg_table_size = src->rt3_reg_table_size; 1166260684Skaiw (*dest)->rt3_rules = malloc(src->rt3_reg_table_size * 1167260684Skaiw sizeof(Dwarf_Regtable_Entry3)); 1168260684Skaiw if ((*dest)->rt3_rules == NULL) { 1169260684Skaiw free(*dest); 1170260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 1171260684Skaiw return (DW_DLE_MEMORY); 1172260684Skaiw } 1173260684Skaiw } 1174260684Skaiw 1175260684Skaiw memcpy(&(*dest)->rt3_cfa_rule, &src->rt3_cfa_rule, 1176260684Skaiw sizeof(Dwarf_Regtable_Entry3)); 1177260684Skaiw 1178260684Skaiw for (i = 0; i < (*dest)->rt3_reg_table_size && 1179260684Skaiw i < src->rt3_reg_table_size; i++) 1180260684Skaiw memcpy(&(*dest)->rt3_rules[i], &src->rt3_rules[i], 1181260684Skaiw sizeof(Dwarf_Regtable_Entry3)); 1182260684Skaiw 1183260684Skaiw for (; i < (*dest)->rt3_reg_table_size; i++) 1184260684Skaiw (*dest)->rt3_rules[i].dw_regnum = 1185260684Skaiw dbg->dbg_frame_undefined_value; 1186260684Skaiw 1187260684Skaiw return (DW_DLE_NONE); 1188260684Skaiw} 1189260684Skaiw 1190260684Skaiwint 1191260684Skaiw_dwarf_frame_get_internal_table(Dwarf_Fde fde, Dwarf_Addr pc_req, 1192260684Skaiw Dwarf_Regtable3 **ret_rt, Dwarf_Addr *ret_row_pc, Dwarf_Error *error) 1193260684Skaiw{ 1194260684Skaiw Dwarf_Debug dbg; 1195260684Skaiw Dwarf_Cie cie; 1196260684Skaiw Dwarf_Regtable3 *rt; 1197260684Skaiw Dwarf_Addr row_pc; 1198260684Skaiw int i, ret; 1199260684Skaiw 1200260684Skaiw assert(ret_rt != NULL); 1201260684Skaiw 1202260684Skaiw dbg = fde->fde_dbg; 1203260684Skaiw assert(dbg != NULL); 1204260684Skaiw 1205260684Skaiw rt = dbg->dbg_internal_reg_table; 1206260684Skaiw 1207260684Skaiw /* Clear the content of regtable from previous run. */ 1208260684Skaiw memset(&rt->rt3_cfa_rule, 0, sizeof(Dwarf_Regtable_Entry3)); 1209260684Skaiw memset(rt->rt3_rules, 0, rt->rt3_reg_table_size * 1210260684Skaiw sizeof(Dwarf_Regtable_Entry3)); 1211260684Skaiw 1212260684Skaiw /* Set rules to initial values. */ 1213260684Skaiw for (i = 0; i < rt->rt3_reg_table_size; i++) 1214260684Skaiw rt->rt3_rules[i].dw_regnum = dbg->dbg_frame_rule_initial_value; 1215260684Skaiw 1216260684Skaiw /* Run initial instructions in CIE. */ 1217260684Skaiw cie = fde->fde_cie; 1218260684Skaiw assert(cie != NULL); 1219276371Semaste ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize, 1220276371Semaste cie->cie_initinst, cie->cie_instlen, cie->cie_caf, cie->cie_daf, 0, 1221276371Semaste ~0ULL, &row_pc, error); 1222260684Skaiw if (ret != DW_DLE_NONE) 1223260684Skaiw return (ret); 1224260684Skaiw 1225260684Skaiw /* Run instructions in FDE. */ 1226260684Skaiw if (pc_req >= fde->fde_initloc) { 1227276371Semaste ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize, 1228276371Semaste fde->fde_inst, fde->fde_instlen, cie->cie_caf, 1229276371Semaste cie->cie_daf, fde->fde_initloc, pc_req, &row_pc, error); 1230260684Skaiw if (ret != DW_DLE_NONE) 1231260684Skaiw return (ret); 1232260684Skaiw } 1233260684Skaiw 1234260684Skaiw *ret_rt = rt; 1235260684Skaiw *ret_row_pc = row_pc; 1236260684Skaiw 1237260684Skaiw return (DW_DLE_NONE); 1238260684Skaiw} 1239260684Skaiw 1240260684Skaiwvoid 1241260684Skaiw_dwarf_frame_cleanup(Dwarf_Debug dbg) 1242260684Skaiw{ 1243260684Skaiw Dwarf_Regtable3 *rt; 1244260684Skaiw 1245260684Skaiw assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); 1246260684Skaiw 1247260684Skaiw if (dbg->dbg_internal_reg_table) { 1248260684Skaiw rt = dbg->dbg_internal_reg_table; 1249260684Skaiw free(rt->rt3_rules); 1250260684Skaiw free(rt); 1251260684Skaiw dbg->dbg_internal_reg_table = NULL; 1252260684Skaiw } 1253260684Skaiw 1254260684Skaiw if (dbg->dbg_frame) { 1255260684Skaiw _dwarf_frame_section_cleanup(dbg->dbg_frame); 1256260684Skaiw dbg->dbg_frame = NULL; 1257260684Skaiw } 1258260684Skaiw 1259260684Skaiw if (dbg->dbg_eh_frame) { 1260260684Skaiw _dwarf_frame_section_cleanup(dbg->dbg_eh_frame); 1261260684Skaiw dbg->dbg_eh_frame = NULL; 1262260684Skaiw } 1263260684Skaiw} 1264260684Skaiw 1265260684Skaiwint 1266260684Skaiw_dwarf_frame_section_load(Dwarf_Debug dbg, Dwarf_Error *error) 1267260684Skaiw{ 1268260684Skaiw Dwarf_Section *ds; 1269260684Skaiw 1270260684Skaiw if ((ds = _dwarf_find_section(dbg, ".debug_frame")) != NULL) { 1271260684Skaiw return (_dwarf_frame_section_init(dbg, &dbg->dbg_frame, 1272260684Skaiw ds, 0, error)); 1273260684Skaiw } 1274260684Skaiw 1275260684Skaiw return (DW_DLE_NONE); 1276260684Skaiw} 1277260684Skaiw 1278260684Skaiwint 1279260684Skaiw_dwarf_frame_section_load_eh(Dwarf_Debug dbg, Dwarf_Error *error) 1280260684Skaiw{ 1281260684Skaiw Dwarf_Section *ds; 1282260684Skaiw 1283260684Skaiw if ((ds = _dwarf_find_section(dbg, ".eh_frame")) != NULL) { 1284260684Skaiw return (_dwarf_frame_section_init(dbg, &dbg->dbg_eh_frame, 1285260684Skaiw ds, 1, error)); 1286260684Skaiw } 1287260684Skaiw 1288260684Skaiw return (DW_DLE_NONE); 1289260684Skaiw} 1290260684Skaiw 1291260684Skaiwvoid 1292260684Skaiw_dwarf_frame_params_init(Dwarf_Debug dbg) 1293260684Skaiw{ 1294260684Skaiw 1295260684Skaiw /* Initialise call frame related parameters. */ 1296260684Skaiw dbg->dbg_frame_rule_table_size = DW_FRAME_LAST_REG_NUM; 1297260684Skaiw dbg->dbg_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE; 1298260684Skaiw dbg->dbg_frame_cfa_value = DW_FRAME_CFA_COL3; 1299260684Skaiw dbg->dbg_frame_same_value = DW_FRAME_SAME_VAL; 1300260684Skaiw dbg->dbg_frame_undefined_value = DW_FRAME_UNDEFINED_VAL; 1301260684Skaiw} 1302260684Skaiw 1303260684Skaiwint 1304260684Skaiw_dwarf_frame_interal_table_init(Dwarf_Debug dbg, Dwarf_Error *error) 1305260684Skaiw{ 1306260684Skaiw Dwarf_Regtable3 *rt; 1307260684Skaiw 1308260684Skaiw if (dbg->dbg_internal_reg_table != NULL) 1309260684Skaiw return (DW_DLE_NONE); 1310260684Skaiw 1311260684Skaiw /* Initialise internal register table. */ 1312260684Skaiw if ((rt = calloc(1, sizeof(Dwarf_Regtable3))) == NULL) { 1313260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 1314260684Skaiw return (DW_DLE_MEMORY); 1315260684Skaiw } 1316260684Skaiw 1317260684Skaiw rt->rt3_reg_table_size = dbg->dbg_frame_rule_table_size; 1318260684Skaiw if ((rt->rt3_rules = calloc(rt->rt3_reg_table_size, 1319260684Skaiw sizeof(Dwarf_Regtable_Entry3))) == NULL) { 1320260684Skaiw free(rt); 1321260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 1322260684Skaiw return (DW_DLE_MEMORY); 1323260684Skaiw } 1324260684Skaiw 1325260684Skaiw dbg->dbg_internal_reg_table = rt; 1326260684Skaiw 1327260684Skaiw return (DW_DLE_NONE); 1328260684Skaiw} 1329260684Skaiw 1330260684Skaiw#define _FDE_INST_INIT_SIZE 128 1331260684Skaiw 1332260684Skaiwint 1333260684Skaiw_dwarf_frame_fde_add_inst(Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1, 1334260684Skaiw Dwarf_Unsigned val2, Dwarf_Error *error) 1335260684Skaiw{ 1336260684Skaiw Dwarf_P_Debug dbg; 1337260684Skaiw uint8_t high2, low6; 1338260684Skaiw int ret; 1339260684Skaiw 1340260684Skaiw#define ds fde 1341260684Skaiw#define ds_data fde_inst 1342260684Skaiw#define ds_cap fde_instcap 1343260684Skaiw#define ds_size fde_instlen 1344260684Skaiw 1345260684Skaiw assert(fde != NULL && fde->fde_dbg != NULL); 1346260684Skaiw dbg = fde->fde_dbg; 1347260684Skaiw 1348260684Skaiw if (fde->fde_inst == NULL) { 1349260684Skaiw fde->fde_instcap = _FDE_INST_INIT_SIZE; 1350260684Skaiw fde->fde_instlen = 0; 1351260684Skaiw if ((fde->fde_inst = malloc((size_t) fde->fde_instcap)) == 1352260684Skaiw NULL) { 1353260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 1354260684Skaiw return (DW_DLE_MEMORY); 1355260684Skaiw } 1356260684Skaiw } 1357260684Skaiw assert(fde->fde_instcap != 0); 1358260684Skaiw 1359260684Skaiw RCHECK(WRITE_VALUE(op, 1)); 1360260684Skaiw if (op == DW_CFA_nop) 1361260684Skaiw return (DW_DLE_NONE); 1362260684Skaiw 1363260684Skaiw high2 = op & 0xc0; 1364260684Skaiw low6 = op & 0x3f; 1365260684Skaiw 1366260684Skaiw if (high2 > 0) { 1367260684Skaiw switch (high2) { 1368260684Skaiw case DW_CFA_advance_loc: 1369260684Skaiw case DW_CFA_restore: 1370260684Skaiw break; 1371260684Skaiw case DW_CFA_offset: 1372260684Skaiw RCHECK(WRITE_ULEB128(val1)); 1373260684Skaiw break; 1374260684Skaiw default: 1375260684Skaiw DWARF_SET_ERROR(dbg, error, 1376260684Skaiw DW_DLE_FRAME_INSTR_EXEC_ERROR); 1377260684Skaiw return (DW_DLE_FRAME_INSTR_EXEC_ERROR); 1378260684Skaiw } 1379260684Skaiw return (DW_DLE_NONE); 1380260684Skaiw } 1381260684Skaiw 1382260684Skaiw switch (low6) { 1383260684Skaiw case DW_CFA_set_loc: 1384260684Skaiw RCHECK(WRITE_VALUE(val1, dbg->dbg_pointer_size)); 1385260684Skaiw break; 1386260684Skaiw case DW_CFA_advance_loc1: 1387260684Skaiw RCHECK(WRITE_VALUE(val1, 1)); 1388260684Skaiw break; 1389260684Skaiw case DW_CFA_advance_loc2: 1390260684Skaiw RCHECK(WRITE_VALUE(val1, 2)); 1391260684Skaiw break; 1392260684Skaiw case DW_CFA_advance_loc4: 1393260684Skaiw RCHECK(WRITE_VALUE(val1, 4)); 1394260684Skaiw break; 1395260684Skaiw case DW_CFA_offset_extended: 1396260684Skaiw case DW_CFA_def_cfa: 1397260684Skaiw case DW_CFA_register: 1398260684Skaiw RCHECK(WRITE_ULEB128(val1)); 1399260684Skaiw RCHECK(WRITE_ULEB128(val2)); 1400260684Skaiw break; 1401260684Skaiw case DW_CFA_restore_extended: 1402260684Skaiw case DW_CFA_undefined: 1403260684Skaiw case DW_CFA_same_value: 1404260684Skaiw case DW_CFA_def_cfa_register: 1405260684Skaiw case DW_CFA_def_cfa_offset: 1406260684Skaiw RCHECK(WRITE_ULEB128(val1)); 1407260684Skaiw break; 1408260684Skaiw case DW_CFA_remember_state: 1409260684Skaiw case DW_CFA_restore_state: 1410260684Skaiw break; 1411260684Skaiw default: 1412260684Skaiw DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR); 1413260684Skaiw return (DW_DLE_FRAME_INSTR_EXEC_ERROR); 1414260684Skaiw } 1415260684Skaiw 1416260684Skaiw return (DW_DLE_NONE); 1417260684Skaiw 1418260684Skaiwgen_fail: 1419260684Skaiw return (ret); 1420260684Skaiw 1421260684Skaiw#undef ds 1422260684Skaiw#undef ds_data 1423260684Skaiw#undef ds_cap 1424260684Skaiw#undef ds_size 1425260684Skaiw} 1426260684Skaiw 1427260684Skaiwstatic int 1428260684Skaiw_dwarf_frame_gen_cie(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_P_Cie cie, 1429260684Skaiw Dwarf_Error *error) 1430260684Skaiw{ 1431260684Skaiw Dwarf_Unsigned len; 1432260684Skaiw uint64_t offset; 1433260684Skaiw int ret; 1434260684Skaiw 1435260684Skaiw assert(dbg != NULL && ds != NULL && cie != NULL); 1436260684Skaiw 1437260684Skaiw cie->cie_offset = offset = ds->ds_size; 1438260684Skaiw cie->cie_length = 0; 1439260684Skaiw cie->cie_version = 1; 1440260684Skaiw 1441260684Skaiw /* Length placeholder. */ 1442260684Skaiw RCHECK(WRITE_VALUE(cie->cie_length, 4)); 1443260684Skaiw 1444260684Skaiw /* .debug_frame use CIE id ~0. */ 1445260684Skaiw RCHECK(WRITE_VALUE(~0U, 4)); 1446260684Skaiw 1447260684Skaiw /* .debug_frame version is 1. (DWARF2) */ 1448260684Skaiw RCHECK(WRITE_VALUE(cie->cie_version, 1)); 1449260684Skaiw 1450260684Skaiw /* Write augmentation, if present. */ 1451260684Skaiw if (cie->cie_augment != NULL) 1452260684Skaiw RCHECK(WRITE_BLOCK(cie->cie_augment, 1453260684Skaiw strlen((char *) cie->cie_augment) + 1)); 1454260684Skaiw else 1455260684Skaiw RCHECK(WRITE_VALUE(0, 1)); 1456260684Skaiw 1457260684Skaiw /* Write caf, daf and ra. */ 1458260684Skaiw RCHECK(WRITE_ULEB128(cie->cie_caf)); 1459260684Skaiw RCHECK(WRITE_SLEB128(cie->cie_daf)); 1460260684Skaiw RCHECK(WRITE_VALUE(cie->cie_ra, 1)); 1461260684Skaiw 1462260684Skaiw /* Write initial instructions, if present. */ 1463260684Skaiw if (cie->cie_initinst != NULL) 1464260684Skaiw RCHECK(WRITE_BLOCK(cie->cie_initinst, cie->cie_instlen)); 1465260684Skaiw 1466260684Skaiw /* Add padding. */ 1467260684Skaiw len = ds->ds_size - cie->cie_offset - 4; 1468260684Skaiw cie->cie_length = roundup(len, dbg->dbg_pointer_size); 1469260684Skaiw while (len++ < cie->cie_length) 1470260684Skaiw RCHECK(WRITE_VALUE(DW_CFA_nop, 1)); 1471260684Skaiw 1472260684Skaiw /* Fill in the length field. */ 1473260684Skaiw dbg->write(ds->ds_data, &offset, cie->cie_length, 4); 1474260684Skaiw 1475260684Skaiw return (DW_DLE_NONE); 1476260684Skaiw 1477260684Skaiwgen_fail: 1478260684Skaiw return (ret); 1479260684Skaiw} 1480260684Skaiw 1481260684Skaiwstatic int 1482260684Skaiw_dwarf_frame_gen_fde(Dwarf_P_Debug dbg, Dwarf_P_Section ds, 1483260684Skaiw Dwarf_Rel_Section drs, Dwarf_P_Fde fde, Dwarf_Error *error) 1484260684Skaiw{ 1485260684Skaiw Dwarf_Unsigned len; 1486260684Skaiw uint64_t offset; 1487260684Skaiw int ret; 1488260684Skaiw 1489260684Skaiw assert(dbg != NULL && ds != NULL && drs != NULL); 1490260684Skaiw assert(fde != NULL && fde->fde_cie != NULL); 1491260684Skaiw 1492260684Skaiw fde->fde_offset = offset = ds->ds_size; 1493260684Skaiw fde->fde_length = 0; 1494260684Skaiw fde->fde_cieoff = fde->fde_cie->cie_offset; 1495260684Skaiw 1496260684Skaiw /* Length placeholder. */ 1497260684Skaiw RCHECK(WRITE_VALUE(fde->fde_length, 4)); 1498260684Skaiw 1499260684Skaiw /* Write CIE pointer. */ 1500260684Skaiw RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4, 1501260684Skaiw ds->ds_size, 0, fde->fde_cieoff, ".debug_frame", error)); 1502260684Skaiw 1503260684Skaiw /* Write FDE initial location. */ 1504260684Skaiw RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 1505260684Skaiw dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx, 1506260684Skaiw fde->fde_initloc, NULL, error)); 1507260684Skaiw 1508260684Skaiw /* 1509260684Skaiw * Write FDE address range. Use a pair of relocation entries if 1510260684Skaiw * application provided end symbol index. Otherwise write the 1511260684Skaiw * length without assoicating any relocation info. 1512260684Skaiw */ 1513260684Skaiw if (fde->fde_esymndx > 0) 1514260684Skaiw RCHECK(_dwarf_reloc_entry_add_pair(dbg, drs, ds, 1515260684Skaiw dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx, 1516260684Skaiw fde->fde_esymndx, fde->fde_initloc, fde->fde_eoff, error)); 1517260684Skaiw else 1518260684Skaiw RCHECK(WRITE_VALUE(fde->fde_adrange, dbg->dbg_pointer_size)); 1519260684Skaiw 1520260684Skaiw /* Write FDE frame instructions. */ 1521260684Skaiw RCHECK(WRITE_BLOCK(fde->fde_inst, fde->fde_instlen)); 1522260684Skaiw 1523260684Skaiw /* Add padding. */ 1524260684Skaiw len = ds->ds_size - fde->fde_offset - 4; 1525260684Skaiw fde->fde_length = roundup(len, dbg->dbg_pointer_size); 1526260684Skaiw while (len++ < fde->fde_length) 1527260684Skaiw RCHECK(WRITE_VALUE(DW_CFA_nop, 1)); 1528260684Skaiw 1529260684Skaiw /* Fill in the length field. */ 1530260684Skaiw dbg->write(ds->ds_data, &offset, fde->fde_length, 4); 1531260684Skaiw 1532260684Skaiw return (DW_DLE_NONE); 1533260684Skaiw 1534260684Skaiwgen_fail: 1535260684Skaiw return (ret); 1536260684Skaiw} 1537260684Skaiw 1538260684Skaiwint 1539260684Skaiw_dwarf_frame_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) 1540260684Skaiw{ 1541260684Skaiw Dwarf_P_Section ds; 1542260684Skaiw Dwarf_Rel_Section drs; 1543260684Skaiw Dwarf_P_Cie cie; 1544260684Skaiw Dwarf_P_Fde fde; 1545260684Skaiw int ret; 1546260684Skaiw 1547260684Skaiw if (STAILQ_EMPTY(&dbg->dbgp_cielist)) 1548260684Skaiw return (DW_DLE_NONE); 1549260684Skaiw 1550260684Skaiw /* Create .debug_frame section. */ 1551260684Skaiw if ((ret = _dwarf_section_init(dbg, &ds, ".debug_frame", 0, error)) != 1552260684Skaiw DW_DLE_NONE) 1553260684Skaiw goto gen_fail0; 1554260684Skaiw 1555260684Skaiw /* Create relocation section for .debug_frame */ 1556260684Skaiw RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error)); 1557260684Skaiw 1558260684Skaiw /* Generate list of CIE. */ 1559260684Skaiw STAILQ_FOREACH(cie, &dbg->dbgp_cielist, cie_next) 1560260684Skaiw RCHECK(_dwarf_frame_gen_cie(dbg, ds, cie, error)); 1561260684Skaiw 1562260684Skaiw /* Generate list of FDE. */ 1563260684Skaiw STAILQ_FOREACH(fde, &dbg->dbgp_fdelist, fde_next) 1564260684Skaiw RCHECK(_dwarf_frame_gen_fde(dbg, ds, drs, fde, error)); 1565260684Skaiw 1566260684Skaiw /* Inform application the creation of .debug_frame ELF section. */ 1567260684Skaiw RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); 1568260684Skaiw 1569260684Skaiw /* Finalize relocation section for .debug_frame */ 1570260684Skaiw RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error)); 1571260684Skaiw 1572260684Skaiw return (DW_DLE_NONE); 1573260684Skaiw 1574260684Skaiwgen_fail: 1575260684Skaiw _dwarf_reloc_section_free(dbg, &drs); 1576260684Skaiw 1577260684Skaiwgen_fail0: 1578260684Skaiw _dwarf_section_free(dbg, &ds); 1579260684Skaiw 1580260684Skaiw return (ret); 1581260684Skaiw} 1582260684Skaiw 1583260684Skaiwvoid 1584260684Skaiw_dwarf_frame_pro_cleanup(Dwarf_P_Debug dbg) 1585260684Skaiw{ 1586260684Skaiw Dwarf_P_Cie cie, tcie; 1587260684Skaiw Dwarf_P_Fde fde, tfde; 1588260684Skaiw 1589260684Skaiw assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); 1590260684Skaiw 1591260684Skaiw STAILQ_FOREACH_SAFE(cie, &dbg->dbgp_cielist, cie_next, tcie) { 1592260684Skaiw STAILQ_REMOVE(&dbg->dbgp_cielist, cie, _Dwarf_Cie, cie_next); 1593260684Skaiw if (cie->cie_augment) 1594260684Skaiw free(cie->cie_augment); 1595260684Skaiw if (cie->cie_initinst) 1596260684Skaiw free(cie->cie_initinst); 1597260684Skaiw free(cie); 1598260684Skaiw } 1599260684Skaiw dbg->dbgp_cielen = 0; 1600260684Skaiw 1601260684Skaiw STAILQ_FOREACH_SAFE(fde, &dbg->dbgp_fdelist, fde_next, tfde) { 1602260684Skaiw STAILQ_REMOVE(&dbg->dbgp_fdelist, fde, _Dwarf_Fde, fde_next); 1603260684Skaiw if (fde->fde_inst != NULL) 1604260684Skaiw free(fde->fde_inst); 1605260684Skaiw free(fde); 1606260684Skaiw } 1607260684Skaiw dbg->dbgp_fdelen = 0; 1608260684Skaiw} 1609