|
@@ -14,19 +14,11 @@
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/string.h>
|
|
|
-
|
|
|
#include <asm/backtrace.h>
|
|
|
-
|
|
|
-#include <arch/chip.h>
|
|
|
-
|
|
|
#include <asm/opcode-tile.h>
|
|
|
+#include <arch/abi.h>
|
|
|
|
|
|
-
|
|
|
-#define TREG_SP 54
|
|
|
-#define TREG_LR 55
|
|
|
-
|
|
|
-
|
|
|
-#if TILE_CHIP >= 10
|
|
|
+#ifdef __tilegx__
|
|
|
#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
|
|
@@ -47,7 +39,7 @@ typedef long long bt_int_reg_t;
|
|
|
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 +48,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 +83,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 +100,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 +113,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 +137,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 +151,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 +171,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 +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
|
|
|
* is the value in the register?
|
|
|
*/
|
|
@@ -260,11 +236,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 +264,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
|
|
@@ -369,10 +345,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 +425,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 +476,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 +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,
|
|
|
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 +610,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) {
|