aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2010-08-13 08:40:57 -0400
committerChris Metcalf <cmetcalf@tilera.com>2010-08-13 08:40:57 -0400
commit1fcbe027b5d29ec9cd0eeb753c14fb366ae852ac (patch)
treeb0d80646567ac71238cf2ffb33e29ad33d758816
parent32020effaf713c0c669864301bcd5dac6b9bb9e0 (diff)
arch/tile: support backtracing on TILE-Gx
This functionality was stubbed out until recently. Now we support our normal backtracing API on TILE-Gx as well as on TILE64/TILEPro. This change includes a tweak to the instruction encoding caused by adding addxli for compat mode. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
-rw-r--r--arch/tile/include/asm/backtrace.h4
-rw-r--r--arch/tile/kernel/backtrace.c137
-rw-r--r--arch/tile/kernel/stack.c8
-rw-r--r--arch/tile/kernel/traps.c4
4 files changed, 105 insertions, 48 deletions
diff --git a/arch/tile/include/asm/backtrace.h b/arch/tile/include/asm/backtrace.h
index 6970bfcad549..758ca4619d50 100644
--- a/arch/tile/include/asm/backtrace.h
+++ b/arch/tile/include/asm/backtrace.h
@@ -21,7 +21,9 @@
21 21
22#include <arch/chip.h> 22#include <arch/chip.h>
23 23
24#if CHIP_VA_WIDTH() > 32 24#if defined(__tile__)
25typedef unsigned long VirtualAddress;
26#elif CHIP_VA_WIDTH() > 32
25typedef unsigned long long VirtualAddress; 27typedef unsigned long long VirtualAddress;
26#else 28#else
27typedef unsigned int VirtualAddress; 29typedef unsigned int VirtualAddress;
diff --git a/arch/tile/kernel/backtrace.c b/arch/tile/kernel/backtrace.c
index 77265f3b58d6..d3c41c1ff6bd 100644
--- a/arch/tile/kernel/backtrace.c
+++ b/arch/tile/kernel/backtrace.c
@@ -19,9 +19,6 @@
19 19
20#include <arch/chip.h> 20#include <arch/chip.h>
21 21
22#if TILE_CHIP < 10
23
24
25#include <asm/opcode-tile.h> 22#include <asm/opcode-tile.h>
26 23
27 24
@@ -29,6 +26,27 @@
29#define TREG_LR 55 26#define TREG_LR 55
30 27
31 28
29#if TILE_CHIP >= 10
30#define tile_bundle_bits tilegx_bundle_bits
31#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE
32#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES
33#define tile_decoded_instruction tilegx_decoded_instruction
34#define tile_mnemonic tilegx_mnemonic
35#define parse_insn_tile parse_insn_tilegx
36#define TILE_OPC_IRET TILEGX_OPC_IRET
37#define TILE_OPC_ADDI TILEGX_OPC_ADDI
38#define TILE_OPC_ADDLI TILEGX_OPC_ADDLI
39#define TILE_OPC_INFO TILEGX_OPC_INFO
40#define TILE_OPC_INFOL TILEGX_OPC_INFOL
41#define TILE_OPC_JRP TILEGX_OPC_JRP
42#define TILE_OPC_MOVE TILEGX_OPC_MOVE
43#define OPCODE_STORE TILEGX_OPC_ST
44typedef long long bt_int_reg_t;
45#else
46#define OPCODE_STORE TILE_OPC_SW
47typedef int bt_int_reg_t;
48#endif
49
32/** A decoded bundle used for backtracer analysis. */ 50/** A decoded bundle used for backtracer analysis. */
33struct BacktraceBundle { 51struct BacktraceBundle {
34 tile_bundle_bits bits; 52 tile_bundle_bits bits;
@@ -41,7 +59,7 @@ struct BacktraceBundle {
41/* This implementation only makes sense for native tools. */ 59/* This implementation only makes sense for native tools. */
42/** Default function to read memory. */ 60/** Default function to read memory. */
43static bool bt_read_memory(void *result, VirtualAddress addr, 61static bool bt_read_memory(void *result, VirtualAddress addr,
44 size_t size, void *extra) 62 unsigned int size, void *extra)
45{ 63{
46 /* FIXME: this should do some horrible signal stuff to catch 64 /* FIXME: this should do some horrible signal stuff to catch
47 * SEGV cleanly and fail. 65 * SEGV cleanly and fail.
@@ -106,6 +124,12 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
106 find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2); 124 find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2);
107 if (insn == NULL) 125 if (insn == NULL)
108 insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2); 126 insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2);
127#if TILE_CHIP >= 10
128 if (insn == NULL)
129 insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2);
130 if (insn == NULL)
131 insn = find_matching_insn(bundle, TILEGX_OPC_ADDXI, vals, 2);
132#endif
109 if (insn == NULL) 133 if (insn == NULL)
110 return false; 134 return false;
111 135
@@ -190,13 +214,52 @@ static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle)
190 return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL; 214 return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL;
191} 215}
192 216
193/** Does this bundle contain the instruction 'sw sp, lr'? */ 217/** Does this bundle contain a store of lr to sp? */
194static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle) 218static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle)
195{ 219{
196 static const int vals[2] = { TREG_SP, TREG_LR }; 220 static const int vals[2] = { TREG_SP, TREG_LR };
197 return find_matching_insn(bundle, TILE_OPC_SW, vals, 2) != NULL; 221 return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL;
222}
223
224#if TILE_CHIP >= 10
225/** Track moveli values placed into registers. */
226static inline void bt_update_moveli(const struct BacktraceBundle *bundle,
227 int moveli_args[])
228{
229 int i;
230 for (i = 0; i < bundle->num_insns; i++) {
231 const struct tile_decoded_instruction *insn =
232 &bundle->insns[i];
233
234 if (insn->opcode->mnemonic == TILEGX_OPC_MOVELI) {
235 int reg = insn->operand_values[0];
236 moveli_args[reg] = insn->operand_values[1];
237 }
238 }
198} 239}
199 240
241/** Does this bundle contain an 'add sp, sp, reg' instruction
242 * from a register that we saw a moveli into, and if so, what
243 * is the value in the register?
244 */
245static bool bt_has_add_sp(const struct BacktraceBundle *bundle, int *adjust,
246 int moveli_args[])
247{
248 static const int vals[2] = { TREG_SP, TREG_SP };
249
250 const struct tile_decoded_instruction *insn =
251 find_matching_insn(bundle, TILEGX_OPC_ADDX, vals, 2);
252 if (insn) {
253 int reg = insn->operand_values[2];
254 if (moveli_args[reg]) {
255 *adjust = moveli_args[reg];
256 return true;
257 }
258 }
259 return false;
260}
261#endif
262
200/** Locates the caller's PC and SP for a program starting at the 263/** Locates the caller's PC and SP for a program starting at the
201 * given address. 264 * given address.
202 */ 265 */
@@ -227,6 +290,11 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
227 int next_bundle = 0; 290 int next_bundle = 0;
228 VirtualAddress pc; 291 VirtualAddress pc;
229 292
293#if TILE_CHIP >= 10
294 /* Naively try to track moveli values to support addx for -m32. */
295 int moveli_args[TILEGX_NUM_REGISTERS] = { 0 };
296#endif
297
230 /* Default to assuming that the caller's sp is the current sp. 298 /* Default to assuming that the caller's sp is the current sp.
231 * This is necessary to handle the case where we start backtracing 299 * This is necessary to handle the case where we start backtracing
232 * right at the end of the epilog. 300 * right at the end of the epilog.
@@ -380,7 +448,11 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
380 448
381 if (!sp_determined) { 449 if (!sp_determined) {
382 int adjust; 450 int adjust;
383 if (bt_has_addi_sp(&bundle, &adjust)) { 451 if (bt_has_addi_sp(&bundle, &adjust)
452#if TILE_CHIP >= 10
453 || bt_has_add_sp(&bundle, &adjust, moveli_args)
454#endif
455 ) {
384 location->sp_location = SP_LOC_OFFSET; 456 location->sp_location = SP_LOC_OFFSET;
385 457
386 if (adjust <= 0) { 458 if (adjust <= 0) {
@@ -427,6 +499,11 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
427 sp_determined = true; 499 sp_determined = true;
428 } 500 }
429 } 501 }
502
503#if TILE_CHIP >= 10
504 /* Track moveli arguments for -m32 mode. */
505 bt_update_moveli(&bundle, moveli_args);
506#endif
430 } 507 }
431 508
432 if (bt_has_iret(&bundle)) { 509 if (bt_has_iret(&bundle)) {
@@ -502,11 +579,10 @@ void backtrace_init(BacktraceIterator *state,
502 break; 579 break;
503 } 580 }
504 581
505 /* The frame pointer should theoretically be aligned mod 8. If 582 /* If the frame pointer is not aligned to the basic word size
506 * it's not even aligned mod 4 then something terrible happened 583 * something terrible happened and we should mark it as invalid.
507 * and we should mark it as invalid.
508 */ 584 */
509 if (fp % 4 != 0) 585 if (fp % sizeof(bt_int_reg_t) != 0)
510 fp = -1; 586 fp = -1;
511 587
512 /* -1 means "don't know initial_frame_caller_pc". */ 588 /* -1 means "don't know initial_frame_caller_pc". */
@@ -547,9 +623,16 @@ void backtrace_init(BacktraceIterator *state,
547 state->read_memory_func_extra = read_memory_func_extra; 623 state->read_memory_func_extra = read_memory_func_extra;
548} 624}
549 625
626/* Handle the case where the register holds more bits than the VA. */
627static bool valid_addr_reg(bt_int_reg_t reg)
628{
629 return ((VirtualAddress)reg == reg);
630}
631
550bool backtrace_next(BacktraceIterator *state) 632bool backtrace_next(BacktraceIterator *state)
551{ 633{
552 VirtualAddress next_fp, next_pc, next_frame[2]; 634 VirtualAddress next_fp, next_pc;
635 bt_int_reg_t next_frame[2];
553 636
554 if (state->fp == -1) { 637 if (state->fp == -1) {
555 /* No parent frame. */ 638 /* No parent frame. */
@@ -563,11 +646,9 @@ bool backtrace_next(BacktraceIterator *state)
563 } 646 }
564 647
565 next_fp = next_frame[1]; 648 next_fp = next_frame[1];
566 if (next_fp % 4 != 0) { 649 if (!valid_addr_reg(next_frame[1]) ||
567 /* Caller's frame pointer is suspect, so give up. 650 next_fp % sizeof(bt_int_reg_t) != 0) {
568 * Technically it should be aligned mod 8, but we will 651 /* Caller's frame pointer is suspect, so give up. */
569 * be forgiving here.
570 */
571 return false; 652 return false;
572 } 653 }
573 654
@@ -585,7 +666,7 @@ bool backtrace_next(BacktraceIterator *state)
585 } else { 666 } else {
586 /* Get the caller PC from the frame linkage area. */ 667 /* Get the caller PC from the frame linkage area. */
587 next_pc = next_frame[0]; 668 next_pc = next_frame[0];
588 if (next_pc == 0 || 669 if (!valid_addr_reg(next_frame[0]) || next_pc == 0 ||
589 next_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0) { 670 next_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0) {
590 /* The PC is suspect, so give up. */ 671 /* The PC is suspect, so give up. */
591 return false; 672 return false;
@@ -599,23 +680,3 @@ bool backtrace_next(BacktraceIterator *state)
599 680
600 return true; 681 return true;
601} 682}
602
603#else /* TILE_CHIP < 10 */
604
605void backtrace_init(BacktraceIterator *state,
606 BacktraceMemoryReader read_memory_func,
607 void *read_memory_func_extra,
608 VirtualAddress pc, VirtualAddress lr,
609 VirtualAddress sp, VirtualAddress r52)
610{
611 state->pc = pc;
612 state->sp = sp;
613 state->fp = -1;
614 state->initial_frame_caller_pc = -1;
615 state->read_memory_func = read_memory_func;
616 state->read_memory_func_extra = read_memory_func_extra;
617}
618
619bool backtrace_next(BacktraceIterator *state) { return false; }
620
621#endif /* TILE_CHIP < 10 */
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index b6268d3ae869..38a68b0b4581 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -108,7 +108,6 @@ static bool read_memory_func(void *result, VirtualAddress address,
108/* Return a pt_regs pointer for a valid fault handler frame */ 108/* Return a pt_regs pointer for a valid fault handler frame */
109static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt) 109static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
110{ 110{
111#ifndef __tilegx__
112 const char *fault = NULL; /* happy compiler */ 111 const char *fault = NULL; /* happy compiler */
113 char fault_buf[64]; 112 char fault_buf[64];
114 VirtualAddress sp = kbt->it.sp; 113 VirtualAddress sp = kbt->it.sp;
@@ -146,7 +145,6 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
146 } 145 }
147 if (!kbt->profile || (INT_MASK(p->faultnum) & QUEUED_INTERRUPTS) == 0) 146 if (!kbt->profile || (INT_MASK(p->faultnum) & QUEUED_INTERRUPTS) == 0)
148 return p; 147 return p;
149#endif
150 return NULL; 148 return NULL;
151} 149}
152 150
@@ -351,12 +349,6 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers)
351 kbt->task->pid, kbt->task->tgid, kbt->task->comm, 349 kbt->task->pid, kbt->task->tgid, kbt->task->comm,
352 smp_processor_id(), get_cycles()); 350 smp_processor_id(), get_cycles());
353 } 351 }
354#ifdef __tilegx__
355 if (kbt->is_current) {
356 __insn_mtspr(SPR_SIM_CONTROL,
357 SIM_DUMP_SPR_ARG(SIM_DUMP_BACKTRACE));
358 }
359#endif
360 kbt->verbose = 1; 352 kbt->verbose = 1;
361 i = 0; 353 i = 0;
362 for (; !KBacktraceIterator_end(kbt); KBacktraceIterator_next(kbt)) { 354 for (; !KBacktraceIterator_end(kbt); KBacktraceIterator_next(kbt)) {
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 3870abbeeaa2..0f362dc2c57f 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -128,7 +128,9 @@ static int special_ill(bundle_bits bundle, int *sigp, int *codep)
128#ifdef __tilegx__ 128#ifdef __tilegx__
129 if ((bundle & TILEGX_BUNDLE_MODE_MASK) != 0) 129 if ((bundle & TILEGX_BUNDLE_MODE_MASK) != 0)
130 return 0; 130 return 0;
131 if (get_Opcode_X1(bundle) != UNARY_OPCODE_X1) 131 if (get_Opcode_X1(bundle) != RRR_0_OPCODE_X1)
132 return 0;
133 if (get_RRROpcodeExtension_X1(bundle) != UNARY_RRR_0_OPCODE_X1)
132 return 0; 134 return 0;
133 if (get_UnaryOpcodeExtension_X1(bundle) != ILL_UNARY_OPCODE_X1) 135 if (get_UnaryOpcodeExtension_X1(bundle) != ILL_UNARY_OPCODE_X1)
134 return 0; 136 return 0;