diff options
Diffstat (limited to 'arch/tile/kernel/backtrace.c')
| -rw-r--r-- | arch/tile/kernel/backtrace.c | 131 | 
1 files changed, 64 insertions, 67 deletions
diff --git a/arch/tile/kernel/backtrace.c b/arch/tile/kernel/backtrace.c index 55a6a74974b..f8b74ca83b9 100644 --- a/arch/tile/kernel/backtrace.c +++ b/arch/tile/kernel/backtrace.c @@ -1,5 +1,5 @@  /* - * Copyright 2010 Tilera Corporation. All Rights Reserved. + * Copyright 2011 Tilera Corporation. All Rights Reserved.   *   *   This program is free software; you can redistribute it and/or   *   modify it under the terms of the GNU General Public License @@ -14,22 +14,13 @@  #include <linux/kernel.h>  #include <linux/string.h> - +#include <asm/byteorder.h>  #include <asm/backtrace.h> +#include <asm/tile-desc.h> +#include <arch/abi.h> -#include <arch/chip.h> - -#include <asm/opcode-tile.h> - - -#define TREG_SP 54 -#define TREG_LR 55 - - -#if TILE_CHIP >= 10 -#define tile_bundle_bits tilegx_bundle_bits +#ifdef __tilegx__  #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 @@ -43,11 +34,22 @@  #define OPCODE_STORE TILEGX_OPC_ST  typedef long long bt_int_reg_t;  #else -#define OPCODE_STORE TILE_OPC_SW +#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE +#define tile_decoded_instruction tilepro_decoded_instruction +#define tile_mnemonic tilepro_mnemonic +#define parse_insn_tile parse_insn_tilepro +#define TILE_OPC_IRET TILEPRO_OPC_IRET +#define TILE_OPC_ADDI TILEPRO_OPC_ADDI +#define TILE_OPC_ADDLI TILEPRO_OPC_ADDLI +#define TILE_OPC_INFO TILEPRO_OPC_INFO +#define TILE_OPC_INFOL TILEPRO_OPC_INFOL +#define TILE_OPC_JRP TILEPRO_OPC_JRP +#define TILE_OPC_MOVE TILEPRO_OPC_MOVE +#define OPCODE_STORE TILEPRO_OPC_SW  typedef int bt_int_reg_t;  #endif -/** A decoded bundle used for backtracer analysis. */ +/* A decoded bundle used for backtracer analysis. */  struct BacktraceBundle {  	tile_bundle_bits bits;  	int num_insns; @@ -56,23 +58,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, -			   unsigned int size, void *extra) -{ -	/* FIXME: this should do some horrible signal stuff to catch -	 * SEGV cleanly and fail. -	 * -	 * Or else the caller should do the setjmp for efficiency. -	 */ - -	memcpy(result, (const void *)addr, size); -	return true; -} - - -/** Locates an instruction inside the given bundle that +/* Locates an instruction inside the given bundle that   * has the specified mnemonic, and whose first 'num_operands_to_match'   * operands exactly match those in 'operand_values'.   */ @@ -107,13 +93,13 @@ static const struct tile_decoded_instruction *find_matching_insn(  	return NULL;  } -/** Does this bundle contain an 'iret' instruction? */ +/* Does this bundle contain an 'iret' instruction? */  static inline bool bt_has_iret(const struct BacktraceBundle *bundle)  {  	return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL;  } -/** Does this bundle contain an 'addi sp, sp, OFFSET' or +/* Does this bundle contain an 'addi sp, sp, OFFSET' or   * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET?   */  static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust) @@ -124,7 +110,7 @@ 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 +#ifdef __tilegx__  	if (insn == NULL)  		insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2);  	if (insn == NULL) @@ -137,7 +123,7 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)  	return true;  } -/** Does this bundle contain any 'info OP' or 'infol OP' +/* Does this bundle contain any 'info OP' or 'infol OP'   * instruction, and if so, what are their OP?  Note that OP is interpreted   * as an unsigned value by this code since that's what the caller wants.   * Returns the number of info ops found. @@ -161,7 +147,7 @@ static int bt_get_info_ops(const struct BacktraceBundle *bundle,  	return num_ops;  } -/** Does this bundle contain a jrp instruction, and if so, to which +/* Does this bundle contain a jrp instruction, and if so, to which   * register is it jumping?   */  static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg) @@ -175,7 +161,7 @@ static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)  	return true;  } -/** Does this bundle modify the specified register in any way? */ +/* Does this bundle modify the specified register in any way? */  static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)  {  	int i, j; @@ -195,34 +181,34 @@ static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)  	return false;  } -/** Does this bundle modify sp? */ +/* Does this bundle modify sp? */  static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle)  {  	return bt_modifies_reg(bundle, TREG_SP);  } -/** Does this bundle modify lr? */ +/* Does this bundle modify lr? */  static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle)  {  	return bt_modifies_reg(bundle, TREG_LR);  } -/** Does this bundle contain the instruction 'move fp, sp'? */ +/* Does this bundle contain the instruction 'move fp, sp'? */  static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle)  {  	static const int vals[2] = { 52, TREG_SP };  	return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL;  } -/** Does this bundle contain a store of lr to sp? */ +/* 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, OPCODE_STORE, vals, 2) != NULL;  } -#if TILE_CHIP >= 10 -/** Track moveli values placed into registers. */ +#ifdef __tilegx__ +/* Track moveli values placed into registers. */  static inline void bt_update_moveli(const struct BacktraceBundle *bundle,  				    int moveli_args[])  { @@ -238,7 +224,7 @@ static inline void bt_update_moveli(const struct BacktraceBundle *bundle,  	}  } -/** Does this bundle contain an 'add sp, sp, reg' instruction +/* 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?   */ @@ -260,11 +246,11 @@ static bool bt_has_add_sp(const struct BacktraceBundle *bundle, int *adjust,  }  #endif -/** Locates the caller's PC and SP for a program starting at the +/* Locates the caller's PC and SP for a program starting at the   * given address.   */  static void find_caller_pc_and_caller_sp(CallerLocation *location, -					 const VirtualAddress start_pc, +					 const unsigned long start_pc,  					 BacktraceMemoryReader read_memory_func,  					 void *read_memory_func_extra)  { @@ -288,9 +274,9 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,  	tile_bundle_bits prefetched_bundles[32];  	int num_bundles_prefetched = 0;  	int next_bundle = 0; -	VirtualAddress pc; +	unsigned long pc; -#if TILE_CHIP >= 10 +#ifdef __tilegx__  	/* Naively try to track moveli values to support addx for -m32. */  	int moveli_args[TILEGX_NUM_REGISTERS] = { 0 };  #endif @@ -351,8 +337,12 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,  				bytes_to_prefetch / sizeof(tile_bundle_bits);  		} -		/* Decode the next bundle. */ -		bundle.bits = prefetched_bundles[next_bundle++]; +		/* +		 * Decode the next bundle. +		 * TILE always stores instruction bundles in little-endian +		 * mode, even when the chip is running in big-endian mode. +		 */ +		bundle.bits = le64_to_cpu(prefetched_bundles[next_bundle++]);  		bundle.num_insns =  			parse_insn_tile(bundle.bits, pc, bundle.insns);  		num_info_ops = bt_get_info_ops(&bundle, info_operands); @@ -369,10 +359,6 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,  					/* Weird; reserved value, ignore it. */  					continue;  				} -				if (info_operand & ENTRY_POINT_INFO_OP)	{ -					/* This info op is ignored by the backtracer. */ -					continue; -				}  				/* Skip info ops which are not in the  				 * "one_ago" mode we want right now. @@ -453,7 +439,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,  		if (!sp_determined) {  			int adjust;  			if (bt_has_addi_sp(&bundle, &adjust) -#if TILE_CHIP >= 10 +#ifdef __tilegx__  			    || bt_has_add_sp(&bundle, &adjust, moveli_args)  #endif  				) { @@ -504,7 +490,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,  				}  			} -#if TILE_CHIP >= 10 +#ifdef __tilegx__  			/* Track moveli arguments for -m32 mode. */  			bt_update_moveli(&bundle, moveli_args);  #endif @@ -546,18 +532,26 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,  	}  } +/* Initializes a backtracer to start from the given location. + * + * If the frame pointer cannot be determined it is set to -1. + * + * state: The state to be filled in. + * read_memory_func: A callback that reads memory. + * read_memory_func_extra: An arbitrary argument to read_memory_func. + * pc: The current PC. + * lr: The current value of the 'lr' register. + * sp: The current value of the 'sp' register. + * r52: The current value of the 'r52' register. + */  void backtrace_init(BacktraceIterator *state,  		    BacktraceMemoryReader read_memory_func,  		    void *read_memory_func_extra, -		    VirtualAddress pc, VirtualAddress lr, -		    VirtualAddress sp, VirtualAddress r52) +		    unsigned long pc, unsigned long lr, +		    unsigned long sp, unsigned long r52)  {  	CallerLocation location; -	VirtualAddress fp, initial_frame_caller_pc; - -	if (read_memory_func == NULL) { -		read_memory_func = bt_read_memory; -	} +	unsigned long fp, initial_frame_caller_pc;  	/* Find out where we are in the initial frame. */  	find_caller_pc_and_caller_sp(&location, pc, @@ -630,12 +624,15 @@ void backtrace_init(BacktraceIterator *state,  /* 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); +	return ((unsigned long)reg == reg);  } +/* Advances the backtracing state to the calling frame, returning + * true iff successful. + */  bool backtrace_next(BacktraceIterator *state)  { -	VirtualAddress next_fp, next_pc; +	unsigned long next_fp, next_pc;  	bt_int_reg_t next_frame[2];  	if (state->fp == -1) {  | 
