Blame libdwarf/dwarf_frame3.c

Packit cdaae3
/*
Packit cdaae3
Packit cdaae3
  Copyright (C) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
Packit cdaae3
  Portions Copyright (C) 2009-2011 David Anderson. All Rights Reserved.
Packit cdaae3
Packit cdaae3
  This program is free software; you can redistribute it and/or modify it
Packit cdaae3
  under the terms of version 2.1 of the GNU Lesser General Public License
Packit cdaae3
  as published by the Free Software Foundation.
Packit cdaae3
Packit cdaae3
  This program is distributed in the hope that it would be useful, but
Packit cdaae3
  WITHOUT ANY WARRANTY; without even the implied warranty of
Packit cdaae3
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit cdaae3
Packit cdaae3
  Further, this software is distributed without any warranty that it is
Packit cdaae3
  free of the rightful claim of any third person regarding infringement
Packit cdaae3
  or the like.  Any license provided herein, whether implied or
Packit cdaae3
  otherwise, applies only to this software file.  Patent licenses, if
Packit cdaae3
  any, provided herein do not apply to combinations of this program with
Packit cdaae3
  other software, or any other product whatsoever.
Packit cdaae3
Packit cdaae3
  You should have received a copy of the GNU Lesser General Public
Packit cdaae3
  License along with this program; if not, write the Free Software
Packit cdaae3
  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
Packit cdaae3
  USA.
Packit cdaae3
Packit cdaae3
*/
Packit cdaae3
Packit cdaae3
#include "config.h"
Packit cdaae3
#include "dwarf_incl.h"
Packit cdaae3
#include <stdio.h>
Packit cdaae3
#include <stdlib.h>
Packit cdaae3
#include "dwarf_frame.h"
Packit cdaae3
#include "dwarf_arange.h" /* using Arange as a way to build a list */
Packit cdaae3
Packit cdaae3
/*  Used by rqs (an IRIX application).
Packit cdaae3
    Not needed except for that one application.
Packit cdaae3
    Should be moved to its own source file since
Packit cdaae3
    it is so rarely needed.
Packit cdaae3
    Returns DW_DLV_OK if returns the arrays.
Packit cdaae3
    Returns DW_DLV_NO_ENTRY if no section. ?? (How do I tell?)
Packit cdaae3
    Returns DW_DLV_ERROR if there is an error.
Packit cdaae3
Packit cdaae3
    Uses DW_FRAME_CFA_COL because IRIX is only DWARF2
Packit cdaae3
    and that is what IRIX compilers and compatible
Packit cdaae3
    compilers support on IRIX.
Packit cdaae3
*/
Packit cdaae3
int
Packit cdaae3
_dwarf_frame_address_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrlist,
Packit cdaae3
    Dwarf_Off ** offsetlist,
Packit cdaae3
    Dwarf_Signed * returncount,
Packit cdaae3
    Dwarf_Error * err)
Packit cdaae3
{
Packit cdaae3
    int retval = DW_DLV_OK;
Packit cdaae3
    int res = DW_DLV_ERROR;
Packit cdaae3
    Dwarf_Cie *cie_data = 0;
Packit cdaae3
    Dwarf_Signed cie_count = 0;
Packit cdaae3
    Dwarf_Fde *fde_data = 0;
Packit cdaae3
    Dwarf_Signed fde_count = 0;
Packit cdaae3
    Dwarf_Signed i = 0;
Packit cdaae3
    Dwarf_Unsigned u = 0;
Packit cdaae3
    Dwarf_Frame_Op *frame_inst = 0;
Packit cdaae3
    Dwarf_Fde fdep = 0;
Packit cdaae3
    Dwarf_Cie ciep = 0;
Packit cdaae3
    Dwarf_Chain curr_chain = 0;
Packit cdaae3
    Dwarf_Chain head_chain = 0;
Packit cdaae3
    Dwarf_Chain prev_chain = 0;
Packit cdaae3
    Dwarf_Arange arange = 0;
Packit cdaae3
    Dwarf_Unsigned arange_count = 0;
Packit cdaae3
    Dwarf_Addr *arange_addrs = 0;
Packit cdaae3
    Dwarf_Off *arange_offsets = 0;
Packit cdaae3
Packit cdaae3
    res = dwarf_get_fde_list(dbg, &cie_data, &cie_count,
Packit cdaae3
        &fde_data, &fde_count, err);
Packit cdaae3
    if (res != DW_DLV_OK) {
Packit cdaae3
        return res;
Packit cdaae3
    }
Packit cdaae3
Packit cdaae3
    res = _dwarf_load_section(dbg, &dbg->de_debug_frame, err);
Packit cdaae3
    if (res != DW_DLV_OK) {
Packit cdaae3
        return res;
Packit cdaae3
    }
Packit cdaae3
    if (!dbg->de_debug_frame.dss_size) {
Packit cdaae3
        return (DW_DLV_NO_ENTRY);
Packit cdaae3
    }
Packit cdaae3
Packit cdaae3
    for (i = 0; i < cie_count; i++) {
Packit cdaae3
        Dwarf_Off instoff = 0;
Packit cdaae3
        Dwarf_Signed initial_instructions_length = 0;
Packit cdaae3
        Dwarf_Small *instr_end = 0;
Packit cdaae3
        Dwarf_Sword icount = 0;
Packit cdaae3
        int j = 0;
Packit cdaae3
Packit cdaae3
        ciep = cie_data[i];
Packit cdaae3
        instoff = ciep->ci_cie_instr_start - dbg->de_debug_frame.dss_data;
Packit cdaae3
        initial_instructions_length = ciep->ci_length +
Packit cdaae3
            ciep->ci_length_size + ciep->ci_extension_size -
Packit cdaae3
            (ciep->ci_cie_instr_start - ciep->ci_cie_start);
Packit cdaae3
        instr_end = ciep->ci_cie_instr_start +
Packit cdaae3
            initial_instructions_length;
Packit cdaae3
        res = _dwarf_exec_frame_instr( /* make_instr */ true,
Packit cdaae3
            &frame_inst,
Packit cdaae3
            /* search_pc= */ false,
Packit cdaae3
            /* search_pc_val= */ 0,
Packit cdaae3
            /* location */ 0,
Packit cdaae3
            ciep->ci_cie_instr_start,
Packit cdaae3
            instr_end,
Packit cdaae3
            /* Dwarf_frame= */ 0,
Packit cdaae3
            /* cie= */ 0,
Packit cdaae3
            dbg,
Packit cdaae3
            DW_FRAME_CFA_COL,
Packit cdaae3
            &icount,
Packit cdaae3
            NULL, NULL,err);
Packit cdaae3
        if (res == DW_DLV_ERROR) {
Packit cdaae3
            return res;
Packit cdaae3
        } else if (res == DW_DLV_NO_ENTRY) {
Packit cdaae3
            continue;
Packit cdaae3
        }
Packit cdaae3
Packit cdaae3
        for (j = 0; j < icount; ++j) {
Packit cdaae3
            Dwarf_Frame_Op *finst = frame_inst + j;
Packit cdaae3
Packit cdaae3
            if (finst->fp_base_op == 0 && finst->fp_extended_op == 1) {
Packit cdaae3
                /* is DW_CFA_set_loc */
Packit cdaae3
                Dwarf_Addr add = (Dwarf_Addr) finst->fp_offset;
Packit cdaae3
                Dwarf_Off off = finst->fp_instr_offset + instoff;
Packit cdaae3
Packit cdaae3
                arange = (Dwarf_Arange)
Packit cdaae3
                    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
Packit cdaae3
                if (arange == NULL) {
Packit cdaae3
                    _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
Packit cdaae3
                    return (DW_DLV_ERROR);
Packit cdaae3
                }
Packit cdaae3
                arange->ar_address = add;
Packit cdaae3
                arange->ar_info_offset = off;
Packit cdaae3
                arange_count++;
Packit cdaae3
                curr_chain = (Dwarf_Chain)
Packit cdaae3
                    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
Packit cdaae3
                if (curr_chain == NULL) {
Packit cdaae3
                    _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
Packit cdaae3
                    return (DW_DLV_ERROR);
Packit cdaae3
                }
Packit cdaae3
                curr_chain->ch_item = arange;
Packit cdaae3
                if (head_chain == NULL)
Packit cdaae3
                    head_chain = prev_chain = curr_chain;
Packit cdaae3
                else {
Packit cdaae3
                    prev_chain->ch_next = curr_chain;
Packit cdaae3
                    prev_chain = curr_chain;
Packit cdaae3
                }
Packit cdaae3
            }
Packit cdaae3
        }
Packit cdaae3
        dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK);
Packit cdaae3
Packit cdaae3
    }
Packit cdaae3
    for (i = 0; i < fde_count; i++) {
Packit cdaae3
        Dwarf_Small *instr_end = 0;
Packit cdaae3
        Dwarf_Sword icount = 0;
Packit cdaae3
        Dwarf_Signed instructions_length = 0;
Packit cdaae3
        Dwarf_Off instoff = 0;
Packit cdaae3
        Dwarf_Off off = 0;
Packit cdaae3
        Dwarf_Addr addr = 0;
Packit cdaae3
        int j = 0;
Packit cdaae3
Packit cdaae3
        fdep = fde_data[i];
Packit cdaae3
        off = fdep->fd_initial_loc_pos - dbg->de_debug_frame.dss_data;
Packit cdaae3
        addr = fdep->fd_initial_location;
Packit cdaae3
        arange = (Dwarf_Arange)
Packit cdaae3
            _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
Packit cdaae3
        if (arange == NULL) {
Packit cdaae3
            _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
Packit cdaae3
            return (DW_DLV_ERROR);
Packit cdaae3
        }
Packit cdaae3
        arange->ar_address = addr;
Packit cdaae3
        arange->ar_info_offset = off;
Packit cdaae3
        arange_count++;
Packit cdaae3
        curr_chain = (Dwarf_Chain)
Packit cdaae3
            _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
Packit cdaae3
        if (curr_chain == NULL) {
Packit cdaae3
            _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
Packit cdaae3
            return (DW_DLV_ERROR);
Packit cdaae3
        }
Packit cdaae3
        curr_chain->ch_item = arange;
Packit cdaae3
        if (head_chain == NULL)
Packit cdaae3
            head_chain = prev_chain = curr_chain;
Packit cdaae3
        else {
Packit cdaae3
            prev_chain->ch_next = curr_chain;
Packit cdaae3
            prev_chain = curr_chain;
Packit cdaae3
        }
Packit cdaae3
Packit cdaae3
Packit cdaae3
        instoff = fdep->fd_fde_instr_start - dbg->de_debug_frame.dss_data;
Packit cdaae3
        instructions_length = fdep->fd_length +
Packit cdaae3
            fdep->fd_length_size + fdep->fd_extension_size -
Packit cdaae3
            (fdep->fd_fde_instr_start - fdep->fd_fde_start);
Packit cdaae3
        instr_end = fdep->fd_fde_instr_start + instructions_length;
Packit cdaae3
        res = _dwarf_exec_frame_instr( /* make_instr */ true,
Packit cdaae3
            &frame_inst,
Packit cdaae3
            /* search_pc= */ false,
Packit cdaae3
            /* search_pc_val= */ 0,
Packit cdaae3
            /* location */ 0,
Packit cdaae3
            fdep->fd_fde_instr_start,
Packit cdaae3
            instr_end,
Packit cdaae3
            /* Dwarf_frame= */ 0,
Packit cdaae3
            /* cie= */ 0,
Packit cdaae3
            dbg,
Packit cdaae3
            DW_FRAME_CFA_COL,
Packit cdaae3
            &icount,
Packit cdaae3
            NULL,NULL,err);
Packit cdaae3
        if (res == DW_DLV_ERROR) {
Packit cdaae3
            return res;
Packit cdaae3
        } else if (res == DW_DLV_NO_ENTRY) {
Packit cdaae3
            continue;
Packit cdaae3
        }
Packit cdaae3
Packit cdaae3
        for (j = 0; j < icount; ++j) {
Packit cdaae3
            Dwarf_Frame_Op *finst2 = frame_inst + j;
Packit cdaae3
Packit cdaae3
            if (finst2->fp_base_op == 0 && finst2->fp_extended_op == 1) {
Packit cdaae3
                /* is DW_CFA_set_loc */
Packit cdaae3
                Dwarf_Addr add = (Dwarf_Addr) finst2->fp_offset;
Packit cdaae3
                Dwarf_Off off2 = finst2->fp_instr_offset + instoff;
Packit cdaae3
Packit cdaae3
                arange = (Dwarf_Arange)
Packit cdaae3
                    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
Packit cdaae3
                if (arange == NULL) {
Packit cdaae3
                    _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
Packit cdaae3
                    return (DW_DLV_ERROR);
Packit cdaae3
                }
Packit cdaae3
                arange->ar_address = add;
Packit cdaae3
                arange->ar_info_offset = off2;
Packit cdaae3
                arange_count++;
Packit cdaae3
                curr_chain = (Dwarf_Chain)
Packit cdaae3
                    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
Packit cdaae3
                if (curr_chain == NULL) {
Packit cdaae3
                    _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
Packit cdaae3
                    return (DW_DLV_ERROR);
Packit cdaae3
                }
Packit cdaae3
                curr_chain->ch_item = arange;
Packit cdaae3
                if (head_chain == NULL)
Packit cdaae3
                    head_chain = prev_chain = curr_chain;
Packit cdaae3
                else {
Packit cdaae3
                    prev_chain->ch_next = curr_chain;
Packit cdaae3
                    prev_chain = curr_chain;
Packit cdaae3
                }
Packit cdaae3
Packit cdaae3
            }
Packit cdaae3
        }
Packit cdaae3
        dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK);
Packit cdaae3
Packit cdaae3
    }
Packit cdaae3
    dwarf_dealloc(dbg, fde_data, DW_DLA_LIST);
Packit cdaae3
    dwarf_dealloc(dbg, cie_data, DW_DLA_LIST);
Packit cdaae3
    arange_addrs = (Dwarf_Addr *)
Packit cdaae3
        _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
Packit cdaae3
    if (arange_addrs == NULL) {
Packit cdaae3
        _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
Packit cdaae3
        return (DW_DLV_ERROR);
Packit cdaae3
    }
Packit cdaae3
    arange_offsets = (Dwarf_Off *)
Packit cdaae3
        _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
Packit cdaae3
    if (arange_offsets == NULL) {
Packit cdaae3
        _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
Packit cdaae3
        return (DW_DLV_ERROR);
Packit cdaae3
    }
Packit cdaae3
Packit cdaae3
    curr_chain = head_chain;
Packit cdaae3
    for (u = 0; u < arange_count; u++) {
Packit cdaae3
        Dwarf_Arange ar = curr_chain->ch_item;
Packit cdaae3
Packit cdaae3
        arange_addrs[u] = ar->ar_address;
Packit cdaae3
        arange_offsets[u] = ar->ar_info_offset;
Packit cdaae3
        prev_chain = curr_chain;
Packit cdaae3
        curr_chain = curr_chain->ch_next;
Packit cdaae3
        dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
Packit cdaae3
        dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
Packit cdaae3
    }
Packit cdaae3
    *returncount = arange_count;
Packit cdaae3
    *offsetlist = arange_offsets;
Packit cdaae3
    *addrlist = arange_addrs;
Packit cdaae3
    return retval;
Packit cdaae3
}