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:
parent
67921394ac
commit
eb51b4294a
16 changed files with 3027 additions and 0 deletions
630
include/dwarf.h
630
include/dwarf.h
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
}
|
|
@ -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, ®num, 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, ®num, 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, ®num, 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, ®num, 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, ®num, 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, ®num, 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, ®num, 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, ®num, 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, ®num, 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, ®num, 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, ®num, 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
Loading…
Reference in a new issue