Blame dwarfexample/frame1.c

Packit cdaae3
/*
Packit cdaae3
  Copyright (c) 2009-2015 David Anderson.
Packit cdaae3
  All rights reserved.
Packit cdaae3
Packit cdaae3
  Redistribution and use in source and binary forms, with or without
Packit cdaae3
  modification, are permitted provided that the following conditions are met:
Packit cdaae3
  * Redistributions of source code must retain the above copyright
Packit cdaae3
    notice, this list of conditions and the following disclaimer.
Packit cdaae3
  * Redistributions in binary form must reproduce the above copyright
Packit cdaae3
    notice, this list of conditions and the following disclaimer in the
Packit cdaae3
    documentation and/or other materials provided with the distribution.
Packit cdaae3
  * Neither the name of the example nor the
Packit cdaae3
    names of its contributors may be used to endorse or promote products
Packit cdaae3
    derived from this software without specific prior written permission.
Packit cdaae3
Packit cdaae3
  THIS SOFTWARE IS PROVIDED BY David Anderson ''AS IS'' AND ANY
Packit cdaae3
  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Packit cdaae3
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit cdaae3
  DISCLAIMED. IN NO EVENT SHALL David Anderson BE LIABLE FOR ANY
Packit cdaae3
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Packit cdaae3
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
Packit cdaae3
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
Packit cdaae3
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit cdaae3
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
Packit cdaae3
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit cdaae3
Packit cdaae3
*/
Packit cdaae3
/*  simplereader.c
Packit cdaae3
    This is an example of code reading dwarf .debug_frame.
Packit cdaae3
    It is kept as simple as possible to expose essential features.
Packit cdaae3
    It does not do all possible error reporting or error handling.
Packit cdaae3
Packit cdaae3
    It specifically calls dwarf_expand_frame_instructions()
Packit cdaae3
    to verify that works without crashing!
Packit cdaae3
Packit cdaae3
    To use, try
Packit cdaae3
        make
Packit cdaae3
        ./frame1 frame1
Packit cdaae3
Packit cdaae3
    gcc/clang may produce .eh_frame without .debug_frame.
Packit cdaae3
    To read .eh_frame call dwarf_get_fde_list_eh()
Packit cdaae3
    below instead of dwarf_get_fde_list() .
Packit cdaae3
*/
Packit cdaae3
#include "config.h"
Packit cdaae3
#include <sys/types.h> /* For open() */
Packit cdaae3
#include <sys/stat.h>  /* For open() */
Packit cdaae3
#include <fcntl.h>     /* For open() */
Packit cdaae3
#include <stdlib.h>     /* For exit() */
Packit cdaae3
#ifdef HAVE_UNISTD_H
Packit cdaae3
#include <unistd.h>     /* For close() */
Packit cdaae3
#endif
Packit cdaae3
#include <string.h>     /* For strcmp* */
Packit cdaae3
#include <stdio.h>
Packit cdaae3
#include <errno.h>
Packit cdaae3
#include "dwarf.h"
Packit cdaae3
#include "libdwarf.h"
Packit cdaae3
Packit cdaae3
Packit cdaae3
static void read_frame_data(Dwarf_Debug dbg);
Packit cdaae3
static void print_fde_instrs(Dwarf_Debug dbg, Dwarf_Fde fde,
Packit cdaae3
    Dwarf_Error *error);
Packit cdaae3
static void print_regtable(Dwarf_Regtable3 *tab3);
Packit cdaae3
static void
Packit cdaae3
print_cie_instrs(Dwarf_Cie cie,Dwarf_Error *error);
Packit cdaae3
Packit cdaae3
Packit cdaae3
#define UNDEF_VAL 2000
Packit cdaae3
#define SAME_VAL 2001
Packit cdaae3
#define CFA_VAL 2002
Packit cdaae3
Packit cdaae3
Packit cdaae3
int
Packit cdaae3
main(int argc, char **argv)
Packit cdaae3
{
Packit cdaae3
Packit cdaae3
    Dwarf_Debug dbg = 0;
Packit cdaae3
    int fd = -1;
Packit cdaae3
    const char *filepath = "<stdin>";
Packit cdaae3
    int res = DW_DLV_ERROR;
Packit cdaae3
    Dwarf_Error error;
Packit cdaae3
    Dwarf_Handler errhand = 0;
Packit cdaae3
    Dwarf_Ptr errarg = 0;
Packit cdaae3
    int regtabrulecount = 0;
Packit cdaae3
Packit cdaae3
    if(argc < 2) {
Packit cdaae3
        fd = 0; /* stdin */
Packit cdaae3
    } else {
Packit cdaae3
        filepath = argv[1];
Packit cdaae3
        fd = open(filepath,O_RDONLY);
Packit cdaae3
    }
Packit cdaae3
    if(fd < 0) {
Packit cdaae3
        printf("Failure attempting to open %s\n",filepath);
Packit cdaae3
    }
Packit cdaae3
    res = dwarf_init(fd,DW_DLC_READ,errhand,errarg, &dbg,&error);
Packit cdaae3
    if(res != DW_DLV_OK) {
Packit cdaae3
        printf("Giving up, dwarf_init failed, cannot do DWARF processing\n");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
    /*  Do this setting after init before any real operations.
Packit cdaae3
        These return the old values, but here we do not
Packit cdaae3
        need to know the old values.  The sizes and
Packit cdaae3
        values here are higher than most ABIs and entirely
Packit cdaae3
        arbitrary.
Packit cdaae3
Packit cdaae3
        The setting of initial_value to
Packit cdaae3
        the same as undefined-value (the other possible choice being
Packit cdaae3
        same-value) is arbitrary, different ABIs do differ, and
Packit cdaae3
        you have to know which is right. */
Packit cdaae3
    regtabrulecount=1999;
Packit cdaae3
    dwarf_set_frame_undefined_value(dbg, UNDEF_VAL);
Packit cdaae3
    dwarf_set_frame_rule_initial_value(dbg, UNDEF_VAL);
Packit cdaae3
    dwarf_set_frame_same_value(dbg,SAME_VAL);
Packit cdaae3
    dwarf_set_frame_cfa_value(dbg,CFA_VAL);
Packit cdaae3
    dwarf_set_frame_rule_table_size(dbg,regtabrulecount);
Packit cdaae3
Packit cdaae3
    read_frame_data(dbg);
Packit cdaae3
    res = dwarf_finish(dbg,&error);
Packit cdaae3
    if(res != DW_DLV_OK) {
Packit cdaae3
        printf("dwarf_finish failed!\n");
Packit cdaae3
    }
Packit cdaae3
    close(fd);
Packit cdaae3
    return 0;
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static void
Packit cdaae3
read_frame_data(Dwarf_Debug dbg)
Packit cdaae3
{
Packit cdaae3
    Dwarf_Error error;
Packit cdaae3
    Dwarf_Signed cie_element_count = 0;
Packit cdaae3
    Dwarf_Signed fde_element_count = 0;
Packit cdaae3
    Dwarf_Cie *cie_data = 0;
Packit cdaae3
    Dwarf_Fde *fde_data = 0;
Packit cdaae3
    int res = DW_DLV_ERROR;
Packit cdaae3
    Dwarf_Signed fdenum = 0;
Packit cdaae3
Packit cdaae3
Packit cdaae3
    /*  If you wish to read .eh_frame data, use
Packit cdaae3
        dwarf_get_fde_list_eh() instead.  */
Packit cdaae3
    res = dwarf_get_fde_list(dbg,&cie_data,&cie_element_count,
Packit cdaae3
        &fde_data,&fde_element_count,&error);
Packit cdaae3
    if(res == DW_DLV_NO_ENTRY) {
Packit cdaae3
        printf("No .debug_frame data present\n");
Packit cdaae3
        printf("Try dwarf_get_fde_list_eh() to read .eh_frame data\n");
Packit cdaae3
        exit(0);
Packit cdaae3
    }
Packit cdaae3
    if( res == DW_DLV_ERROR) {
Packit cdaae3
        printf("Error reading frame data ");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
    printf( "%" DW_PR_DSd " cies present. "
Packit cdaae3
        "%" DW_PR_DSd " fdes present. \n",
Packit cdaae3
        cie_element_count,fde_element_count);
Packit cdaae3
    /*if(fdenum >= fde_element_count) {
Packit cdaae3
        printf("Want fde %d but only %" DW_PR_DSd " present\n",fdenum,
Packit cdaae3
            fde_element_count);
Packit cdaae3
        exit(1);
Packit cdaae3
    }*/
Packit cdaae3
Packit cdaae3
    for(fdenum = 0; fdenum < fde_element_count; ++fdenum) {
Packit cdaae3
        Dwarf_Cie cie = 0;
Packit cdaae3
        printf("Print cie of fde %" DW_PR_DSd  "\n",fdenum);
Packit cdaae3
        res = dwarf_get_cie_of_fde(fde_data[fdenum],&cie,&error);
Packit cdaae3
        if(res != DW_DLV_OK) {
Packit cdaae3
            printf("Error accessing fdenum %" DW_PR_DSd
Packit cdaae3
                " to get its cie\n",fdenum);
Packit cdaae3
            exit(1);
Packit cdaae3
        }
Packit cdaae3
        print_cie_instrs(cie,&error);
Packit cdaae3
        printf("Print fde %" DW_PR_DSd  "\n",fdenum);
Packit cdaae3
        print_fde_instrs(dbg,fde_data[fdenum],&error);
Packit cdaae3
    }
Packit cdaae3
Packit cdaae3
    /* Done with the data. */
Packit cdaae3
    dwarf_fde_cie_list_dealloc(dbg,cie_data,cie_element_count,
Packit cdaae3
        fde_data, fde_element_count);
Packit cdaae3
    return;
Packit cdaae3
}
Packit cdaae3
static void
Packit cdaae3
print_cie_instrs(Dwarf_Cie cie,Dwarf_Error *error)
Packit cdaae3
{
Packit cdaae3
    int res = DW_DLV_ERROR;
Packit cdaae3
    Dwarf_Unsigned bytes_in_cie = 0;
Packit cdaae3
    Dwarf_Small version = 0;
Packit cdaae3
    char *augmentation = 0;
Packit cdaae3
    Dwarf_Unsigned code_alignment_factor = 0;
Packit cdaae3
    Dwarf_Signed data_alignment_factor = 0;
Packit cdaae3
    Dwarf_Half return_address_register_rule = 0;
Packit cdaae3
    Dwarf_Ptr instrp = 0;
Packit cdaae3
    Dwarf_Unsigned instr_len = 0;
Packit cdaae3
Packit cdaae3
    res = dwarf_get_cie_info(cie,&bytes_in_cie,
Packit cdaae3
        &version, &augmentation, &code_alignment_factor,
Packit cdaae3
        &data_alignment_factor, &return_address_register_rule,
Packit cdaae3
        &instrp,&instr_len,error);
Packit cdaae3
    if(res != DW_DLV_OK) {
Packit cdaae3
        printf("Unable to get cie info!\n");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static void
Packit cdaae3
print_frame_instrs(Dwarf_Frame_Op *frame_op_list,
Packit cdaae3
  Dwarf_Signed frame_op_count)
Packit cdaae3
{
Packit cdaae3
    Dwarf_Signed i = 0;
Packit cdaae3
    printf("Base op. Ext op. Reg. Offset. Instr-offset.\n");
Packit cdaae3
    for(i = 0; i < frame_op_count; ++i) {
Packit cdaae3
        printf("[%" DW_PR_DSd "]", i);
Packit cdaae3
        printf(" %d. ", frame_op_list[i].fp_base_op);
Packit cdaae3
        printf(" %d. ", frame_op_list[i].fp_extended_op);
Packit cdaae3
        printf(" %" DW_PR_DSd ". ", frame_op_list[i].fp_offset);
Packit cdaae3
        printf(" 0x%" DW_PR_DUx ". ", frame_op_list[i].fp_instr_offset);
Packit cdaae3
        printf("\n");
Packit cdaae3
    }
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static void
Packit cdaae3
print_fde_instrs(Dwarf_Debug dbg,
Packit cdaae3
    Dwarf_Fde fde, Dwarf_Error *error)
Packit cdaae3
{
Packit cdaae3
    int res;
Packit cdaae3
    Dwarf_Addr lowpc = 0;
Packit cdaae3
    Dwarf_Unsigned func_length = 0;
Packit cdaae3
    Dwarf_Ptr fde_bytes;
Packit cdaae3
    Dwarf_Unsigned fde_byte_length = 0;
Packit cdaae3
    Dwarf_Off cie_offset = 0;
Packit cdaae3
    Dwarf_Signed cie_index = 0;
Packit cdaae3
    Dwarf_Off fde_offset = 0;
Packit cdaae3
    Dwarf_Addr arbitrary_addr = 0;
Packit cdaae3
    Dwarf_Addr actual_pc = 0;
Packit cdaae3
    Dwarf_Regtable3 tab3;
Packit cdaae3
    int oldrulecount = 0;
Packit cdaae3
    Dwarf_Ptr outinstrs = 0;
Packit cdaae3
    Dwarf_Unsigned instrslen = 0;
Packit cdaae3
    Dwarf_Frame_Op * frame_op_list = 0;
Packit cdaae3
    Dwarf_Signed frame_op_count = 0;
Packit cdaae3
    Dwarf_Cie cie = 0;
Packit cdaae3
Packit cdaae3
Packit cdaae3
    res = dwarf_get_fde_range(fde,&lowpc,&func_length,&fde_bytes,
Packit cdaae3
        &fde_byte_length,&cie_offset,&cie_index,&fde_offset,error);
Packit cdaae3
    if(res != DW_DLV_OK) {
Packit cdaae3
        printf("Problem getting fde range \n");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
Packit cdaae3
    arbitrary_addr = lowpc + (func_length/2);
Packit cdaae3
    printf("function low pc 0x%" DW_PR_DUx
Packit cdaae3
        "  and length 0x%" DW_PR_DUx
Packit cdaae3
        "  and addr we choose 0x%" DW_PR_DUx
Packit cdaae3
        "\n",
Packit cdaae3
        lowpc,func_length,arbitrary_addr);
Packit cdaae3
Packit cdaae3
    /*  1 is arbitrary. We are winding up getting the
Packit cdaae3
        rule count here while leaving things unchanged. */
Packit cdaae3
    oldrulecount = dwarf_set_frame_rule_table_size(dbg,1);
Packit cdaae3
    dwarf_set_frame_rule_table_size(dbg,oldrulecount);
Packit cdaae3
Packit cdaae3
    tab3.rt3_reg_table_size = oldrulecount;
Packit cdaae3
    tab3.rt3_rules = (struct Dwarf_Regtable_Entry3_s *) malloc(
Packit cdaae3
        sizeof(struct Dwarf_Regtable_Entry3_s)* oldrulecount);
Packit cdaae3
    if (!tab3.rt3_rules) {
Packit cdaae3
        printf("Unable to malloc for %d rules\n",oldrulecount);
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
Packit cdaae3
    res = dwarf_get_fde_info_for_all_regs3(fde,arbitrary_addr ,
Packit cdaae3
        &tab3,&actual_pc,error);
Packit cdaae3
Packit cdaae3
    if(res != DW_DLV_OK) {
Packit cdaae3
        printf("dwarf_get_fde_info_for_all_regs3 failed!\n");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
    print_regtable(&tab3);
Packit cdaae3
Packit cdaae3
    res = dwarf_get_fde_instr_bytes(fde,&outinstrs,&instrslen,error);
Packit cdaae3
    if(res != DW_DLV_OK) {
Packit cdaae3
        printf("dwarf_get_fde_instr_bytes failed!\n");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
    res = dwarf_get_cie_of_fde(fde,&cie,error);
Packit cdaae3
    if(res != DW_DLV_OK) {
Packit cdaae3
        printf("Error getting cie from fde\n");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
Packit cdaae3
    res = dwarf_expand_frame_instructions(cie,
Packit cdaae3
        outinstrs,instrslen,&frame_op_list,
Packit cdaae3
        &frame_op_count,error);
Packit cdaae3
    if(res != DW_DLV_OK) {
Packit cdaae3
        printf("dwarf_expand_frame_instructions failed!\n");
Packit cdaae3
        exit(1);
Packit cdaae3
    }
Packit cdaae3
    printf("Frame op count: %" DW_PR_DUu "\n",frame_op_count);
Packit cdaae3
    print_frame_instrs(frame_op_list,frame_op_count);
Packit cdaae3
Packit cdaae3
    dwarf_dealloc(dbg,frame_op_list, DW_DLA_FRAME_BLOCK);
Packit cdaae3
    free(tab3.rt3_rules);
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static void
Packit cdaae3
print_reg(int r)
Packit cdaae3
{
Packit cdaae3
   switch(r) {
Packit cdaae3
   case SAME_VAL:
Packit cdaae3
        printf(" %d SAME_VAL ",r);
Packit cdaae3
        break;
Packit cdaae3
   case UNDEF_VAL:
Packit cdaae3
        printf(" %d UNDEF_VAL ",r);
Packit cdaae3
        break;
Packit cdaae3
   case CFA_VAL:
Packit cdaae3
        printf(" %d (CFA) ",r);
Packit cdaae3
        break;
Packit cdaae3
   default:
Packit cdaae3
        printf(" r%d ",r);
Packit cdaae3
        break;
Packit cdaae3
   }
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static void
Packit cdaae3
print_one_regentry(const char *prefix,
Packit cdaae3
    struct Dwarf_Regtable_Entry3_s *entry)
Packit cdaae3
{
Packit cdaae3
    int is_cfa = !strcmp("cfa",prefix);
Packit cdaae3
    printf("%s ",prefix);
Packit cdaae3
    printf("type: %d %s ",
Packit cdaae3
        entry->dw_value_type,
Packit cdaae3
        (entry->dw_value_type == DW_EXPR_OFFSET)? "DW_EXPR_OFFSET":
Packit cdaae3
        (entry->dw_value_type == DW_EXPR_VAL_OFFSET)? "DW_EXPR_VAL_OFFSET":
Packit cdaae3
        (entry->dw_value_type == DW_EXPR_EXPRESSION)? "DW_EXPR_EXPRESSION":
Packit cdaae3
        (entry->dw_value_type == DW_EXPR_VAL_EXPRESSION)?
Packit cdaae3
            "DW_EXPR_VAL_EXPRESSION":
Packit cdaae3
            "Unknown");
Packit cdaae3
    switch(entry->dw_value_type) {
Packit cdaae3
    case DW_EXPR_OFFSET:
Packit cdaae3
        print_reg(entry->dw_regnum);
Packit cdaae3
        printf(" offset_rel? %d ",entry->dw_offset_relevant);
Packit cdaae3
        if(entry->dw_offset_relevant) {
Packit cdaae3
            printf(" offset  %" DW_PR_DSd " " ,
Packit cdaae3
                entry->dw_offset_or_block_len);
Packit cdaae3
            if(is_cfa) {
Packit cdaae3
                printf("defines cfa value");
Packit cdaae3
            } else {
Packit cdaae3
                printf("address of value is CFA plus signed offset");
Packit cdaae3
            }
Packit cdaae3
            if(!is_cfa  && entry->dw_regnum != CFA_VAL) {
Packit cdaae3
                printf(" compiler botch, regnum != CFA_VAL");
Packit cdaae3
            }
Packit cdaae3
        } else {
Packit cdaae3
            printf("value in register");
Packit cdaae3
        }
Packit cdaae3
        break;
Packit cdaae3
    case DW_EXPR_VAL_OFFSET:
Packit cdaae3
        print_reg(entry->dw_regnum);
Packit cdaae3
        printf(" offset  %" DW_PR_DSd " " ,
Packit cdaae3
            entry->dw_offset_or_block_len);
Packit cdaae3
        if(is_cfa) {
Packit cdaae3
            printf("does this make sense? No?");
Packit cdaae3
        } else {
Packit cdaae3
            printf("value at CFA plus signed offset");
Packit cdaae3
        }
Packit cdaae3
        if(!is_cfa  && entry->dw_regnum != CFA_VAL) {
Packit cdaae3
            printf(" compiler botch, regnum != CFA_VAL");
Packit cdaae3
        }
Packit cdaae3
        break;
Packit cdaae3
    case DW_EXPR_EXPRESSION:
Packit cdaae3
        print_reg(entry->dw_regnum);
Packit cdaae3
        printf(" offset_rel? %d ",entry->dw_offset_relevant);
Packit cdaae3
        printf(" offset  %" DW_PR_DSd " " ,
Packit cdaae3
            entry->dw_offset_or_block_len);
Packit cdaae3
        printf("Block ptr set? %s ",entry->dw_block_ptr?"yes":"no");
Packit cdaae3
        printf(" Value is at address given by expr val ");
Packit cdaae3
        /* printf(" block-ptr  0x%" DW_PR_DUx " ",
Packit cdaae3
            (Dwarf_Unsigned)entry->dw_block_ptr); */
Packit cdaae3
        break;
Packit cdaae3
    case DW_EXPR_VAL_EXPRESSION:
Packit cdaae3
        printf(" expression byte len  %" DW_PR_DSd " " ,
Packit cdaae3
            entry->dw_offset_or_block_len);
Packit cdaae3
        printf("Block ptr set? %s ",entry->dw_block_ptr?"yes":"no");
Packit cdaae3
        printf(" Value is expr val ");
Packit cdaae3
        if(!entry->dw_block_ptr) {
Packit cdaae3
            printf("Compiler botch. ");
Packit cdaae3
        }
Packit cdaae3
        /* printf(" block-ptr  0x%" DW_PR_DUx " ",
Packit cdaae3
            (Dwarf_Unsigned)entry->dw_block_ptr); */
Packit cdaae3
        break;
Packit cdaae3
    }
Packit cdaae3
    printf("\n");
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
static void
Packit cdaae3
print_regtable(Dwarf_Regtable3 *tab3)
Packit cdaae3
{
Packit cdaae3
    int r;
Packit cdaae3
    /* We won't print too much. A bit arbitrary. */
Packit cdaae3
    int max = 10;
Packit cdaae3
    if(max > tab3->rt3_reg_table_size) {
Packit cdaae3
        max = tab3->rt3_reg_table_size;
Packit cdaae3
    }
Packit cdaae3
    print_one_regentry("cfa",&tab3->rt3_cfa_rule);
Packit cdaae3
Packit cdaae3
    for(r = 0; r < max; r++) {
Packit cdaae3
        char rn[30];
Packit cdaae3
        snprintf(rn,sizeof(rn),"reg %d",r);
Packit cdaae3
        print_one_regentry(rn,tab3->rt3_rules+r);
Packit cdaae3
    }
Packit cdaae3
Packit cdaae3
Packit cdaae3
}
Packit cdaae3
Packit cdaae3
Packit cdaae3
Packit cdaae3