@ -19,9 +19,6 @@
# include <arch/chip.h>
# if TILE_CHIP < 10
# include <asm/opcode-tile.h>
@ -29,6 +26,27 @@
# define TREG_LR 55
# if TILE_CHIP >= 10
# define tile_bundle_bits tilegx_bundle_bits
# define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE
# define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES
# define tile_decoded_instruction tilegx_decoded_instruction
# define tile_mnemonic tilegx_mnemonic
# define parse_insn_tile parse_insn_tilegx
# define TILE_OPC_IRET TILEGX_OPC_IRET
# define TILE_OPC_ADDI TILEGX_OPC_ADDI
# define TILE_OPC_ADDLI TILEGX_OPC_ADDLI
# define TILE_OPC_INFO TILEGX_OPC_INFO
# define TILE_OPC_INFOL TILEGX_OPC_INFOL
# define TILE_OPC_JRP TILEGX_OPC_JRP
# define TILE_OPC_MOVE TILEGX_OPC_MOVE
# define OPCODE_STORE TILEGX_OPC_ST
typedef long long bt_int_reg_t ;
# else
# define OPCODE_STORE TILE_OPC_SW
typedef int bt_int_reg_t ;
# endif
/** A decoded bundle used for backtracer analysis. */
struct BacktraceBundle {
tile_bundle_bits bits ;
@ -41,7 +59,7 @@ struct BacktraceBundle {
/* This implementation only makes sense for native tools. */
/** Default function to read memory. */
static bool bt_read_memory ( void * result , VirtualAddress addr ,
size_ t size , void * extra )
unsigned in t size , void * extra )
{
/* FIXME: this should do some horrible signal stuff to catch
* SEGV cleanly and fail .
@ -106,6 +124,12 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
find_matching_insn ( bundle , TILE_OPC_ADDI , vals , 2 ) ;
if ( insn = = NULL )
insn = find_matching_insn ( bundle , TILE_OPC_ADDLI , vals , 2 ) ;
# if TILE_CHIP >= 10
if ( insn = = NULL )
insn = find_matching_insn ( bundle , TILEGX_OPC_ADDXLI , vals , 2 ) ;
if ( insn = = NULL )
insn = find_matching_insn ( bundle , TILEGX_OPC_ADDXI , vals , 2 ) ;
# endif
if ( insn = = NULL )
return false ;
@ -190,13 +214,52 @@ static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle)
return find_matching_insn ( bundle , TILE_OPC_MOVE , vals , 2 ) ! = NULL ;
}
/** Does this bundle contain the instruction 'sw sp, lr' ? */
/** Does this bundle contain a store of lr to sp ? */
static inline bool bt_has_sw_sp_lr ( const struct BacktraceBundle * bundle )
{
static const int vals [ 2 ] = { TREG_SP , TREG_LR } ;
return find_matching_insn ( bundle , TILE_OPC_SW , vals , 2 ) ! = NULL ;
return find_matching_insn ( bundle , OPCODE_STORE , vals , 2 ) ! = NULL ;
}
# if TILE_CHIP >= 10
/** Track moveli values placed into registers. */
static inline void bt_update_moveli ( const struct BacktraceBundle * bundle ,
int moveli_args [ ] )
{
int i ;
for ( i = 0 ; i < bundle - > num_insns ; i + + ) {
const struct tile_decoded_instruction * insn =
& bundle - > insns [ i ] ;
if ( insn - > opcode - > mnemonic = = TILEGX_OPC_MOVELI ) {
int reg = insn - > operand_values [ 0 ] ;
moveli_args [ reg ] = insn - > operand_values [ 1 ] ;
}
}
}
/** Does this bundle contain an 'add sp, sp, reg' instruction
* from a register that we saw a moveli into , and if so , what
* is the value in the register ?
*/
static bool bt_has_add_sp ( const struct BacktraceBundle * bundle , int * adjust ,
int moveli_args [ ] )
{
static const int vals [ 2 ] = { TREG_SP , TREG_SP } ;
const struct tile_decoded_instruction * insn =
find_matching_insn ( bundle , TILEGX_OPC_ADDX , vals , 2 ) ;
if ( insn ) {
int reg = insn - > operand_values [ 2 ] ;
if ( moveli_args [ reg ] ) {
* adjust = moveli_args [ reg ] ;
return true ;
}
}
return false ;
}
# endif
/** Locates the caller's PC and SP for a program starting at the
* given address .
*/
@ -227,6 +290,11 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
int next_bundle = 0 ;
VirtualAddress pc ;
# if TILE_CHIP >= 10
/* Naively try to track moveli values to support addx for -m32. */
int moveli_args [ TILEGX_NUM_REGISTERS ] = { 0 } ;
# endif
/* Default to assuming that the caller's sp is the current sp.
* This is necessary to handle the case where we start backtracing
* right at the end of the epilog .
@ -380,7 +448,11 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
if ( ! sp_determined ) {
int adjust ;
if ( bt_has_addi_sp ( & bundle , & adjust ) ) {
if ( bt_has_addi_sp ( & bundle , & adjust )
# if TILE_CHIP >= 10
| | bt_has_add_sp ( & bundle , & adjust , moveli_args )
# endif
) {
location - > sp_location = SP_LOC_OFFSET ;
if ( adjust < = 0 ) {
@ -427,6 +499,11 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
sp_determined = true ;
}
}
# if TILE_CHIP >= 10
/* Track moveli arguments for -m32 mode. */
bt_update_moveli ( & bundle , moveli_args ) ;
# endif
}
if ( bt_has_iret ( & bundle ) ) {
@ -502,11 +579,10 @@ void backtrace_init(BacktraceIterator *state,
break ;
}
/* The frame pointer should theoretically be aligned mod 8. If
* it ' s not even aligned mod 4 then something terrible happened
* and we should mark it as invalid .
/* If the frame pointer is not aligned to the basic word size
* something terrible happened and we should mark it as invalid .
*/
if ( fp % 4 ! = 0 )
if ( fp % sizeof ( bt_int_reg_t ) ! = 0 )
fp = - 1 ;
/* -1 means "don't know initial_frame_caller_pc". */
@ -547,9 +623,16 @@ void backtrace_init(BacktraceIterator *state,
state - > read_memory_func_extra = read_memory_func_extra ;
}
/* Handle the case where the register holds more bits than the VA. */
static bool valid_addr_reg ( bt_int_reg_t reg )
{
return ( ( VirtualAddress ) reg = = reg ) ;
}
bool backtrace_next ( BacktraceIterator * state )
{
VirtualAddress next_fp , next_pc , next_frame [ 2 ] ;
VirtualAddress next_fp , next_pc ;
bt_int_reg_t next_frame [ 2 ] ;
if ( state - > fp = = - 1 ) {
/* No parent frame. */
@ -563,11 +646,9 @@ bool backtrace_next(BacktraceIterator *state)
}
next_fp = next_frame [ 1 ] ;
if ( next_fp % 4 ! = 0 ) {
/* Caller's frame pointer is suspect, so give up.
* Technically it should be aligned mod 8 , but we will
* be forgiving here .
*/
if ( ! valid_addr_reg ( next_frame [ 1 ] ) | |
next_fp % sizeof ( bt_int_reg_t ) ! = 0 ) {
/* Caller's frame pointer is suspect, so give up. */
return false ;
}
@ -585,7 +666,7 @@ bool backtrace_next(BacktraceIterator *state)
} else {
/* Get the caller PC from the frame linkage area. */
next_pc = next_frame [ 0 ] ;
if ( next_pc = = 0 | |
if ( ! valid_addr_reg ( next_frame [ 0 ] ) | | next_pc = = 0 | |
next_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES ! = 0 ) {
/* The PC is suspect, so give up. */
return false ;
@ -599,23 +680,3 @@ bool backtrace_next(BacktraceIterator *state)
return true ;
}
# else /* TILE_CHIP < 10 */
void backtrace_init ( BacktraceIterator * state ,
BacktraceMemoryReader read_memory_func ,
void * read_memory_func_extra ,
VirtualAddress pc , VirtualAddress lr ,
VirtualAddress sp , VirtualAddress r52 )
{
state - > pc = pc ;
state - > sp = sp ;
state - > fp = - 1 ;
state - > initial_frame_caller_pc = - 1 ;
state - > read_memory_func = read_memory_func ;
state - > read_memory_func_extra = read_memory_func_extra ;
}
bool backtrace_next ( BacktraceIterator * state ) { return false ; }
# endif /* TILE_CHIP < 10 */