arch/tile: refactor backtracing code
This change is the result of some work to make the backtrace code more shareable between kernel, libc, and gdb. For the kernel, some good effects are to eliminate the hacky "VirtualAddress" typedef in favor of "unsigned long", to eliminate a bunch of spurious kernel doc comments, to remove the dead "bt_read_memory" function, and to use "__tilegx__" in #ifdefs instead of "TILE_CHIP". Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
This commit is contained in:
parent
8e10cd7434
commit
93013a0f53
@ -12,80 +12,41 @@
|
|||||||
* more details.
|
* more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _TILE_BACKTRACE_H
|
#ifndef _ASM_TILE_BACKTRACE_H
|
||||||
#define _TILE_BACKTRACE_H
|
#define _ASM_TILE_BACKTRACE_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#include <arch/chip.h>
|
/* Reads 'size' bytes from 'address' and writes the data to 'result'.
|
||||||
|
|
||||||
#if defined(__tile__)
|
|
||||||
typedef unsigned long VirtualAddress;
|
|
||||||
#elif CHIP_VA_WIDTH() > 32
|
|
||||||
typedef unsigned long long VirtualAddress;
|
|
||||||
#else
|
|
||||||
typedef unsigned int VirtualAddress;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/** Reads 'size' bytes from 'address' and writes the data to 'result'.
|
|
||||||
* Returns true if successful, else false (e.g. memory not readable).
|
* Returns true if successful, else false (e.g. memory not readable).
|
||||||
*/
|
*/
|
||||||
typedef bool (*BacktraceMemoryReader)(void *result,
|
typedef bool (*BacktraceMemoryReader)(void *result,
|
||||||
VirtualAddress address,
|
unsigned long address,
|
||||||
unsigned int size,
|
unsigned int size,
|
||||||
void *extra);
|
void *extra);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/** Current PC. */
|
/* Current PC. */
|
||||||
VirtualAddress pc;
|
unsigned long pc;
|
||||||
|
|
||||||
/** Current stack pointer value. */
|
/* Current stack pointer value. */
|
||||||
VirtualAddress sp;
|
unsigned long sp;
|
||||||
|
|
||||||
/** Current frame pointer value (i.e. caller's stack pointer) */
|
/* Current frame pointer value (i.e. caller's stack pointer) */
|
||||||
VirtualAddress fp;
|
unsigned long fp;
|
||||||
|
|
||||||
/** Internal use only: caller's PC for first frame. */
|
/* Internal use only: caller's PC for first frame. */
|
||||||
VirtualAddress initial_frame_caller_pc;
|
unsigned long initial_frame_caller_pc;
|
||||||
|
|
||||||
/** Internal use only: callback to read memory. */
|
/* Internal use only: callback to read memory. */
|
||||||
BacktraceMemoryReader read_memory_func;
|
BacktraceMemoryReader read_memory_func;
|
||||||
|
|
||||||
/** Internal use only: arbitrary argument to read_memory_func. */
|
/* Internal use only: arbitrary argument to read_memory_func. */
|
||||||
void *read_memory_func_extra;
|
void *read_memory_func_extra;
|
||||||
|
|
||||||
} BacktraceIterator;
|
} BacktraceIterator;
|
||||||
|
|
||||||
|
|
||||||
/** Initializes a backtracer to start from the given location.
|
|
||||||
*
|
|
||||||
* If the frame pointer cannot be determined it is set to -1.
|
|
||||||
*
|
|
||||||
* @param state The state to be filled in.
|
|
||||||
* @param read_memory_func A callback that reads memory. If NULL, a default
|
|
||||||
* value is provided.
|
|
||||||
* @param read_memory_func_extra An arbitrary argument to read_memory_func.
|
|
||||||
* @param pc The current PC.
|
|
||||||
* @param lr The current value of the 'lr' register.
|
|
||||||
* @param sp The current value of the 'sp' register.
|
|
||||||
* @param r52 The current value of the 'r52' register.
|
|
||||||
*/
|
|
||||||
extern void backtrace_init(BacktraceIterator *state,
|
|
||||||
BacktraceMemoryReader read_memory_func,
|
|
||||||
void *read_memory_func_extra,
|
|
||||||
VirtualAddress pc, VirtualAddress lr,
|
|
||||||
VirtualAddress sp, VirtualAddress r52);
|
|
||||||
|
|
||||||
|
|
||||||
/** Advances the backtracing state to the calling frame, returning
|
|
||||||
* true iff successful.
|
|
||||||
*/
|
|
||||||
extern bool backtrace_next(BacktraceIterator *state);
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
||||||
/* We have no idea what the caller's pc is. */
|
/* We have no idea what the caller's pc is. */
|
||||||
@ -138,7 +99,7 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Internal constants used to define 'info' operands. */
|
/* Internal constants used to define 'info' operands. */
|
||||||
enum {
|
enum {
|
||||||
/* 0 and 1 are reserved, as are all negative numbers. */
|
/* 0 and 1 are reserved, as are all negative numbers. */
|
||||||
|
|
||||||
@ -147,13 +108,10 @@ enum {
|
|||||||
CALLER_SP_IN_R52_BASE = 4,
|
CALLER_SP_IN_R52_BASE = 4,
|
||||||
|
|
||||||
CALLER_SP_OFFSET_BASE = 8,
|
CALLER_SP_OFFSET_BASE = 8,
|
||||||
|
|
||||||
/* Marks the entry point of certain functions. */
|
|
||||||
ENTRY_POINT_INFO_OP = 16
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Current backtracer state describing where it thinks the caller is. */
|
/* Current backtracer state describing where it thinks the caller is. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/*
|
/*
|
||||||
* Public fields
|
* Public fields
|
||||||
@ -192,7 +150,13 @@ typedef struct {
|
|||||||
|
|
||||||
} CallerLocation;
|
} CallerLocation;
|
||||||
|
|
||||||
|
extern void backtrace_init(BacktraceIterator *state,
|
||||||
|
BacktraceMemoryReader read_memory_func,
|
||||||
|
void *read_memory_func_extra,
|
||||||
|
unsigned long pc, unsigned long lr,
|
||||||
|
unsigned long sp, unsigned long r52);
|
||||||
|
|
||||||
|
|
||||||
|
extern bool backtrace_next(BacktraceIterator *state);
|
||||||
|
|
||||||
#endif /* _TILE_BACKTRACE_H */
|
#endif /* _ASM_TILE_BACKTRACE_H */
|
||||||
|
@ -1502,5 +1502,12 @@ extern int parse_insn_tile(tile_bundle_bits bits,
|
|||||||
decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
|
decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
|
||||||
|
|
||||||
|
|
||||||
|
/* Given a set of bundle bits and a specific pipe, returns which
|
||||||
|
* instruction the bundle contains in that pipe.
|
||||||
|
*/
|
||||||
|
extern const struct tile_opcode *
|
||||||
|
find_opcode(tile_bundle_bits bits, tile_pipeline pipe);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* opcode_tile_h */
|
#endif /* opcode_tile_h */
|
||||||
|
@ -1502,5 +1502,12 @@ extern int parse_insn_tile(tile_bundle_bits bits,
|
|||||||
decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
|
decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
|
||||||
|
|
||||||
|
|
||||||
|
/* Given a set of bundle bits and a specific pipe, returns which
|
||||||
|
* instruction the bundle contains in that pipe.
|
||||||
|
*/
|
||||||
|
extern const struct tile_opcode *
|
||||||
|
find_opcode(tile_bundle_bits bits, tile_pipeline pipe);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* opcode_tile_h */
|
#endif /* opcode_tile_h */
|
||||||
|
@ -14,19 +14,11 @@
|
|||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
|
||||||
#include <asm/backtrace.h>
|
#include <asm/backtrace.h>
|
||||||
|
|
||||||
#include <arch/chip.h>
|
|
||||||
|
|
||||||
#include <asm/opcode-tile.h>
|
#include <asm/opcode-tile.h>
|
||||||
|
#include <arch/abi.h>
|
||||||
|
|
||||||
|
#ifdef __tilegx__
|
||||||
#define TREG_SP 54
|
|
||||||
#define TREG_LR 55
|
|
||||||
|
|
||||||
|
|
||||||
#if TILE_CHIP >= 10
|
|
||||||
#define tile_bundle_bits tilegx_bundle_bits
|
#define tile_bundle_bits tilegx_bundle_bits
|
||||||
#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE
|
#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE
|
||||||
#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES
|
#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES
|
||||||
@ -47,7 +39,7 @@ typedef long long bt_int_reg_t;
|
|||||||
typedef int bt_int_reg_t;
|
typedef int bt_int_reg_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** A decoded bundle used for backtracer analysis. */
|
/* A decoded bundle used for backtracer analysis. */
|
||||||
struct BacktraceBundle {
|
struct BacktraceBundle {
|
||||||
tile_bundle_bits bits;
|
tile_bundle_bits bits;
|
||||||
int num_insns;
|
int num_insns;
|
||||||
@ -56,23 +48,7 @@ struct BacktraceBundle {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* This implementation only makes sense for native tools. */
|
/* Locates an instruction inside the given bundle that
|
||||||
/** 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
|
|
||||||
* has the specified mnemonic, and whose first 'num_operands_to_match'
|
* has the specified mnemonic, and whose first 'num_operands_to_match'
|
||||||
* operands exactly match those in 'operand_values'.
|
* operands exactly match those in 'operand_values'.
|
||||||
*/
|
*/
|
||||||
@ -107,13 +83,13 @@ static const struct tile_decoded_instruction *find_matching_insn(
|
|||||||
return NULL;
|
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)
|
static inline bool bt_has_iret(const struct BacktraceBundle *bundle)
|
||||||
{
|
{
|
||||||
return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL;
|
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?
|
* 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET?
|
||||||
*/
|
*/
|
||||||
static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
|
static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
|
||||||
@ -124,7 +100,7 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
|
|||||||
find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2);
|
find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2);
|
||||||
if (insn == NULL)
|
if (insn == NULL)
|
||||||
insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2);
|
insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2);
|
||||||
#if TILE_CHIP >= 10
|
#ifdef __tilegx__
|
||||||
if (insn == NULL)
|
if (insn == NULL)
|
||||||
insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2);
|
insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2);
|
||||||
if (insn == NULL)
|
if (insn == NULL)
|
||||||
@ -137,7 +113,7 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
|
|||||||
return true;
|
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
|
* 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.
|
* as an unsigned value by this code since that's what the caller wants.
|
||||||
* Returns the number of info ops found.
|
* Returns the number of info ops found.
|
||||||
@ -161,7 +137,7 @@ static int bt_get_info_ops(const struct BacktraceBundle *bundle,
|
|||||||
return num_ops;
|
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?
|
* register is it jumping?
|
||||||
*/
|
*/
|
||||||
static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
|
static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
|
||||||
@ -175,7 +151,7 @@ static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
|
|||||||
return true;
|
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)
|
static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
@ -195,34 +171,34 @@ static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Does this bundle modify sp? */
|
/* Does this bundle modify sp? */
|
||||||
static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle)
|
static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle)
|
||||||
{
|
{
|
||||||
return bt_modifies_reg(bundle, TREG_SP);
|
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)
|
static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle)
|
||||||
{
|
{
|
||||||
return bt_modifies_reg(bundle, TREG_LR);
|
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 inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle)
|
||||||
{
|
{
|
||||||
static const int vals[2] = { 52, TREG_SP };
|
static const int vals[2] = { 52, TREG_SP };
|
||||||
return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL;
|
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 inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle)
|
||||||
{
|
{
|
||||||
static const int vals[2] = { TREG_SP, TREG_LR };
|
static const int vals[2] = { TREG_SP, TREG_LR };
|
||||||
return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL;
|
return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TILE_CHIP >= 10
|
#ifdef __tilegx__
|
||||||
/** Track moveli values placed into registers. */
|
/* Track moveli values placed into registers. */
|
||||||
static inline void bt_update_moveli(const struct BacktraceBundle *bundle,
|
static inline void bt_update_moveli(const struct BacktraceBundle *bundle,
|
||||||
int moveli_args[])
|
int moveli_args[])
|
||||||
{
|
{
|
||||||
@ -238,7 +214,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
|
* from a register that we saw a moveli into, and if so, what
|
||||||
* is the value in the register?
|
* is the value in the register?
|
||||||
*/
|
*/
|
||||||
@ -260,11 +236,11 @@ static bool bt_has_add_sp(const struct BacktraceBundle *bundle, int *adjust,
|
|||||||
}
|
}
|
||||||
#endif
|
#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.
|
* given address.
|
||||||
*/
|
*/
|
||||||
static void find_caller_pc_and_caller_sp(CallerLocation *location,
|
static void find_caller_pc_and_caller_sp(CallerLocation *location,
|
||||||
const VirtualAddress start_pc,
|
const unsigned long start_pc,
|
||||||
BacktraceMemoryReader read_memory_func,
|
BacktraceMemoryReader read_memory_func,
|
||||||
void *read_memory_func_extra)
|
void *read_memory_func_extra)
|
||||||
{
|
{
|
||||||
@ -288,9 +264,9 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
|
|||||||
tile_bundle_bits prefetched_bundles[32];
|
tile_bundle_bits prefetched_bundles[32];
|
||||||
int num_bundles_prefetched = 0;
|
int num_bundles_prefetched = 0;
|
||||||
int next_bundle = 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. */
|
/* Naively try to track moveli values to support addx for -m32. */
|
||||||
int moveli_args[TILEGX_NUM_REGISTERS] = { 0 };
|
int moveli_args[TILEGX_NUM_REGISTERS] = { 0 };
|
||||||
#endif
|
#endif
|
||||||
@ -369,10 +345,6 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
|
|||||||
/* Weird; reserved value, ignore it. */
|
/* Weird; reserved value, ignore it. */
|
||||||
continue;
|
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
|
/* Skip info ops which are not in the
|
||||||
* "one_ago" mode we want right now.
|
* "one_ago" mode we want right now.
|
||||||
@ -453,7 +425,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
|
|||||||
if (!sp_determined) {
|
if (!sp_determined) {
|
||||||
int adjust;
|
int adjust;
|
||||||
if (bt_has_addi_sp(&bundle, &adjust)
|
if (bt_has_addi_sp(&bundle, &adjust)
|
||||||
#if TILE_CHIP >= 10
|
#ifdef __tilegx__
|
||||||
|| bt_has_add_sp(&bundle, &adjust, moveli_args)
|
|| bt_has_add_sp(&bundle, &adjust, moveli_args)
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
@ -504,7 +476,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TILE_CHIP >= 10
|
#ifdef __tilegx__
|
||||||
/* Track moveli arguments for -m32 mode. */
|
/* Track moveli arguments for -m32 mode. */
|
||||||
bt_update_moveli(&bundle, moveli_args);
|
bt_update_moveli(&bundle, moveli_args);
|
||||||
#endif
|
#endif
|
||||||
@ -546,18 +518,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,
|
void backtrace_init(BacktraceIterator *state,
|
||||||
BacktraceMemoryReader read_memory_func,
|
BacktraceMemoryReader read_memory_func,
|
||||||
void *read_memory_func_extra,
|
void *read_memory_func_extra,
|
||||||
VirtualAddress pc, VirtualAddress lr,
|
unsigned long pc, unsigned long lr,
|
||||||
VirtualAddress sp, VirtualAddress r52)
|
unsigned long sp, unsigned long r52)
|
||||||
{
|
{
|
||||||
CallerLocation location;
|
CallerLocation location;
|
||||||
VirtualAddress fp, initial_frame_caller_pc;
|
unsigned long fp, initial_frame_caller_pc;
|
||||||
|
|
||||||
if (read_memory_func == NULL) {
|
|
||||||
read_memory_func = bt_read_memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find out where we are in the initial frame. */
|
/* Find out where we are in the initial frame. */
|
||||||
find_caller_pc_and_caller_sp(&location, pc,
|
find_caller_pc_and_caller_sp(&location, pc,
|
||||||
@ -630,12 +610,15 @@ void backtrace_init(BacktraceIterator *state,
|
|||||||
/* Handle the case where the register holds more bits than the VA. */
|
/* Handle the case where the register holds more bits than the VA. */
|
||||||
static bool valid_addr_reg(bt_int_reg_t reg)
|
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)
|
bool backtrace_next(BacktraceIterator *state)
|
||||||
{
|
{
|
||||||
VirtualAddress next_fp, next_pc;
|
unsigned long next_fp, next_pc;
|
||||||
bt_int_reg_t next_frame[2];
|
bt_int_reg_t next_frame[2];
|
||||||
|
|
||||||
if (state->fp == -1) {
|
if (state->fp == -1) {
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
#define KBT_LOOP 3 /* Backtrace entered a loop */
|
#define KBT_LOOP 3 /* Backtrace entered a loop */
|
||||||
|
|
||||||
/* Is address on the specified kernel stack? */
|
/* Is address on the specified kernel stack? */
|
||||||
static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
|
static int in_kernel_stack(struct KBacktraceIterator *kbt, unsigned long sp)
|
||||||
{
|
{
|
||||||
ulong kstack_base = (ulong) kbt->task->stack;
|
ulong kstack_base = (ulong) kbt->task->stack;
|
||||||
if (kstack_base == 0) /* corrupt task pointer; just follow stack... */
|
if (kstack_base == 0) /* corrupt task pointer; just follow stack... */
|
||||||
@ -45,7 +45,7 @@ static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Is address valid for reading? */
|
/* Is address valid for reading? */
|
||||||
static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
|
static int valid_address(struct KBacktraceIterator *kbt, unsigned long address)
|
||||||
{
|
{
|
||||||
HV_PTE *l1_pgtable = kbt->pgtable;
|
HV_PTE *l1_pgtable = kbt->pgtable;
|
||||||
HV_PTE *l2_pgtable;
|
HV_PTE *l2_pgtable;
|
||||||
@ -97,7 +97,7 @@ static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Callback for backtracer; basically a glorified memcpy */
|
/* Callback for backtracer; basically a glorified memcpy */
|
||||||
static bool read_memory_func(void *result, VirtualAddress address,
|
static bool read_memory_func(void *result, unsigned long address,
|
||||||
unsigned int size, void *vkbt)
|
unsigned int size, void *vkbt)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
@ -124,7 +124,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
|
|||||||
{
|
{
|
||||||
const char *fault = NULL; /* happy compiler */
|
const char *fault = NULL; /* happy compiler */
|
||||||
char fault_buf[64];
|
char fault_buf[64];
|
||||||
VirtualAddress sp = kbt->it.sp;
|
unsigned long sp = kbt->it.sp;
|
||||||
struct pt_regs *p;
|
struct pt_regs *p;
|
||||||
|
|
||||||
if (!in_kernel_stack(kbt, sp))
|
if (!in_kernel_stack(kbt, sp))
|
||||||
@ -163,7 +163,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Is the pc pointing to a sigreturn trampoline? */
|
/* Is the pc pointing to a sigreturn trampoline? */
|
||||||
static int is_sigreturn(VirtualAddress pc)
|
static int is_sigreturn(unsigned long pc)
|
||||||
{
|
{
|
||||||
return (pc == VDSO_BASE);
|
return (pc == VDSO_BASE);
|
||||||
}
|
}
|
||||||
@ -260,7 +260,7 @@ static void validate_stack(struct pt_regs *regs)
|
|||||||
void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
|
void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
|
||||||
struct task_struct *t, struct pt_regs *regs)
|
struct task_struct *t, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
VirtualAddress pc, lr, sp, r52;
|
unsigned long pc, lr, sp, r52;
|
||||||
int is_current;
|
int is_current;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -331,7 +331,7 @@ EXPORT_SYMBOL(KBacktraceIterator_end);
|
|||||||
|
|
||||||
void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
|
void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
|
||||||
{
|
{
|
||||||
VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp;
|
unsigned long old_pc = kbt->it.pc, old_sp = kbt->it.sp;
|
||||||
kbt->new_context = 0;
|
kbt->new_context = 0;
|
||||||
if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) {
|
if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) {
|
||||||
kbt->end = KBT_DONE;
|
kbt->end = KBT_DONE;
|
||||||
|
@ -2413,12 +2413,13 @@ const struct tile_operand tile_operands[43] =
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Given a set of bundle bits and the lookup FSM for a specific pipe,
|
/* Given a set of bundle bits and a specific pipe, returns which
|
||||||
* returns which instruction the bundle contains in that pipe.
|
* instruction the bundle contains in that pipe.
|
||||||
*/
|
*/
|
||||||
static const struct tile_opcode *
|
const struct tile_opcode *
|
||||||
find_opcode(tile_bundle_bits bits, const unsigned short *table)
|
find_opcode(tile_bundle_bits bits, tile_pipeline pipe)
|
||||||
{
|
{
|
||||||
|
const unsigned short *table = tile_bundle_decoder_fsms[pipe];
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
@ -2465,7 +2466,7 @@ parse_insn_tile(tile_bundle_bits bits,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
d = &decoded[num_instructions++];
|
d = &decoded[num_instructions++];
|
||||||
opc = find_opcode (bits, tile_bundle_decoder_fsms[pipe]);
|
opc = find_opcode (bits, (tile_pipeline)pipe);
|
||||||
d->opcode = opc;
|
d->opcode = opc;
|
||||||
|
|
||||||
/* Decode each operand, sign extending, etc. as appropriate. */
|
/* Decode each operand, sign extending, etc. as appropriate. */
|
||||||
|
Loading…
Reference in New Issue
Block a user