1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-12-23 03:53:43 +01:00

(Logical change 1.145)

This commit is contained in:
hp.com!davidm 2003-12-20 11:43:08 +00:00
parent 67921394ac
commit eb51b4294a
16 changed files with 3027 additions and 0 deletions

View file

@ -0,0 +1,630 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef dwarf_h
#define dwarf_h
#include "internal.h"
#include "mempool.h"
struct dwarf_cursor; /* forward-declaration */
#include "dwarf-config.h"
/* DWARF expression opcodes. */
typedef enum
{
DW_OP_addr = 0x03,
DW_OP_deref = 0x06,
DW_OP_const1u = 0x08,
DW_OP_const1s = 0x09,
DW_OP_const2u = 0x0a,
DW_OP_const2s = 0x0b,
DW_OP_const4u = 0x0c,
DW_OP_const4s = 0x0d,
DW_OP_const8u = 0x0e,
DW_OP_const8s = 0x0f,
DW_OP_constu = 0x10,
DW_OP_consts = 0x11,
DW_OP_dup = 0x12,
DW_OP_drop = 0x13,
DW_OP_over = 0x14,
DW_OP_pick = 0x15,
DW_OP_swap = 0x16,
DW_OP_rot = 0x17,
DW_OP_xderef = 0x18,
DW_OP_abs = 0x19,
DW_OP_and = 0x1a,
DW_OP_div = 0x1b,
DW_OP_minus = 0x1c,
DW_OP_mod = 0x1d,
DW_OP_mul = 0x1e,
DW_OP_neg = 0x1f,
DW_OP_not = 0x20,
DW_OP_or = 0x21,
DW_OP_plus = 0x22,
DW_OP_plus_uconst = 0x23,
DW_OP_shl = 0x24,
DW_OP_shr = 0x25,
DW_OP_shra = 0x26,
DW_OP_xor = 0x27,
DW_OP_skip = 0x2f,
DW_OP_bra = 0x28,
DW_OP_eq = 0x29,
DW_OP_ge = 0x2a,
DW_OP_gt = 0x2b,
DW_OP_le = 0x2c,
DW_OP_lt = 0x2d,
DW_OP_ne = 0x2e,
DW_OP_lit0 = 0x30,
DW_OP_lit1, DW_OP_lit2, DW_OP_lit3, DW_OP_lit4, DW_OP_lit5,
DW_OP_lit6, DW_OP_lit7, DW_OP_lit8, DW_OP_lit9, DW_OP_lit10,
DW_OP_lit11, DW_OP_lit12, DW_OP_lit13, DW_OP_lit14, DW_OP_lit15,
DW_OP_lit16, DW_OP_lit17, DW_OP_lit18, DW_OP_lit19, DW_OP_lit20,
DW_OP_lit21, DW_OP_lit22, DW_OP_lit23, DW_OP_lit24, DW_OP_lit25,
DW_OP_lit26, DW_OP_lit27, DW_OP_lit28, DW_OP_lit29, DW_OP_lit30,
DW_OP_lit31,
DW_OP_reg0 = 0x50,
DW_OP_reg1, DW_OP_reg2, DW_OP_reg3, DW_OP_reg4, DW_OP_reg5,
DW_OP_reg6, DW_OP_reg7, DW_OP_reg8, DW_OP_reg9, DW_OP_reg10,
DW_OP_reg11, DW_OP_reg12, DW_OP_reg13, DW_OP_reg14, DW_OP_reg15,
DW_OP_reg16, DW_OP_reg17, DW_OP_reg18, DW_OP_reg19, DW_OP_reg20,
DW_OP_reg21, DW_OP_reg22, DW_OP_reg23, DW_OP_reg24, DW_OP_reg25,
DW_OP_reg26, DW_OP_reg27, DW_OP_reg28, DW_OP_reg29, DW_OP_reg30,
DW_OP_reg31,
DW_OP_breg0 = 0x70,
DW_OP_breg1, DW_OP_breg2, DW_OP_breg3, DW_OP_breg4, DW_OP_breg5,
DW_OP_breg6, DW_OP_breg7, DW_OP_breg8, DW_OP_breg9, DW_OP_breg10,
DW_OP_breg11, DW_OP_breg12, DW_OP_breg13, DW_OP_breg14, DW_OP_breg15,
DW_OP_breg16, DW_OP_breg17, DW_OP_breg18, DW_OP_breg19, DW_OP_breg20,
DW_OP_breg21, DW_OP_breg22, DW_OP_breg23, DW_OP_breg24, DW_OP_breg25,
DW_OP_breg26, DW_OP_breg27, DW_OP_breg28, DW_OP_breg29, DW_OP_breg30,
DW_OP_breg31,
DW_OP_regx = 0x90,
DW_OP_fbreg = 0x91,
DW_OP_bregx = 0x92,
DW_OP_piece = 0x93,
DW_OP_deref_size = 0x94,
DW_OP_xderef_size = 0x95,
DW_OP_nop = 0x96,
DW_OP_push_object_address = 0x97,
DW_OP_call2 = 0x98,
DW_OP_call4 = 0x99,
DW_OP_call_ref = 0x9a,
DW_OP_lo_user = 0xe0,
DW_OP_hi_user = 0xff
}
dwarf_expr_op_t;
#define DWARF_CIE_VERSION 3 /* GCC emits version 1??? */
#define DWARF_CFA_OPCODE_MASK 0xc0
#define DWARF_CFA_OPERAND_MASK 0x3f
typedef enum
{
DW_CFA_advance_loc = 0x40,
DW_CFA_offset = 0x80,
DW_CFA_restore = 0xc0,
DW_CFA_nop = 0x00,
DW_CFA_set_loc = 0x01,
DW_CFA_advance_loc1 = 0x02,
DW_CFA_advance_loc2 = 0x03,
DW_CFA_advance_loc4 = 0x04,
DW_CFA_offset_extended = 0x05,
DW_CFA_restore_extended = 0x06,
DW_CFA_undefined = 0x07,
DW_CFA_same_value = 0x08,
DW_CFA_register = 0x09,
DW_CFA_remember_state = 0x0a,
DW_CFA_restore_state = 0x0b,
DW_CFA_def_cfa = 0x0c,
DW_CFA_def_cfa_register = 0x0d,
DW_CFA_def_cfa_offset = 0x0e,
DW_CFA_def_cfa_expression = 0x0f,
DW_CFA_CFA_expression = 0x10,
DW_CFA_offset_extended_sf = 0x11,
DW_CFA_def_cfa_sf = 0x12,
DW_CFA_def_cfa_offset_sf = 0x13,
DW_CFA_lo_user = 0x1c,
DW_CFA_MIPS_advance_loc8 = 0x1d,
DW_CFA_GNU_window_save = 0x2d,
DW_CFA_GNU_args_size = 0x2e,
DW_CFA_GNU_negative_offset_extended = 0x2f,
DW_CFA_hi_user = 0x3c
}
dwarf_cfa_t;
/* DWARF Pointer-Encoding (PEs).
Pointer-Encodings were invented for the GCC exception-handling
support for C++, but they represent a rather generic way of
describing the format in which an address/pointer is stored and
hence we include the definitions here, in the main dwarf.h file.
The Pointer-Encoding format is partially documented in Linux Base
Spec v1.3 (http://www.linuxbase.org/spec/). The rest is reverse
engineered from GCC.
*/
#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */
#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */
/* Flag bit. If set, the resulting pointer is the address of the word
that contains the final address. */
#define DW_EH_PE_indirect 0x80
/* Pointer-encoding formats: */
#define DW_EH_PE_omit 0xff
#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */
#define DW_EH_PE_uleb128 0x01 /* unsigned LE base-128 value */
#define DW_EH_PE_udata2 0x02 /* unsigned 16-bit value */
#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */
#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */
#define DW_EH_PE_sleb128 0x09 /* signed LE base-128 value */
#define DW_EH_PE_sdata2 0x0a /* signed 16-bit value */
#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */
#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */
/* Pointer-encoding application: */
#define DW_EH_PE_absptr 0x00 /* absolute value */
#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */
#define DW_EH_PE_textrel 0x20 /* text-relative (GCC-specific???) */
#define DW_EH_PE_datarel 0x30 /* data-relative */
/* The following are not documented by LSB v1.3, yet they are used by
GCC, presumably they aren't documented by LSB since they aren't
used on Linux: */
#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */
#define DW_EH_PE_aligned 0x50 /* aligned pointer */
extern HIDDEN struct mempool dwarf_reg_state_pool;
#ifdef UNW_LOCAL_ONLY
/* In the local-only case, we can let the compiler directly access
memory and don't need to worry about differing byte-order. */
typedef union
{
int8_t s8;
int16_t s16;
int32_t s32;
int64_t s64;
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
unw_word_t w;
void *ptr;
}
dwarf_misaligned_value_t __attribute__ ((packed));
static inline int
dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int8_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->s8;
*addr += sizeof (mvp->s8);
return 0;
}
static inline int
dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int16_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->s16;
*addr += sizeof (mvp->s16);
return 0;
}
static inline int
dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int32_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->s32;
*addr += sizeof (mvp->s32);
return 0;
}
static inline int
dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int64_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->s64;
*addr += sizeof (mvp->s64);
return 0;
}
static inline int
dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint8_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->u8;
*addr += sizeof (mvp->u8);
return 0;
}
static inline int
dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint16_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->u16;
*addr += sizeof (mvp->u16);
return 0;
}
static inline int
dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint32_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->u32;
*addr += sizeof (mvp->u32);
return 0;
}
static inline int
dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint64_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->u64;
*addr += sizeof (mvp->u64);
return 0;
}
static inline int
dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->w;
*addr += sizeof (mvp->w);
return 0;
}
static inline int
dwarf_readptr (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = (unw_word_t) mvp->ptr;
*addr += sizeof (mvp->ptr);
return 0;
}
#else /* !UNW_LOCAL_ONLY */
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
FIX ME
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
typedef union
{
int8_t s8;
int16_t s16;
int32_t s32;
int64_t s64;
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
unw_word_t w;
void *ptr;
}
dwarf_misaligned_value_t __attribute__ ((packed));
static inline int
dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int8_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->s8;
*addr += sizeof (mvp->s8);
return 0;
}
static inline int
dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int16_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->s16;
*addr += sizeof (mvp->s16);
return 0;
}
static inline int
dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int32_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->s32;
*addr += sizeof (mvp->s32);
return 0;
}
static inline int
dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int64_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->s64;
*addr += sizeof (mvp->s64);
return 0;
}
static inline int
dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint8_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->u8;
*addr += sizeof (mvp->u8);
return 0;
}
static inline int
dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint16_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->u16;
*addr += sizeof (mvp->u16);
return 0;
}
static inline int
dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint32_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->u32;
*addr += sizeof (mvp->u32);
return 0;
}
static inline int
dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint64_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->u64;
*addr += sizeof (mvp->u64);
return 0;
}
static inline int
dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->w;
*addr += sizeof (mvp->w);
return 0;
}
static inline int
dwarf_readptr (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = (unw_word_t) mvp->ptr;
*addr += sizeof (mvp->ptr);
return 0;
}
#endif /* !UNW_LOCAL_ONLY */
/* Read an unsigned "little-endian base 128" value. See Chapter 7.6
of DWARF spec v3. */
static inline int
dwarf_read_uleb128 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *valp, void *arg)
{
unw_word_t val = 0, shift = 0;
unsigned char byte;
int ret;
do
{
if ((ret = dwarf_readu8 (as, a, addr, &byte, arg)) < 0)
return ret;
val |= ((unw_word_t) byte & 0x7f) << shift;
shift += 7;
}
while (byte & 0x80);
*valp = val;
return 0;
}
/* Read a signed "little-endian base 128" value. See Chapter 7.6 of
DWARF spec v3. */
static inline int
dwarf_read_sleb128 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *valp, void *arg)
{
unw_word_t val = 0, shift = 0;
unsigned char byte;
int ret;
do
{
if ((ret = dwarf_readu8 (as, a, addr, &byte, arg)) < 0)
return ret;
val |= ((unw_word_t) byte & 0x7f) << shift;
shift += 7;
}
while (byte & 0x80);
if (shift < 8 * sizeof (unw_word_t) && (byte & 0x40) != 0)
/* sign-extend negative value */
val |= ((unw_word_t) -1) << shift;
*valp = val;
return 0;
}
typedef enum
{
DWARF_WHERE_UNDEF, /* register isn't saved at all */
DWARF_WHERE_SAME, /* register has same value as in prev. frame */
DWARF_WHERE_CFAREL, /* register saved at CFA-relative address */
DWARF_WHERE_REG, /* register saved in another register */
DWARF_WHERE_EXPR, /* register saved */
}
dwarf_where_t;
typedef struct
{
dwarf_where_t where; /* how is the register saved? */
unw_word_t val; /* where it's saved */
}
dwarf_save_loc_t;
/* For uniformity, we'd like to treat the CFA save-location like any
other register save-location, but this doesn't quite work, because
the CFA can be expressed as a (REGISTER,OFFSET) pair. To handle
this, we use two dwarf_save_loc structures to describe the CFA.
The first one (CFA_REG_COLUMN), tells us where the CFA is saved.
In the case of DWARF_WHERE_EXPR, the CFA is defined by a DWARF
location expression whose address is given by member "val". In the
case of DWARF_WHERE_REG, member "val" gives the number of the
base-register and the "val" member of DWARF_CFA_OFF_COLUMN gives
the offset value. */
#define DWARF_CFA_REG_COLUMN DWARF_NUM_PRESERVED_REGS
#define DWARF_CFA_OFF_COLUMN (DWARF_NUM_PRESERVED_REGS + 1)
typedef struct dwarf_reg_state
{
struct dwarf_reg_state *next; /* for rs_stack */
dwarf_save_loc_t reg[DWARF_NUM_PRESERVED_REGS + 2];
}
dwarf_reg_state_t;
typedef struct dwarf_state_record
{
unsigned char fde_encoding;
unw_word_t args_size;
dwarf_reg_state_t rs_initial; /* reg-state after CIE instructions */
dwarf_reg_state_t rs_current; /* current reg-state */
}
dwarf_state_record_t;
typedef struct dwarf_cursor
{
void *as_arg; /* argument to address-space callbacks */
unw_addr_space_t as; /* reference to per-address-space info */
unw_word_t cfa; /* canonical frame address; aka frame-/stack-pointer */
unw_word_t ip; /* instruction pointer */
unw_word_t args_size; /* size of arguments */
unw_word_t ret_addr_column; /* column for return-address */
dwarf_loc_t loc[DWARF_NUM_PRESERVED_REGS];
unsigned int pi_valid :1; /* is proc_info valid? */
unsigned int pi_is_dynamic :1; /* proc_info found via dynamic proc info? */
unw_proc_info_t pi; /* info about current procedure */
}
dwarf_cursor_t;
/* Convenience macros: */
#define dwarf_init UNW_ARCH_OBJ (dwarf_init)
#define dwarf_find_proc_info UNW_OBJ (dwarf_find_proc_info)
#define dwarf_search_unwind_table UNW_OBJ (dwarf_search_unwind_table)
#define dwarf_put_unwind_info UNW_OBJ (dwarf_put_unwind_info)
#define dwarf_put_unwind_info UNW_OBJ (dwarf_put_unwind_info)
#define dwarf_eval_expr UNW_OBJ (dwarf_eval_expr)
#define dwarf_parse_fde UNW_OBJ (dwarf_parse_fde)
#define dwarf_find_save_locs UNW_OBJ (dwarf_find_save_locs)
#define dwarf_create_state_record UNW_OBJ (dwarf_create_state_record)
#define dwarf_make_proc_info UNW_OBJ (dwarf_make_proc_info)
#define dwarf_read_encoded_pointer UNW_OBJ (dwarf_read_encoded_pointer)
#define dwarf_step UNW_OBJ (dwarf_step)
extern HIDDEN int dwarf_init (void);
extern HIDDEN int dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi,
int need_unwind_info, void *arg);
extern HIDDEN int dwarf_search_unwind_table (unw_addr_space_t as,
unw_word_t ip,
unw_dyn_info_t *di,
unw_proc_info_t *pi,
int need_unwind_info, void *arg);
extern HIDDEN void dwarf_put_unwind_info (unw_addr_space_t as,
unw_proc_info_t *pi, void *arg);
extern HIDDEN int dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr,
unw_word_t len, unw_word_t *valp,
int *is_register);
extern HIDDEN int dwarf_parse_fde (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unw_proc_info_t *pi,
unw_dyn_dwarf_fde_info_t *dfi, void *arg);
extern HIDDEN int dwarf_find_save_locs (struct dwarf_cursor *c);
extern HIDDEN int dwarf_create_state_record (struct dwarf_cursor *c,
dwarf_state_record_t *sr);
extern HIDDEN int dwarf_make_proc_info (struct dwarf_cursor *c);
extern HIDDEN int dwarf_read_encoded_pointer (unw_addr_space_t as,
unw_accessors_t *a,
unw_word_t *addr,
unsigned char encoding,
unw_proc_info_t *pi,
unw_word_t *valp, void *arg);
extern HIDDEN int dwarf_step (struct dwarf_cursor *c);
#endif /* dwarf_h */

View file

@ -0,0 +1,59 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef dwarf_config_h
#define dwarf_config_h
/* This matches the value used by GCC, which leaves plenty of room for
expansion. */
#define DWARF_NUM_PRESERVED_REGS 17
/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */
#define dwarf_is_big_endian(addr_space) 0
/* Convert a pointer to a dwarf_cursor structure to a pointer to
unw_cursor_t. */
#define dwarf_to_cursor(c) ((unw_cursor_t *) (c))
HIDDEN extern uint8_t dwarf_to_unw_regnum_map[19];
static inline unw_regnum_t
dwarf_to_unw_regnum (unw_word_t regnum)
{
if (regnum <= NELEMS (dwarf_to_unw_regnum_map))
return dwarf_to_unw_regnum_map[regnum];
return 0;
}
typedef struct dwarf_loc
{
unw_word_t val;
#ifndef UNW_LOCAL_ONLY
unw_word_t type; /* see X86_LOC_TYPE_* macros. */
#endif
}
dwarf_loc_t;
#endif /* dwarf_config_h */

View file

@ -0,0 +1,578 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "dwarf.h"
#include "tdep.h"
/* The "pick" operator provides an index range of 0..255 indicating
that the stack could at least have a depth of up to 256 elements,
but the GCC unwinder restricts the depth to 64, which seems
reasonable so we use the same value here. */
#define MAX_EXPR_STACK_SIZE 64
#define NUM_OPERANDS(signature) (((signature) >> 6) & 0x3)
#define OPND1_TYPE(signature) (((signature) >> 3) & 0x7)
#define OPND2_TYPE(signature) (((signature) >> 0) & 0x7)
#define OPND_SIGNATURE(n, t1, t2) (((n) << 6) | ((t1) << 3) | ((t2) << 0))
#define OPND1(t1) OPND_SIGNATURE(1, t1, 0)
#define OPND2(t1, t2) OPND_SIGNATURE(2, t1, t2)
#define VAL8 0x0
#define VAL16 0x1
#define VAL32 0x2
#define VAL64 0x3
#define ULEB128 0x4
#define SLEB128 0x5
#define OFFSET 0x6 /* 32-bit offset for 32-bit DWARF, 64-bit otherwise */
static uint8_t operands[256] =
{
[DW_OP_addr] = OPND1 (sizeof (unw_word_t) == 4 ? VAL32 : VAL64),
[DW_OP_const1u] = OPND1 (VAL8),
[DW_OP_const1s] = OPND1 (VAL8),
[DW_OP_const2u] = OPND1 (VAL16),
[DW_OP_const2s] = OPND1 (VAL16),
[DW_OP_const4u] = OPND1 (VAL32),
[DW_OP_const4s] = OPND1 (VAL32),
[DW_OP_const8u] = OPND1 (VAL64),
[DW_OP_const8s] = OPND1 (VAL64),
[DW_OP_pick] = OPND1 (VAL8),
[DW_OP_plus_uconst] = OPND1 (ULEB128),
[DW_OP_skip] = OPND1 (VAL16),
[DW_OP_bra] = OPND1 (VAL16),
[DW_OP_breg0 + 0] = OPND1 (SLEB128),
[DW_OP_breg0 + 1] = OPND1 (SLEB128),
[DW_OP_breg0 + 2] = OPND1 (SLEB128),
[DW_OP_breg0 + 3] = OPND1 (SLEB128),
[DW_OP_breg0 + 4] = OPND1 (SLEB128),
[DW_OP_breg0 + 5] = OPND1 (SLEB128),
[DW_OP_breg0 + 6] = OPND1 (SLEB128),
[DW_OP_breg0 + 7] = OPND1 (SLEB128),
[DW_OP_breg0 + 8] = OPND1 (SLEB128),
[DW_OP_breg0 + 9] = OPND1 (SLEB128),
[DW_OP_breg0 + 10] = OPND1 (SLEB128),
[DW_OP_breg0 + 11] = OPND1 (SLEB128),
[DW_OP_breg0 + 12] = OPND1 (SLEB128),
[DW_OP_breg0 + 13] = OPND1 (SLEB128),
[DW_OP_breg0 + 14] = OPND1 (SLEB128),
[DW_OP_breg0 + 15] = OPND1 (SLEB128),
[DW_OP_breg0 + 16] = OPND1 (SLEB128),
[DW_OP_breg0 + 17] = OPND1 (SLEB128),
[DW_OP_breg0 + 18] = OPND1 (SLEB128),
[DW_OP_breg0 + 19] = OPND1 (SLEB128),
[DW_OP_breg0 + 20] = OPND1 (SLEB128),
[DW_OP_breg0 + 21] = OPND1 (SLEB128),
[DW_OP_breg0 + 22] = OPND1 (SLEB128),
[DW_OP_breg0 + 23] = OPND1 (SLEB128),
[DW_OP_breg0 + 24] = OPND1 (SLEB128),
[DW_OP_breg0 + 25] = OPND1 (SLEB128),
[DW_OP_breg0 + 26] = OPND1 (SLEB128),
[DW_OP_breg0 + 27] = OPND1 (SLEB128),
[DW_OP_breg0 + 28] = OPND1 (SLEB128),
[DW_OP_breg0 + 29] = OPND1 (SLEB128),
[DW_OP_breg0 + 30] = OPND1 (SLEB128),
[DW_OP_breg0 + 31] = OPND1 (SLEB128),
[DW_OP_regx] = OPND1 (ULEB128),
[DW_OP_fbreg] = OPND1 (SLEB128),
[DW_OP_bregx] = OPND2 (ULEB128, SLEB128),
[DW_OP_piece] = OPND1 (ULEB128),
[DW_OP_deref_size] = OPND1 (VAL8),
[DW_OP_xderef_size] = OPND1 (VAL8),
[DW_OP_call2] = OPND1 (VAL16),
[DW_OP_call4] = OPND1 (VAL32),
[DW_OP_call_ref] = OPND1 (OFFSET)
};
static inline unw_word_t
sword (unw_word_t val)
{
switch (sizeof (unw_word_t))
{
case 1: return (int8_t) val;
case 2: return (int16_t) val;
case 4: return (int32_t) val;
case 8: return (int64_t) val;
default: abort ();
}
}
static inline unw_word_t
read_operand (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, int operand_type, unw_word_t *val, void *arg)
{
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
int ret;
switch (operand_type)
{
case VAL8:
ret = dwarf_readu8 (as, a, addr, &u8, arg);
*val = u8;
break;
case VAL16:
ret = dwarf_readu16 (as, a, addr, &u16, arg);
*val = u16;
break;
case VAL32:
ret = dwarf_readu32 (as, a, addr, &u32, arg);
*val = u32;
break;
case VAL64:
ret = dwarf_readu64 (as, a, addr, &u64, arg);
*val = u64;
break;
case ULEB128:
ret = dwarf_read_uleb128 (as, a, addr, val, arg);
break;
case SLEB128:
ret = dwarf_read_sleb128 (as, a, addr, val, arg);
break;
case OFFSET: /* only used by DW_OP_call_ref, which we don't implement */
default:
Debug (1, "Unexpected operand type %d", operand_type);
ret = -UNW_EINVAL;
}
return ret;
}
HIDDEN int
dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr, unw_word_t len,
unw_word_t *valp, int *is_register)
{
unw_word_t operand1 = 0, operand2 = 0, tmp1, tmp2, tmp3, end_addr;
uint8_t opcode, operands_signature, u8;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
unw_word_t stack[MAX_EXPR_STACK_SIZE];
unsigned int tos = 0;
uint16_t u16;
uint32_t u32;
uint64_t u64;
int ret;
# define pop() \
({ \
if (tos >= MAX_EXPR_STACK_SIZE) \
{ \
Debug (1, "Stack underflow\n"); \
return -UNW_EINVAL; \
} \
stack[tos--]; \
})
# define push(x) \
do { \
if (tos >= MAX_EXPR_STACK_SIZE) \
{ \
Debug (1, "Stack overflow\n"); \
return -UNW_EINVAL; \
} \
stack[tos++] = (x); \
} while (0)
# define pick(n) \
({ \
unsigned int _index = tos - (n); \
if (_index >= MAX_EXPR_STACK_SIZE) \
{ \
Debug (1, "Out-of-stack pick\n"); \
return -UNW_EINVAL; \
} \
stack[_index]; \
})
as = c->as;
arg = c->as_arg;
a = unw_get_accessors (as);
end_addr = *addr + len;
push (c->cfa); /* push current CFA as required by DWARF spec */
while (*addr < len)
{
if ((ret = dwarf_readu8 (as, a, addr, &opcode, arg)) < 0)
return ret;
operands_signature = operands[opcode];
if (unlikely (NUM_OPERANDS (operands_signature) > 0))
{
if ((ret = read_operand (as, a, addr,
OPND1_TYPE (operands_signature),
&operand1, arg)) < 0)
return ret;
if (NUM_OPERANDS (operands_signature > 1))
if ((ret = read_operand (as, a, addr,
OPND2_TYPE (operands_signature),
&operand2, arg)) < 0)
return ret;
}
switch ((dwarf_expr_op_t) opcode)
{
case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2:
case DW_OP_lit3: case DW_OP_lit4: case DW_OP_lit5:
case DW_OP_lit6: case DW_OP_lit7: case DW_OP_lit8:
case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11:
case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14:
case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17:
case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20:
case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23:
case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26:
case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29:
case DW_OP_lit30: case DW_OP_lit31:
push (opcode = DW_OP_lit0);
break;
case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2:
case DW_OP_breg3: case DW_OP_breg4: case DW_OP_breg5:
case DW_OP_breg6: case DW_OP_breg7: case DW_OP_breg8:
case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11:
case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14:
case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17:
case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20:
case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23:
case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26:
case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29:
case DW_OP_breg30: case DW_OP_breg31:
if ((ret = unw_get_reg (dwarf_to_cursor (c),
dwarf_to_unw_regnum (opcode - DW_OP_breg0),
&tmp1)) < 0)
return ret;
push (tmp1 + operand1);
break;
case DW_OP_bregx:
if ((ret = unw_get_reg (dwarf_to_cursor (c),
dwarf_to_unw_regnum (operand1), &tmp1)) < 0)
return ret;
push (tmp1 + operand2);
break;
case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2:
case DW_OP_reg3: case DW_OP_reg4: case DW_OP_reg5:
case DW_OP_reg6: case DW_OP_reg7: case DW_OP_reg8:
case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11:
case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14:
case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17:
case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20:
case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23:
case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26:
case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29:
case DW_OP_reg30: case DW_OP_reg31:
*valp = dwarf_to_unw_regnum (opcode - DW_OP_reg0);
*is_register = 1;
return 0;
case DW_OP_regx:
*valp = dwarf_to_unw_regnum (operand1);
*is_register = 1;
return 0;
case DW_OP_addr:
case DW_OP_const1u:
case DW_OP_const2u:
case DW_OP_const4u:
case DW_OP_const8u:
case DW_OP_constu:
case DW_OP_const8s:
case DW_OP_consts:
push (operand1);
break;
case DW_OP_const1s:
if (operand1 & 0x80)
operand1 |= ((unw_word_t) -1) << 8;
push (operand1);
break;
case DW_OP_const2s:
if (operand1 & 0x8000)
operand1 |= ((unw_word_t) -1) << 16;
push (operand1);
break;
case DW_OP_const4s:
if (operand1 & 0x80000000)
operand1 |= (((unw_word_t) -1) << 16) << 16;
push (operand1);
break;
case DW_OP_deref:
tmp1 = pop ();
if ((ret = dwarf_readw (as, a, &tmp1, &tmp2, arg)) < 0)
return ret;
push (tmp2);
break;
case DW_OP_deref_size:
tmp1 = pop ();
switch (operand1)
{
case 0:
break;
case 1:
if ((ret = dwarf_readu8 (as, a, &tmp1, &u8, arg)) < 0)
return ret;
tmp2 = u8;
break;
case 2:
if ((ret = dwarf_readu16 (as, a, &tmp1, &u16, arg)) < 0)
return ret;
tmp2 = u16;
break;
case 3:
case 4:
if ((ret = dwarf_readu32 (as, a, &tmp1, &u32, arg)) < 0)
return ret;
tmp2 = u32;
if (operand1 == 3)
{
if (dwarf_is_big_endian (as))
tmp2 >>= 8;
else
tmp2 &= 0xffffff;
}
break;
case 5:
case 6:
case 7:
case 8:
if ((ret = dwarf_readu64 (as, a, &tmp1, &u64, arg)) < 0)
return ret;
tmp2 = u16;
if (operand1 != 8)
{
if (dwarf_is_big_endian (as))
tmp2 >>= 64 - 8 * operand1;
else
tmp2 &= (~ (unw_word_t) 0) << (8 * operand1);
}
break;
}
push (tmp2);
break;
case DW_OP_dup:
push (pick (0));
break;
case DW_OP_drop:
pop ();
break;
case DW_OP_pick:
push (pick (operand1));
break;
case DW_OP_over:
push (pick (1));
break;
case DW_OP_swap:
tmp1 = pop ();
tmp2 = pop ();
push (tmp1);
push (tmp2);
break;
case DW_OP_rot:
tmp1 = pop ();
tmp2 = pop ();
tmp3 = pop ();
push (tmp1);
push (tmp3);
push (tmp2);
break;
case DW_OP_abs:
tmp1 = pop ();
if (tmp1 & ((unw_word_t) 1 << (8 * sizeof (unw_word_t) - 1)))
tmp1 = -tmp1;
push (tmp1);
break;
case DW_OP_and:
tmp1 = pop ();
tmp2 = pop ();
push (tmp1 & tmp2);
break;
case DW_OP_div:
tmp1 = pop ();
tmp2 = pop ();
if (tmp1)
tmp1 = sword (tmp2) / sword (tmp1);
push (tmp1);
break;
case DW_OP_minus:
tmp1 = pop ();
tmp2 = pop ();
tmp1 = tmp2 - tmp1;
push (tmp1);
break;
case DW_OP_mod:
tmp1 = pop ();
tmp2 = pop ();
if (tmp1)
tmp1 = tmp2 % tmp1;
push (tmp1);
break;
case DW_OP_mul:
tmp1 = pop ();
tmp2 = pop ();
if (tmp1)
tmp1 = tmp2 * tmp1;
push (tmp1);
break;
case DW_OP_neg:
push (-pop ());
break;
case DW_OP_not:
push (~pop ());
break;
case DW_OP_or:
tmp1 = pop ();
tmp2 = pop ();
push (tmp1 | tmp2);
break;
case DW_OP_plus:
tmp1 = pop ();
tmp2 = pop ();
push (tmp1 + tmp2);
break;
case DW_OP_plus_uconst:
tmp1 = pop ();
push (tmp1 + operand1);
break;
case DW_OP_shl:
tmp1 = pop ();
tmp2 = pop ();
push (tmp2 << tmp1);
break;
case DW_OP_shr:
tmp1 = pop ();
tmp2 = pop ();
push (tmp2 >> tmp1);
break;
case DW_OP_shra:
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp2) >> tmp1);
break;
case DW_OP_xor:
tmp1 = pop ();
tmp2 = pop ();
push (tmp1 ^ tmp2);
break;
case DW_OP_le:
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) <= sword (tmp2));
break;
case DW_OP_ge:
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) >= sword (tmp2));
break;
case DW_OP_eq:
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) == sword (tmp2));
break;
case DW_OP_lt:
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) < sword (tmp2));
break;
case DW_OP_gt:
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) > sword (tmp2));
break;
case DW_OP_ne:
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) != sword (tmp2));
break;
case DW_OP_skip:
*addr += (int16_t) operand1;
break;
case DW_OP_bra:
tmp1 = pop ();
if (tmp1)
*addr += (int16_t) operand1;
break;
case DW_OP_nop:
break;
case DW_OP_call2:
case DW_OP_call4:
case DW_OP_call_ref:
case DW_OP_fbreg:
case DW_OP_piece:
case DW_OP_push_object_address:
case DW_OP_xderef:
case DW_OP_xderef_size:
default:
Debug (1, "Unexpected opcode 0x%x\n", opcode);
return -UNW_EINVAL;
}
}
*valp = pop ();
return 0;
}

View file

@ -0,0 +1,287 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <string.h>
#include "dwarf.h"
#include "tdep.h"
/* Note: we don't need to keep track of more than the first four
characters of the augmentation string, because we (a) ignore any
augmentation string contents once we find an unrecognized character
and (b) those characters that we do recognize, can't be
repeated. */
static inline int
parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_proc_info_t *pi, unw_dyn_dwarf_fde_info_t *dfi,
int *lsda_encodingp, void *arg)
{
uint8_t version, ch, augstr[5], fde_encoding, handler_encoding;
unw_word_t len, cie_end_addr, aug_size, handler = 0;
uint32_t u32val;
uint64_t u64val;
size_t i;
int ret;
# define STR2(x) #x
# define STR(x) STR2(x)
fde_encoding = DW_EH_PE_omit;
*lsda_encodingp = DW_EH_PE_omit;
dfi->flags = 0;
if ((ret = dwarf_readu32 (as, a, addr, &u32val, arg)) < 0)
return ret;
if (u32val != 0xffffffff)
{
/* the CIE is in the 32-bit DWARF format */
uint32_t cie_id;
len = u32val;
cie_end_addr = *addr + len;
if ((ret = dwarf_readu32 (as, a, addr, &cie_id, arg)) < 0)
return ret;
/* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */
if (cie_id != 0)
{
Debug (1, "Unexpected CIE id %x\n", cie_id);
return -UNW_EINVAL;
}
}
else
{
/* the CIE is in the 64-bit DWARF format */
uint64_t cie_id;
if ((ret = dwarf_readu64 (as, a, addr, &u64val, arg)) < 0)
return ret;
len = u64val;
cie_end_addr = *addr + len;
if ((ret = dwarf_readu64 (as, a, addr, &cie_id, arg)) < 0)
return ret;
/* DWARF says CIE id should be 0xffffffffffffffff, but in
.eh_frame, it's 0 */
if (cie_id != 0)
{
Debug (1, "Unexpected CIE id %llx\n", (long long) cie_id);
return -UNW_EINVAL;
}
}
dfi->cie_instr_end = cie_end_addr;
if ((ret = dwarf_readu8 (as, a, addr, &version, arg)) < 0)
return ret;
if (version != 1 && version != DWARF_CIE_VERSION)
{
Debug (1, "Got CIE version %u, expected version 1 or "
STR (DWARF_CIE_VERSION) "\n", version);
return -UNW_EBADVERSION;
}
/* read and parse the augmentation string: */
memset (augstr, 0, sizeof (augstr));
for (i = 0;;)
{
if ((ret = dwarf_readu8 (as, a, addr, &ch, arg)) < 0)
return ret;
if (!ch)
break; /* end of augmentation string */
if (i < sizeof (augstr) - 1)
augstr[i++] = ch;
}
if ((ret = dwarf_read_uleb128 (as, a, addr, &dfi->code_align, arg)) < 0
|| (ret = dwarf_read_sleb128 (as, a, addr, &dfi->data_align, arg)) < 0)
return ret;
/* Read the return-address column either as a u8 or as a uleb128. */
if (version == 1)
{
if ((ret = dwarf_readu8 (as, a, addr, &ch, arg)) < 0)
return ret;
dfi->ret_addr_column = ch;
}
else if ((ret = dwarf_read_uleb128 (as, a, addr, &dfi->ret_addr_column, arg))
< 0)
return ret;
if (augstr[0] == 'z')
{
dfi->flags |= UNW_DYN_DFI_FLAG_AUGMENTATION_HAS_SIZE;
if ((ret = dwarf_read_uleb128 (as, a, addr, &aug_size, arg))
< 0)
return ret;
}
for (i = 1; i < sizeof (augstr) && augstr[i]; ++i)
switch (augstr[i])
{
case 'L':
/* read the LSDA pointer-encoding format. */
if ((ret = dwarf_readu8 (as, a, addr, &ch, arg)) < 0)
return ret;
*lsda_encodingp = ch;
break;
case 'R':
/* read the FDE pointer-encoding format. */
if ((ret = dwarf_readu8 (as, a, addr, &fde_encoding, arg)) < 0)
return ret;
break;
case 'P':
/* read the personality-routine pointer-encoding format. */
if ((ret = dwarf_readu8 (as, a, addr, &handler_encoding, arg)) < 0)
return ret;
if ((ret = dwarf_read_encoded_pointer (as, a, addr, handler_encoding,
pi, &handler, arg)) < 0)
return ret;
break;
default:
if (dfi->flags & UNW_DYN_DFI_FLAG_AUGMENTATION_HAS_SIZE)
/* If we have the size of the augmentation body, we can skip
over the parts that we don't understand, so we're OK. */
return 0;
else
{
Debug (1, "Unexpected augmentation string `%s'\n", augstr);
return -UNW_EINVAL;
}
}
dfi->flags |= fde_encoding & UNW_DYN_DFI_FLAG_FDE_PE_MASK;
pi->handler = handler;
Debug (16, "CIE parsed OK, augmentation = \"%s\", handler=0x%lx\n",
augstr, (long) handler);
dfi->cie_instr_start = *addr;
return 0;
}
HIDDEN int
dwarf_parse_fde (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_proc_info_t *pi, unw_dyn_dwarf_fde_info_t *dfi, void *arg)
{
unw_word_t fde_end_addr, cie_addr, cie_offset_addr, aug_end_addr = 0;
int ret, fde_encoding, ip_range_encoding, lsda_encoding;
unw_word_t start_ip, ip_range, aug_size;
uint64_t u64val;
uint32_t u32val;
Debug (12, "FDE @ 0x%lx\n", (long) *addr);
/* Parse enough of the FDE to get the procedure info (LSDA and handler). */
if ((ret = dwarf_readu32 (as, a, addr, &u32val, arg)) < 0)
return ret;
if (u32val != 0xffffffff)
{
uint32_t cie_offset;
/* the FDE is in the 32-bit DWARF format */
fde_end_addr = *addr + u32val;
cie_offset_addr = *addr;
if ((ret = dwarf_reads32 (as, a, addr, &cie_offset, arg)) < 0)
return ret;
/* DWARF says that the CIE_pointer in the FDE is a
.debug_frame-relative offset, but the GCC-generated .eh_frame
sections instead store a "pcrelative" offset, which is just
as fine as it's self-contained. */
cie_addr = cie_offset_addr - cie_offset;
}
else
{
uint64_t cie_offset;
/* the FDE is in the 64-bit DWARF format */
if ((ret = dwarf_readu64 (as, a, addr, &u64val, arg)) < 0)
return ret;
fde_end_addr = *addr + u64val;
cie_offset_addr = *addr;
if ((ret = dwarf_reads64 (as, a, addr, &cie_offset, arg)) < 0)
return ret;
/* DWARF says that the CIE_pointer in the FDE is a
.debug_frame-relative offset, but the GCC-generated .eh_frame
sections instead store a "pcrelative" offset, which is just
as fine as it's self-contained. */
cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset);
}
pi->extra.dwarf_info.fde_instr_end = fde_end_addr;
if ((ret = parse_cie (as, a, &cie_addr, pi, &pi->extra.dwarf_info,
&lsda_encoding, arg)) < 0)
return ret;
fde_encoding = pi->extra.dwarf_info.flags & UNW_DYN_DFI_FLAG_FDE_PE_MASK;
/* IP-range has same encoding as FDE pointers, except that it's
always an absolute value: */
ip_range_encoding = fde_encoding & DW_EH_PE_FORMAT_MASK;
if ((ret = dwarf_read_encoded_pointer (as, a, addr, fde_encoding,
pi, &start_ip, arg)) < 0
|| (ret = dwarf_read_encoded_pointer (as, a, addr, ip_range_encoding,
pi, &ip_range, arg)) < 0)
return ret;
pi->start_ip = start_ip;
pi->end_ip = start_ip + ip_range;
if (pi->extra.dwarf_info.flags & UNW_DYN_DFI_FLAG_AUGMENTATION_HAS_SIZE)
{
if ((ret = dwarf_read_uleb128 (as, a, addr, &aug_size, arg))
< 0)
return ret;
aug_end_addr = *addr + aug_size;
}
if ((ret = dwarf_read_encoded_pointer (as, a, addr, lsda_encoding,
pi, &pi->lsda, arg)) < 0)
return ret;
if (pi->extra.dwarf_info.flags & UNW_DYN_DFI_FLAG_AUGMENTATION_HAS_SIZE)
pi->extra.dwarf_info.fde_instr_start = aug_end_addr;
else
pi->extra.dwarf_info.fde_instr_start = *addr;
/* Always set the unwind info, whether or not need_unwind_info is
set. We had to do all the work anyhow, so there is no point in
not doing so. */
pi->format = UNW_INFO_FORMAT_DWARF_FDE;
pi->unwind_info_size = sizeof (pi->extra.dwarf_info) / sizeof (unw_word_t);
pi->unwind_info = &pi->extra.dwarf_info;
Debug (16, "FDE covers IP 0x%lx-0x%lx, LSDA=0x%lx\n",
(long) pi->start_ip, (long) pi->end_ip, (long) pi->lsda);
return 0;
}

View file

@ -0,0 +1,373 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/* Locate an FDE via the ELF data-structures defined by LSB v1.3
(http://www.linuxbase.org/spec/). */
#include <link.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "dwarf-eh.h"
#include "tdep.h"
#ifndef UNW_REMOTE_ONLY
/* Info is a pointer to a unw_dyn_info_t structure and, on entry,
member u.rti.segbase contains the instruction-pointer we're looking
for. */
static int
callback (struct dl_phdr_info *info, size_t size, void *ptr)
{
unw_dyn_info_t *di = ptr;
const Elf_W(Phdr) *phdr, *p_eh_hdr, *p_dynamic, *p_text;
unw_word_t addr, eh_frame_ptr, fde_count;
Elf_W(Addr) load_base, segbase = 0;
struct dwarf_eh_frame_hdr *hdr;
unw_proc_info_t pi;
unw_accessors_t *a;
int ret;
long n;
/* Make sure struct dl_phdr_info is at least as big as we need. */
if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
+ sizeof (info->dlpi_phnum))
return -1;
Debug (16, "checking %s, base=0x%lx)\n",
info->dlpi_name, (long) info->dlpi_addr);
phdr = info->dlpi_phdr;
load_base = info->dlpi_addr;
p_text = NULL;
p_eh_hdr = NULL;
p_dynamic = NULL;
/* See if PC falls into one of the loaded segments. Find the
eh-header segment at the same time. */
for (n = info->dlpi_phnum; --n >= 0; phdr++)
{
if (phdr->p_type == PT_LOAD)
{
Elf_W(Addr) vaddr = phdr->p_vaddr + load_base;
if (di->u.rti.segbase >= vaddr
&& di->u.rti.segbase < vaddr + phdr->p_memsz)
p_text = phdr;
}
else if (phdr->p_type == PT_GNU_EH_FRAME)
p_eh_hdr = phdr;
else if (phdr->p_type == PT_DYNAMIC)
p_dynamic = phdr;
}
if (!p_text || !p_eh_hdr)
return 0;
if (likely (p_eh_hdr->p_vaddr >= p_text->p_vaddr
&& p_eh_hdr->p_vaddr < p_text->p_vaddr + p_text->p_memsz))
/* normal case: eh-hdr is inside text segment */
segbase = p_text->p_vaddr + load_base;
else
{
/* Special case: eh-hdr is in some other segment; this may
happen, e.g., for the Linux kernel's gate DSO, for
example. */
phdr = info->dlpi_phdr;
for (n = info->dlpi_phnum; --n >= 0; phdr++)
{
if (phdr->p_type == PT_LOAD && p_eh_hdr->p_vaddr >= phdr->p_vaddr
&& p_eh_hdr->p_vaddr < phdr->p_vaddr + phdr->p_memsz)
{
segbase = phdr->p_vaddr + load_base;
break;
}
}
}
if (p_dynamic)
{
/* For dynamicly linked executables and shared libraries,
DT_PLTGOT is the value that data-relative addresses are
relative to for that object. We call this the "gp". */
Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base);
for (; dyn->d_tag != DT_NULL; ++dyn)
if (dyn->d_tag == DT_PLTGOT)
{
/* Assume that _DYNAMIC is writable and GLIBC has
relocated it (true for x86 at least). */
di->gp = dyn->d_un.d_ptr;
break;
}
}
else
/* Otherwise this is a static executable with no _DYNAMIC. Assume
that data-relative addresses are relative to 0, i.e.,
absolute. */
di->gp = 0;
hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base);
if (hdr->version != DW_EH_VERSION)
{
Debug (1, "table `%s' has unexpected version %d\n",
info->dlpi_name, hdr->version);
return 0;
}
if (hdr->table_enc == DW_EH_PE_omit)
{
Debug (1, "table `%s' doesn't have a binary search table\n",
info->dlpi_name);
return 0;
}
/* For now, only support binary-search tables which are
data-relative and whose entries have the size of a pointer. */
if (!(hdr->table_enc == (DW_EH_PE_datarel | DW_EH_PE_ptr)
|| ((sizeof (unw_word_t) == 4
&& hdr->table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4)))
|| ((sizeof (unw_word_t) == 8
&& hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata8)))))
{
Debug (1, "search table in `%s' has unexpected encoding 0x%x\n",
info->dlpi_name, hdr->table_enc);
return 0;
}
addr = (unw_word_t) (hdr + 1);
a = unw_get_accessors (unw_local_addr_space);
pi.gp = di->gp;
/* Read eh_frame_ptr: */
if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
&addr, hdr->eh_frame_ptr_enc, &pi,
&eh_frame_ptr, NULL)) < 0)
return ret;
/* Read fde_count: */
if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
&addr, hdr->fde_count_enc, &pi,
&fde_count, NULL)) < 0)
return ret;
di->format = UNW_INFO_FORMAT_REMOTE_TABLE;
di->start_ip = p_text->p_vaddr + load_base;
di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz;
di->u.rti.name_ptr = (unw_word_t) info->dlpi_name;
di->u.rti.table_data = addr;
di->u.rti.table_len = fde_count + 2 * sizeof (unw_word_t);
/* For the binary-search table in the eh_frame_hdr, data-relative
means relative to the start of that section... */
di->u.rti.segbase = (unw_word_t) hdr;
Debug (15, "found table `%s': segbase=0x%lx, len=%lu, gp=0x%lx, "
"table_data=0x%lx\n", (char *) di->u.rti.name_ptr,
(long) di->u.rti.segbase, (long) di->u.rti.table_len,
(long) di->gp, (long) di->u.rti.table_data);
return 1;
}
HIDDEN int
dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi, int need_unwind_info, void *arg)
{
unw_dyn_info_t di;
Debug (14, "looking for IP=0x%lx\n", (long) ip);
di.u.rti.segbase = ip; /* this is cheap... */
if (dl_iterate_phdr (callback, &di) <= 0)
{
Debug (14, "IP=0x%lx not found\n", (long) ip);
return -UNW_ENOINFO;
}
/* now search the table: */
return dwarf_search_unwind_table (as, ip, &di, pi, need_unwind_info, arg);
}
struct table_entry
{
unw_word_t start_ip_offset;
unw_word_t fde_offset;
};
static inline const struct table_entry *
lookup (struct table_entry *table, size_t table_size, unw_word_t rel_ip)
{
unsigned long table_len = table_size / sizeof (struct table_entry);
const struct table_entry *e = 0;
unsigned long lo, hi, mid;
unw_word_t end = 0;
/* do a binary search for right entry: */
for (lo = 0, hi = table_len; lo < hi;)
{
mid = (lo + hi) / 2;
e = table + mid;
if (rel_ip < e->start_ip_offset)
hi = mid;
else
{
if (mid + 1 >= table_len)
break;
end = table[mid + 1].start_ip_offset;
if (rel_ip >= end)
lo = mid + 1;
else
break;
}
}
if (rel_ip < e->start_ip_offset || rel_ip >= end)
return NULL;
return e;
}
#endif /* !UNW_REMOTE_ONLY */
/* Helper macro for reading an table_entry from remote memory. */
#define remote_read(addr, member) \
(*a->access_mem) (as, (addr) + offsetof (struct table_entry, \
member), &member, 0, arg)
#ifndef UNW_LOCAL_ONLY
/* Lookup an unwind-table entry in remote memory. Returns 1 if an
entry is found, 0 if no entry is found, negative if an error
occurred reading remote memory. */
static int
remote_lookup (unw_addr_space_t as,
unw_word_t table, size_t table_size, unw_word_t rel_ip,
struct table_entry *e, void *arg)
{
unsigned long table_len = table_size / sizeof (struct table_entry);
unw_word_t e_addr = 0, start_ip_offset, fde_offset;
unw_word_t start = ~(unw_word_t) 0, end = 0;
unw_accessors_t *a = unw_get_accessors (as);
unsigned long lo, hi, mid;
int ret;
/* do a binary search for right entry: */
for (lo = 0, hi = table_len; lo < hi;)
{
mid = (lo + hi) / 2;
e_addr = table + mid * sizeof (struct table_entry);
if ((ret = remote_read (e_addr, start_ip_offset)) < 0)
return ret;
start = start_ip_offset;
if (rel_ip < start)
hi = mid;
else
{
if (mid + 1 >= table_len)
break;
if ((ret = remote_read (e_addr + sizeof (struct table_entry),
start_ip_offset)) < 0)
return ret;
end = start_ip_offset;
if (rel_ip >= end)
lo = mid + 1;
else
break;
}
}
if (rel_ip < start || rel_ip >= end)
return 0;
e->start_ip_offset = start;
if ((ret = remote_read (e_addr, fde_offset)) < 0)
return ret;
e->fde_offset = fde_offset;
return 1;
}
#endif /* UNW_LOCAL_ONLY */
HIDDEN int
dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
unw_dyn_info_t *di, unw_proc_info_t *pi,
int need_unwind_info, void *arg)
{
const struct table_entry *e = NULL;
unw_word_t segbase = 0, fde_addr;
unw_accessors_t *a;
#ifndef UNW_LOCAL_ONLY
struct table_entry ent;
int ret;
#endif
assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE
&& (ip >= di->start_ip && ip < di->end_ip));
a = unw_get_accessors (as);
pi->flags = 0;
pi->unwind_info = 0;
pi->handler = 0;
pi->gp = 0;
memset (&pi->extra, 0, sizeof (pi->extra));
#ifndef UNW_REMOTE_ONLY
if (as == unw_local_addr_space)
{
segbase = di->u.rti.segbase;
e = lookup ((struct table_entry *) di->u.rti.table_data,
di->u.rti.table_len * sizeof (unw_word_t), ip - segbase);
}
else
#endif
{
#ifndef UNW_LOCAL_ONLY
segbase = di->u.rti.segbase;
if ((ret = remote_lookup (as, di->u.rti.table_data,
di->u.rti.table_len * sizeof (unw_word_t),
ip - segbase, &ent, arg)) < 0)
return ret;
if (ret)
e = &ent;
else
e = NULL; /* no info found */
#endif
}
if (!e)
{
/* IP is inside this table's range, but there is no explicit
unwind info. */
return -UNW_ENOINFO;
}
Debug (16, "ip=0x%lx, start_ip=0x%lx\n",
(long) ip, (long) (e->start_ip_offset + segbase));
fde_addr = e->fde_offset + segbase;
return dwarf_parse_fde (as, a, &fde_addr, pi, &pi->extra.dwarf_info, arg);
}
HIDDEN void
dwarf_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
{
return; /* always a nop */
}

View file

@ -0,0 +1,610 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <string.h>
#include "dwarf.h"
#include "tdep.h"
#define alloc_reg_state() (mempool_alloc (&dwarf_reg_state_pool))
#define free_reg_state(rs) (mempool_free (&dwarf_reg_state_pool, rs))
static inline int
read_regnum (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *valp, void *arg)
{
int ret;
if ((ret = dwarf_read_uleb128 (as, a, addr, valp, arg)) < 0)
return ret;
if (*valp >= DWARF_NUM_PRESERVED_REGS)
{
Debug (1, "Invalid register number %u\n", *valp);
return -UNW_EBADREG;
}
return 0;
}
static inline void
set_reg (dwarf_state_record_t *sr, unw_word_t regnum, dwarf_where_t where,
unw_word_t val)
{
sr->rs_current.reg[regnum].where = where;
sr->rs_current.reg[regnum].val = val;
}
/* Run a CFI program to update the register state. */
static int
run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr,
unw_word_t ip, unw_word_t *addr, unw_word_t end_addr,
unw_dyn_dwarf_fde_info_t *dfi)
{
unw_word_t curr_ip, operand = 0, regnum, val, len, fde_encoding;
dwarf_reg_state_t *rs_stack = NULL, *new_rs, *old_rs;
unw_addr_space_t as;
unw_accessors_t *a;
uint8_t u8, op;
uint16_t u16;
uint32_t u32;
void *arg;
int ret;
as = c->as;
arg = c->as_arg;
a = unw_get_accessors (as);
curr_ip = c->pi.start_ip;
while (curr_ip < ip && *addr < end_addr)
{
if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0)
return ret;
if (op & DWARF_CFA_OPCODE_MASK)
{
operand = op & DWARF_CFA_OPERAND_MASK;
op &= ~DWARF_CFA_OPERAND_MASK;
}
switch ((dwarf_cfa_t) op)
{
case DW_CFA_advance_loc:
curr_ip += operand * dfi->code_align;
Debug (16, "CFA_advance_loc to 0x%lx\n", (long) curr_ip);
break;
case DW_CFA_advance_loc1:
if ((ret = dwarf_readu8 (as, a, addr, &u8, arg)) < 0)
goto fail;
curr_ip += u8 * dfi->code_align;
Debug (16, "CFA_advance_loc1 to 0x%lx\n", (long) curr_ip);
break;
case DW_CFA_advance_loc2:
if ((ret = dwarf_readu16 (as, a, addr, &u16, arg)) < 0)
goto fail;
curr_ip += u16 * dfi->code_align;
Debug (16, "CFA_advance_loc2 to 0x%lx\n", (long) curr_ip);
break;
case DW_CFA_advance_loc4:
if ((ret = dwarf_readu32 (as, a, addr, &u32, arg)) < 0)
goto fail;
curr_ip += u32 * dfi->code_align;
Debug (16, "CFA_advance_loc4 to 0x%lx\n", (long) curr_ip);
break;
case DW_CFA_MIPS_advance_loc8:
#ifdef UNW_TARGET_MIPS
{
uint64_t u64;
if ((ret = dwarf_readu64 (as, a, addr, &u64, arg)) < 0)
goto fail;
curr_ip += u64 * dfi->code_align;
Debug (16, "CFA_MIPS_advance_loc8\n");
break;
}
#else
Debug (1, "DW_CFA_MIPS_advance_loc8 on non-MIPS target\n");
ret = -UNW_EINVAL;
goto fail;
#endif
case DW_CFA_offset:
regnum = operand;
if (regnum >= DWARF_NUM_PRESERVED_REGS)
{
Debug (1, "Invalid register number %u in DW_cfa_OFFSET\n",
regnum);
ret = -UNW_EBADREG;
goto fail;
}
if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
goto fail;
set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dfi->data_align);
Debug (16, "CFA_offset r%lu at cfa+0x%lx\n",
(long) regnum, (long) (val * dfi->data_align));
break;
case DW_CFA_offset_extended:
if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
|| ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
goto fail;
set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dfi->data_align);
Debug (16, "CFA_offset_extended r%lu at cf+0x%lx\n",
(long) regnum, (long) (val * dfi->data_align));
break;
case DW_CFA_offset_extended_sf:
if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
|| ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
goto fail;
set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dfi->data_align);
Debug (16, "CFA_offset_extended_sf r%lu at cf+0x%lx\n",
(long) regnum, (long) (val * dfi->data_align));
break;
case DW_CFA_restore:
regnum = operand;
if (regnum >= DWARF_NUM_PRESERVED_REGS)
{
Debug (1, "Invalid register number %u in DW_CFA_restore\n",
regnum);
ret = -UNW_EINVAL;
goto fail;
}
sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
Debug (16, "CFA_restore r%lu\n", (long) regnum);
break;
case DW_CFA_restore_extended:
if ((ret = dwarf_read_uleb128 (as, a, addr, &regnum, arg)) < 0)
goto fail;
if (regnum >= DWARF_NUM_PRESERVED_REGS)
{
Debug (1, "Invalid register number %u in "
"DW_CFA_restore_extended\n", regnum);
ret = -UNW_EINVAL;
goto fail;
}
sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
Debug (16, "CFA_restore_extended r%lu\n", (long) regnum);
break;
case DW_CFA_nop:
break;
case DW_CFA_set_loc:
fde_encoding = dfi->flags & UNW_DYN_DFI_FLAG_FDE_PE_MASK;
if ((ret = dwarf_read_encoded_pointer (as, a, addr, fde_encoding,
&c->pi, &curr_ip,
arg)) < 0)
goto fail;
Debug (16, "CFA_set_loc to 0x%lx\n", (long) curr_ip);
break;
case DW_CFA_undefined:
if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
goto fail;
set_reg (sr, regnum, DWARF_WHERE_UNDEF, 0);
Debug (16, "CFA_undefined r%lu\n", (long) regnum);
break;
case DW_CFA_same_value:
if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
goto fail;
set_reg (sr, regnum, DWARF_WHERE_SAME, 0);
Debug (16, "CFA_same_value r%lu\n", (long) regnum);
break;
case DW_CFA_register:
if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
|| ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
goto fail;
set_reg (sr, regnum, DWARF_WHERE_REG, val);
Debug (16, "CFA_register r%lu to r%lu\n", (long) regnum, (long) val);
break;
case DW_CFA_remember_state:
new_rs = alloc_reg_state ();
if (!new_rs)
{
Debug (1, "Out of memory in DW_CFA_remember_state\n");
ret = -UNW_ENOMEM;
goto fail;
}
memcpy (new_rs->reg, sr->rs_current.reg, sizeof (new_rs->reg));
new_rs->next = rs_stack;
rs_stack = new_rs;
Debug (16, "CFA_remember_state\n");
break;
case DW_CFA_restore_state:
if (!rs_stack)
{
Debug (1, "register-state stack underflow\n");
ret = -UNW_EINVAL;
goto fail;
}
memcpy (&sr->rs_current.reg, &rs_stack->reg, sizeof (rs_stack->reg));
old_rs = rs_stack;
rs_stack = rs_stack->next;
free_reg_state (old_rs);
Debug (16, "CFA_restore_state\n");
break;
case DW_CFA_def_cfa:
if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
|| ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
goto fail;
set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val); /* NOT factored! */
Debug (16, "CFA_def_cfa r%lu+0x%lx\n", (long) regnum, (long) val);
break;
case DW_CFA_def_cfa_sf:
if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
|| ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
goto fail;
set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
val * dfi->data_align); /* factored! */
Debug (16, "CFA_def_cfa_sf r%lu+0x%lx\n",
(long) regnum, (long) (val * dfi->data_align));
break;
case DW_CFA_def_cfa_register:
if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
goto fail;
set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
Debug (16, "CFA_def_cfa_register r%lu\n", (long) regnum);
break;
case DW_CFA_def_cfa_offset:
if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
goto fail;
set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val); /* NOT factored! */
Debug (16, "CFA_def_cfa_offsets 0x%lx\n", (long) val);
break;
case DW_CFA_def_cfa_offset_sf:
if ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0)
goto fail;
set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
val * dfi->data_align); /* factored! */
Debug (16, "CFA_def_cfa_offsets_sf 0x%lx\n",
(long) (val * dfi->data_align));
break;
case DW_CFA_def_cfa_expression:
/* Save the address of the DW_FORM_block for later evaluation. */
set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_EXPR, *addr);
if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
goto fail;
Debug (16, "CFA_def_cfa_expr @ 0x%lx [%lu bytes]\n",
(long) *addr, (long) len);
*addr += len;
break;
case DW_CFA_CFA_expression:
if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
goto fail;
/* Save the address of the DW_FORM_block for later evaluation. */
set_reg (sr, regnum, DWARF_WHERE_EXPR, *addr);
if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
goto fail;
Debug (16, "CFA_expression r%lu @ 0x%lx [%lu bytes]\n",
(long) regnum, (long) addr, (long) len);
*addr += len;
break;
case DW_CFA_GNU_args_size:
if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
goto fail;
sr->args_size = val;
Debug (16, "CFA_GNU_args_size %lu\n", (long) val);
break;
case DW_CFA_GNU_negative_offset_extended:
/* A comment in GCC says that this is obsoleted by
DW_CFA_offset_extended_sf, but that it's used by older
PowerPC code. */
if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
|| ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
goto fail;
set_reg (sr, regnum, DWARF_WHERE_CFAREL, -(val * dfi->data_align));
Debug (16, "CFA_GNU_negative_offsets_extended cfa+0x%lx\n",
(long) -(val * dfi->data_align));
break;
case DW_CFA_GNU_window_save:
#ifdef UNW_TARGET_SPARC
/* This is a special CFA to handle all 16 windowed registers
on SPARC. */
for (regnum = 16; regnum < 32; ++regnum)
set_reg (sr, regnum, DWARF_WHERE_CFAREL,
(regnum - 16) * sizeof (unw_word_t));
Debug (16, "CFA_GNU_window_save\n");
break;
#else
/* FALL THROUGH */
#endif
case DW_CFA_lo_user:
case DW_CFA_hi_user:
Debug (1, "Unexpected CFA opcode 0x%x", op);
ret = -UNW_EINVAL;
goto fail;
}
}
ret = 0;
fail:
/* Free the register-state stack, if not empty already. */
while (rs_stack)
{
old_rs = rs_stack;
rs_stack = rs_stack->next;
free_reg_state (old_rs);
}
return ret;
}
static int
fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
{
int ret, dynamic = 1;
if (c->pi_valid && !need_unwind_info)
return 0;
/* check dynamic info first --- it overrides everything else */
ret = unwi_find_dynamic_proc_info (c->as, ip, &c->pi, need_unwind_info,
c->as_arg);
if (ret == -UNW_ENOINFO)
{
dynamic = 0;
if ((ret = dwarf_find_proc_info (c->as, ip, &c->pi, need_unwind_info,
c->as_arg)) < 0)
return ret;
}
c->pi_valid = 1;
c->pi_is_dynamic = dynamic;
return ret;
}
static int
parse_dynamic (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
{
Debug (1, "Not yet implemented\n");
#if 0
/* Don't forget to set the ret_addr_column! */
c->ret_addr_column = XXX;
#endif
return -UNW_ENOINFO;
}
static inline void
put_unwind_info (struct dwarf_cursor *c, unw_proc_info_t *pi)
{
if (!c->pi_valid)
return;
if (c->pi_is_dynamic)
unwi_put_dynamic_unwind_info (c->as, pi, c->as_arg);
}
static inline int
parse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
{
unw_dyn_dwarf_fde_info_t *dfi;
unw_word_t addr;
int ret;
dfi = c->pi.unwind_info;
c->ret_addr_column = dfi->ret_addr_column;
addr = dfi->cie_instr_start;
if ((ret = run_cfi_program (c, sr, ~(unw_word_t) 0, &addr,
dfi->cie_instr_end, dfi)) < 0)
return ret;
memcpy (&sr->rs_initial, &sr->rs_current, sizeof (sr->rs_initial));
addr = dfi->fde_instr_start;
if ((ret = run_cfi_program (c, sr, ip, &addr, dfi->fde_instr_end, dfi)) < 0)
return ret;
return 0;
}
static int
create_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr,
unw_word_t ip)
{
int i, ret;
assert (c->pi_valid);
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
set_reg (sr, i, DWARF_WHERE_SAME, 0);
switch (c->pi.format)
{
case UNW_INFO_FORMAT_DWARF_FDE:
ret = parse_fde (c, ip, sr);
break;
case UNW_INFO_FORMAT_DYNAMIC:
ret = parse_dynamic (c, ip, sr);
break;
case UNW_INFO_FORMAT_REMOTE_TABLE:
case UNW_INFO_FORMAT_TABLE:
default:
Debug (1, "Unexpected unwind-info format %d\n", c->pi.format);
ret = -UNW_EINVAL;
}
return ret;
}
static inline int
eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as,
unw_accessors_t *a, unw_word_t addr,
dwarf_loc_t *locp, void *arg)
{
int ret, is_register;
unw_word_t len, val;
/* read the length of the expression: */
if ((ret = dwarf_read_uleb128 (as, a, &addr, &len, arg)) < 0)
return ret;
/* evaluate the expression: */
if ((ret = dwarf_eval_expr (c, &addr, len, &val, &is_register)) < 0)
return ret;
if (is_register)
*locp = DWARF_REG_LOC (c, dwarf_to_unw_regnum (val));
else
*locp = DWARF_MEM_LOC (c, val);
return 0;
}
static int
apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
{
unw_word_t regnum, addr, cfa;
unw_addr_space_t as;
dwarf_loc_t cfa_loc;
unw_accessors_t *a;
int i, ret;
void *arg;
as = c->as;
arg = c->as_arg;
a = unw_get_accessors (as);
/* Evaluate the CFA first, because it may be referred to be other
expressions. */
if (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
{
/* CFA is equal to [reg] + offset: */
regnum = dwarf_to_unw_regnum (rs->reg[DWARF_CFA_REG_COLUMN].val);
if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0)
return ret;
cfa += rs->reg[DWARF_CFA_OFF_COLUMN].val;
}
else
{
/* CFA is equal to EXPR: */
assert (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_EXPR);
addr = rs->reg[DWARF_CFA_REG_COLUMN].val;
if ((ret = eval_location_expr (c, as, a, addr, &cfa_loc, arg)) < 0)
return ret;
if ((ret = dwarf_get (c, cfa_loc, &cfa)) < 0)
return ret;
}
c->cfa = cfa;
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
{
switch ((dwarf_where_t) rs->reg[i].where)
{
case DWARF_WHERE_UNDEF:
c->loc[i] = DWARF_NULL_LOC;
break;
case DWARF_WHERE_SAME:
break;
case DWARF_WHERE_CFAREL:
c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val);
break;
case DWARF_WHERE_REG:
c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val));
break;
case DWARF_WHERE_EXPR:
addr = rs->reg[i].val;
if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) , 0)
return ret;
break;
}
}
return 0;
}
HIDDEN int
dwarf_find_save_locs (struct dwarf_cursor *c)
{
dwarf_state_record_t sr;
int ret;
if ((ret = fetch_proc_info (c, c->ip, 1)) < 0)
return ret;
if ((ret = create_state_record_for (c, &sr, c->ip)) < 0)
return ret;
if ((ret = apply_reg_state (c, &sr.rs_current)) < 0)
return ret;
put_unwind_info (c, &c->pi);
return 0;
}
/* The proc-info must be valid for IP before this routine can be
called. */
HIDDEN int
dwarf_create_state_record (struct dwarf_cursor *c, dwarf_state_record_t *sr)
{
return create_state_record_for (c, sr, c->ip);
}
HIDDEN int
dwarf_make_proc_info (struct dwarf_cursor *c)
{
#if 0
if (c->as->caching_policy == UNW_CACHE_NONE
|| get_cached_proc_info (c) < 0)
#endif
/* Lookup it up the slow way... */
return fetch_proc_info (c, c->ip, 0);
return 0;
}

View file

@ -0,0 +1,162 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "dwarf.h"
#include "tdep.h"
HIDDEN int
dwarf_read_encoded_pointer (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unsigned char encoding,
unw_proc_info_t *pi,
unw_word_t *valp, void *arg)
{
unw_word_t val, initial_addr = *addr;
uint16_t uval16;
uint32_t uval32;
uint64_t uval64;
int16_t sval16;
int32_t sval32;
int64_t sval64;
int ret;
/* DW_EH_PE_omit and DW_EH_PE_aligned don't follow the normal
format/application encoding. Handle them first. */
if (encoding == DW_EH_PE_omit)
{
*valp = 0;
return 0;
}
else if (encoding == DW_EH_PE_aligned)
{
*addr = (initial_addr + sizeof (unw_word_t) - 1) & -sizeof (unw_word_t);
return dwarf_readw (as, a, addr, valp, arg);
}
switch (encoding & DW_EH_PE_FORMAT_MASK)
{
case DW_EH_PE_ptr:
if ((ret = dwarf_readw (as, a, addr, &val, arg)) < 0)
return ret;
break;
case DW_EH_PE_uleb128:
if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
return ret;
break;
case DW_EH_PE_udata2:
if ((ret = dwarf_readu16 (as, a, addr, &uval16, arg)) < 0)
return ret;
val = uval16;
break;
case DW_EH_PE_udata4:
if ((ret = dwarf_readu32 (as, a, addr, &uval32, arg)) < 0)
return ret;
val = uval32;
break;
case DW_EH_PE_udata8:
if ((ret = dwarf_readu64 (as, a, addr, &uval64, arg)) < 0)
return ret;
val = uval64;
break;
case DW_EH_PE_sleb128:
if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
return ret;
break;
case DW_EH_PE_sdata2:
if ((ret = dwarf_reads16 (as, a, addr, &sval16, arg)) < 0)
return ret;
val = sval16;
break;
case DW_EH_PE_sdata4:
if ((ret = dwarf_reads32 (as, a, addr, &sval32, arg)) < 0)
return ret;
val = sval32;
break;
case DW_EH_PE_sdata8:
if ((ret = dwarf_reads64 (as, a, addr, &sval64, arg)) < 0)
return ret;
val = sval64;
break;
default:
Debug (1, "unexpected encoding format 0x%x\n",
encoding & DW_EH_PE_FORMAT_MASK);
return -UNW_EINVAL;
}
if (val == 0)
{
/* 0 is a special value and always absolute. */
*valp = 0;
return 0;
}
switch (encoding & DW_EH_PE_APPL_MASK)
{
case DW_EH_PE_absptr:
break;
case DW_EH_PE_pcrel:
val += initial_addr;
break;
case DW_EH_PE_datarel:
/* XXX For now, assume that data-relative addresses are relative
to the global pointer. */
val += pi->gp;
break;
case DW_EH_PE_funcrel:
val += pi->start_ip;
break;
case DW_EH_PE_textrel:
/* XXX For now we don't support text-rel values. If there is a
platform which needs this, we probably would have to add a
"segbase" member to unw_proc_info_t. */
default:
Debug (1, "unexpected application type 0x%x\n",
encoding & DW_EH_PE_APPL_MASK);
return -UNW_EINVAL;
}
if (encoding & DW_EH_PE_indirect)
{
unw_word_t indirect_addr = val;
if ((ret = dwarf_readw (as, a, &indirect_addr, &val, arg)) < 0)
return ret;
}
*valp = val;
return 0;
}

View file

@ -0,0 +1,135 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "dwarf.h"
#include "tdep.h"
static int
update_frame_state (struct dwarf_cursor *c)
{
unw_word_t prev_ip, prev_cfa, ip;
int ret;
prev_ip = c->ip;
prev_cfa = c->cfa;
/* Update the IP cache (do this first: if we reach the end of the
frame-chain, the rest of the info may not be valid/useful
anymore. */
ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip);
if (ret < 0)
return ret;
c->ip = ip;
#if 0
/* ??? fix me---perhaps move to where we have convenient access to
code_align? */
if ((ip & (c->code_align - 1)) != 0)
{
/* don't let obviously bad addresses pollute the cache */
Debug (1, "rejecting bad ip=0x%lx\n", (long) c->ip);
return -UNW_EINVALIDIP;
}
#endif
if (ip == 0)
/* end of frame-chain reached */
return 0;
#if 0
num_regs = 0;
if (unlikely (c->abi_marker))
{
c->last_abi_marker = c->abi_marker;
switch (c->abi_marker)
{
case ABI_MARKER_LINUX_SIGTRAMP:
case ABI_MARKER_OLD_LINUX_SIGTRAMP:
c->as->abi = ABI_LINUX;
if ((ret = linux_sigtramp (c, &num_regs)) < 0)
return ret;
break;
case ABI_MARKER_OLD_LINUX_INTERRUPT:
case ABI_MARKER_LINUX_INTERRUPT:
c->as->abi = ABI_LINUX;
if ((ret = linux_interrupt (c, &num_regs, c->abi_marker)) < 0)
return ret;
break;
case ABI_MARKER_HP_UX_SIGTRAMP:
c->as->abi = ABI_HPUX;
if ((ret = hpux_sigtramp (c, &num_regs)) < 0)
return ret;
break;
default:
Debug (1, "unknown ABI marker: ABI=%u, context=%u\n",
c->abi_marker >> 8, c->abi_marker & 0xff);
return -UNW_EINVAL;
}
Debug (10, "sigcontext_addr=%lx (ret=%d)\n",
(unsigned long) c->sigcontext_addr, ret);
c->sigcontext_off = c->sigcontext_addr - c->cfa;
/* update the IP cache: */
if ((ret = ia64_get (c, c->loc[IA64_REG_IP], &ip)) < 0)
return ret;
c->ip = ip;
if (ip == 0)
/* end of frame-chain reached */
return 0;
}
else
num_regs = (c->cfm >> 7) & 0x7f; /* size of locals */
c->abi_marker = 0;
#endif
if (c->ip == prev_ip && c->cfa == prev_cfa)
{
dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
__FUNCTION__, (long) ip);
return -UNW_EBADFRAME;
}
c->pi_valid = 0;
return 0;
}
HIDDEN int
dwarf_step (struct dwarf_cursor *c)
{
int ret;
if ((ret = dwarf_find_save_locs (c)) < 0)
return ret;
if ((ret = update_frame_state (c)) < 0)
return ret;
Debug (16, "done\n");
return (c->ip == 0) ? 0 : 1;
}

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gexpr-dwarf.c"
#endif

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gfde-dwarf.c"
#endif

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gfind_proc_info-lsb.c"
#endif

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gparser-dwarf.c"
#endif

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gpe-dwarf.c"
#endif

View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gstep-dwarf.c"
#endif

View file

@ -0,0 +1,128 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef dwarf_eh_h
#define dwarf_eh_h
#include "dwarf.h"
/* This header file defines the format of a DWARF exception-header
section (.eh_frame_hdr, pointed to by program-header
PT_GNU_EH_FRAME). The exception-header is self-describing in the
sense that the format of the addresses contained in it is expressed
as a one-byte type-descriptor called a "pointer-encoding" (PE).
The exception header encodes the address of the .eh_frame section
and optionally contains a binary search table for the
Frame Descriptor Entries (FDEs) in the .eh_frame. The contents of
.eh_frame has the format described by the DWARF v3 standard
(http://www.eagercon.com/dwarf/dwarf3std.htm), except that code
addresses may be encoded in different ways. Also, .eh_frame has
augmentations that allow encoding a language-specific data-area
(LSDA) pointer and a pointer to a personality-routine.
Details:
The Common Information Entry (CIE) associated with an FDE may
contain an augmentation string. Each character in this string has
a specific meaning and either one or two associated operands. The
operands are stored in an augmentation body which appears right
after the "return_address_register" member and before the
"initial_instructions" member. The operands appear in the order
in which the characters appear in the string. For example, if the
augmentation string is "zL", the operand for 'z' would be first in
the augmentation body and the operand for 'L' would be second.
The following characters are supported for the CIE augmentation
string:
'z': The operand for this character is a uleb128 value that gives the
length of the CIE augmentation body, not counting the length
of the uleb128 operand itself. If present, this code must
appear as the first character in the augmentation body.
'L': Indicates that the FDE's augmentation body contains an LSDA
pointer. The operand for this character is a single byte
that specifies the pointer-encoding (PE) that is used for
the LSDA pointer.
'R': Indicates that the code-pointers (FDE members
"initial_location" and "address_range" and the operand for
DW_CFA_set_loc) in the FDE have a non-default encoding. The
operand for this character is a single byte that specifies
the pointer-encoding (PE) that is used for the
code-pointers. Note: the "address_range" member is always
encoded as an absolute value. Apart from that, the specified
FDE pointer-encoding applies.
'P': Indicates the presence of a personality routine (handler).
The first operand for this character specifies the
pointer-encoding (PE) that is used for the second operand,
which specifies the address of the personality routine.
If the augmentation string contains any other characters, the
remainder of the augmentation string should be ignored.
Furthermore, if the size of the augmentation body is unknown
(i.e., 'z' is not the first character of the augmentation string),
then the entire CIE as well all associated FDEs must be ignored.
A Frame Descriptor Entries (FDE) may contain an augmentation body
which, if present, appears right after the "address_range" member
and before the "instructions" member. The contents of this body
is implicitly defined by the augmentation string of the associated
CIE. The meaning of the characters in the CIE's augmentation
string as far as FDEs are concerned is as follows:
'z': The first operand in the FDE's augmentation body specifies
the total length of the augmentation body as a uleb128 (not
counting the length of the uleb128 operand itself).
'L': The operand for this character is an LSDA pointer, encoded
in the format specified by the corresponding operand in the
CIE's augmentation body.
*/
#define DW_EH_VERSION 1 /* The version we're implementing */
struct dwarf_eh_frame_hdr
{
unsigned char version;
unsigned char eh_frame_ptr_enc;
unsigned char fde_count_enc;
unsigned char table_enc;
/* The rest of the header is variable-length and consists of the
following members:
encoded_t eh_frame_ptr;
encoded_t fde_count;
struct
{
encoded_t start_ip; // first address covered by this FDE
encoded_t fde_addr; // address of the FDE
}
binary_search_table[fde_count]; */
};
#endif /* dwarf_eh_h */

View file

@ -0,0 +1,35 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "dwarf.h"
HIDDEN struct mempool dwarf_reg_state_pool;
HIDDEN int
dwarf_init (void)
{
mempool_init (&dwarf_reg_state_pool, sizeof (dwarf_reg_state_t), 0);
return 0;
}