diff options
Diffstat (limited to 'arch/tile/kernel/backtrace.c')
-rw-r--r-- | arch/tile/kernel/backtrace.c | 103 |
1 files changed, 43 insertions, 60 deletions
diff --git a/arch/tile/kernel/backtrace.c b/arch/tile/kernel/backtrace.c index 55a6a74974b4..1dc71eabfc5a 100644 --- a/arch/tile/kernel/backtrace.c +++ b/arch/tile/kernel/backtrace.c | |||
@@ -14,19 +14,11 @@ | |||
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | |||
18 | #include <asm/backtrace.h> | 17 | #include <asm/backtrace.h> |
19 | |||
20 | #include <arch/chip.h> | ||
21 | |||
22 | #include <asm/opcode-tile.h> | 18 | #include <asm/opcode-tile.h> |
19 | #include <arch/abi.h> | ||
23 | 20 | ||
24 | 21 | #ifdef __tilegx__ | |
25 | #define TREG_SP 54 | ||
26 | #define TREG_LR 55 | ||
27 | |||
28 | |||
29 | #if TILE_CHIP >= 10 | ||
30 | #define tile_bundle_bits tilegx_bundle_bits | 22 | #define tile_bundle_bits tilegx_bundle_bits |
31 | #define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE | 23 | #define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE |
32 | #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES | 24 | #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES |
@@ -47,7 +39,7 @@ typedef long long bt_int_reg_t; | |||
47 | typedef int bt_int_reg_t; | 39 | typedef int bt_int_reg_t; |
48 | #endif | 40 | #endif |
49 | 41 | ||
50 | /** A decoded bundle used for backtracer analysis. */ | 42 | /* A decoded bundle used for backtracer analysis. */ |
51 | struct BacktraceBundle { | 43 | struct BacktraceBundle { |
52 | tile_bundle_bits bits; | 44 | tile_bundle_bits bits; |
53 | int num_insns; | 45 | int num_insns; |
@@ -56,23 +48,7 @@ struct BacktraceBundle { | |||
56 | }; | 48 | }; |
57 | 49 | ||
58 | 50 | ||
59 | /* This implementation only makes sense for native tools. */ | 51 | /* Locates an instruction inside the given bundle that |
60 | /** Default function to read memory. */ | ||
61 | static bool bt_read_memory(void *result, VirtualAddress addr, | ||
62 | unsigned int size, void *extra) | ||
63 | { | ||
64 | /* FIXME: this should do some horrible signal stuff to catch | ||
65 | * SEGV cleanly and fail. | ||
66 | * | ||
67 | * Or else the caller should do the setjmp for efficiency. | ||
68 | */ | ||
69 | |||
70 | memcpy(result, (const void *)addr, size); | ||
71 | return true; | ||
72 | } | ||
73 | |||
74 | |||
75 | /** Locates an instruction inside the given bundle that | ||
76 | * has the specified mnemonic, and whose first 'num_operands_to_match' | 52 | * has the specified mnemonic, and whose first 'num_operands_to_match' |
77 | * operands exactly match those in 'operand_values'. | 53 | * operands exactly match those in 'operand_values'. |
78 | */ | 54 | */ |
@@ -107,13 +83,13 @@ static const struct tile_decoded_instruction *find_matching_insn( | |||
107 | return NULL; | 83 | return NULL; |
108 | } | 84 | } |
109 | 85 | ||
110 | /** Does this bundle contain an 'iret' instruction? */ | 86 | /* Does this bundle contain an 'iret' instruction? */ |
111 | static inline bool bt_has_iret(const struct BacktraceBundle *bundle) | 87 | static inline bool bt_has_iret(const struct BacktraceBundle *bundle) |
112 | { | 88 | { |
113 | return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL; | 89 | return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL; |
114 | } | 90 | } |
115 | 91 | ||
116 | /** Does this bundle contain an 'addi sp, sp, OFFSET' or | 92 | /* Does this bundle contain an 'addi sp, sp, OFFSET' or |
117 | * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET? | 93 | * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET? |
118 | */ | 94 | */ |
119 | static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust) | 95 | 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) | |||
124 | find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2); | 100 | find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2); |
125 | if (insn == NULL) | 101 | if (insn == NULL) |
126 | insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2); | 102 | insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2); |
127 | #if TILE_CHIP >= 10 | 103 | #ifdef __tilegx__ |
128 | if (insn == NULL) | 104 | if (insn == NULL) |
129 | insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2); | 105 | insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2); |
130 | if (insn == NULL) | 106 | if (insn == NULL) |
@@ -137,7 +113,7 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust) | |||
137 | return true; | 113 | return true; |
138 | } | 114 | } |
139 | 115 | ||
140 | /** Does this bundle contain any 'info OP' or 'infol OP' | 116 | /* Does this bundle contain any 'info OP' or 'infol OP' |
141 | * instruction, and if so, what are their OP? Note that OP is interpreted | 117 | * instruction, and if so, what are their OP? Note that OP is interpreted |
142 | * as an unsigned value by this code since that's what the caller wants. | 118 | * as an unsigned value by this code since that's what the caller wants. |
143 | * Returns the number of info ops found. | 119 | * Returns the number of info ops found. |
@@ -161,7 +137,7 @@ static int bt_get_info_ops(const struct BacktraceBundle *bundle, | |||
161 | return num_ops; | 137 | return num_ops; |
162 | } | 138 | } |
163 | 139 | ||
164 | /** Does this bundle contain a jrp instruction, and if so, to which | 140 | /* Does this bundle contain a jrp instruction, and if so, to which |
165 | * register is it jumping? | 141 | * register is it jumping? |
166 | */ | 142 | */ |
167 | static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg) | 143 | 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) | |||
175 | return true; | 151 | return true; |
176 | } | 152 | } |
177 | 153 | ||
178 | /** Does this bundle modify the specified register in any way? */ | 154 | /* Does this bundle modify the specified register in any way? */ |
179 | static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg) | 155 | static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg) |
180 | { | 156 | { |
181 | int i, j; | 157 | int i, j; |
@@ -195,34 +171,34 @@ static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg) | |||
195 | return false; | 171 | return false; |
196 | } | 172 | } |
197 | 173 | ||
198 | /** Does this bundle modify sp? */ | 174 | /* Does this bundle modify sp? */ |
199 | static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle) | 175 | static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle) |
200 | { | 176 | { |
201 | return bt_modifies_reg(bundle, TREG_SP); | 177 | return bt_modifies_reg(bundle, TREG_SP); |
202 | } | 178 | } |
203 | 179 | ||
204 | /** Does this bundle modify lr? */ | 180 | /* Does this bundle modify lr? */ |
205 | static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle) | 181 | static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle) |
206 | { | 182 | { |
207 | return bt_modifies_reg(bundle, TREG_LR); | 183 | return bt_modifies_reg(bundle, TREG_LR); |
208 | } | 184 | } |
209 | 185 | ||
210 | /** Does this bundle contain the instruction 'move fp, sp'? */ | 186 | /* Does this bundle contain the instruction 'move fp, sp'? */ |
211 | static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle) | 187 | static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle) |
212 | { | 188 | { |
213 | static const int vals[2] = { 52, TREG_SP }; | 189 | static const int vals[2] = { 52, TREG_SP }; |
214 | return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL; | 190 | return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL; |
215 | } | 191 | } |
216 | 192 | ||
217 | /** Does this bundle contain a store of lr to sp? */ | 193 | /* Does this bundle contain a store of lr to sp? */ |
218 | static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle) | 194 | static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle) |
219 | { | 195 | { |
220 | static const int vals[2] = { TREG_SP, TREG_LR }; | 196 | static const int vals[2] = { TREG_SP, TREG_LR }; |
221 | return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL; | 197 | return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL; |
222 | } | 198 | } |
223 | 199 | ||
224 | #if TILE_CHIP >= 10 | 200 | #ifdef __tilegx__ |
225 | /** Track moveli values placed into registers. */ | 201 | /* Track moveli values placed into registers. */ |
226 | static inline void bt_update_moveli(const struct BacktraceBundle *bundle, | 202 | static inline void bt_update_moveli(const struct BacktraceBundle *bundle, |
227 | int moveli_args[]) | 203 | int moveli_args[]) |
228 | { | 204 | { |
@@ -238,7 +214,7 @@ static inline void bt_update_moveli(const struct BacktraceBundle *bundle, | |||
238 | } | 214 | } |
239 | } | 215 | } |
240 | 216 | ||
241 | /** Does this bundle contain an 'add sp, sp, reg' instruction | 217 | /* Does this bundle contain an 'add sp, sp, reg' instruction |
242 | * from a register that we saw a moveli into, and if so, what | 218 | * from a register that we saw a moveli into, and if so, what |
243 | * is the value in the register? | 219 | * is the value in the register? |
244 | */ | 220 | */ |
@@ -260,11 +236,11 @@ static bool bt_has_add_sp(const struct BacktraceBundle *bundle, int *adjust, | |||
260 | } | 236 | } |
261 | #endif | 237 | #endif |
262 | 238 | ||
263 | /** Locates the caller's PC and SP for a program starting at the | 239 | /* Locates the caller's PC and SP for a program starting at the |
264 | * given address. | 240 | * given address. |
265 | */ | 241 | */ |
266 | static void find_caller_pc_and_caller_sp(CallerLocation *location, | 242 | static void find_caller_pc_and_caller_sp(CallerLocation *location, |
267 | const VirtualAddress start_pc, | 243 | const unsigned long start_pc, |
268 | BacktraceMemoryReader read_memory_func, | 244 | BacktraceMemoryReader read_memory_func, |
269 | void *read_memory_func_extra) | 245 | void *read_memory_func_extra) |
270 | { | 246 | { |
@@ -288,9 +264,9 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location, | |||
288 | tile_bundle_bits prefetched_bundles[32]; | 264 | tile_bundle_bits prefetched_bundles[32]; |
289 | int num_bundles_prefetched = 0; | 265 | int num_bundles_prefetched = 0; |
290 | int next_bundle = 0; | 266 | int next_bundle = 0; |
291 | VirtualAddress pc; | 267 | unsigned long pc; |
292 | 268 | ||
293 | #if TILE_CHIP >= 10 | 269 | #ifdef __tilegx__ |
294 | /* Naively try to track moveli values to support addx for -m32. */ | 270 | /* Naively try to track moveli values to support addx for -m32. */ |
295 | int moveli_args[TILEGX_NUM_REGISTERS] = { 0 }; | 271 | int moveli_args[TILEGX_NUM_REGISTERS] = { 0 }; |
296 | #endif | 272 | #endif |
@@ -369,10 +345,6 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location, | |||
369 | /* Weird; reserved value, ignore it. */ | 345 | /* Weird; reserved value, ignore it. */ |
370 | continue; | 346 | continue; |
371 | } | 347 | } |
372 | if (info_operand & ENTRY_POINT_INFO_OP) { | ||
373 | /* This info op is ignored by the backtracer. */ | ||
374 | continue; | ||
375 | } | ||
376 | 348 | ||
377 | /* Skip info ops which are not in the | 349 | /* Skip info ops which are not in the |
378 | * "one_ago" mode we want right now. | 350 | * "one_ago" mode we want right now. |
@@ -453,7 +425,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location, | |||
453 | if (!sp_determined) { | 425 | if (!sp_determined) { |
454 | int adjust; | 426 | int adjust; |
455 | if (bt_has_addi_sp(&bundle, &adjust) | 427 | if (bt_has_addi_sp(&bundle, &adjust) |
456 | #if TILE_CHIP >= 10 | 428 | #ifdef __tilegx__ |
457 | || bt_has_add_sp(&bundle, &adjust, moveli_args) | 429 | || bt_has_add_sp(&bundle, &adjust, moveli_args) |
458 | #endif | 430 | #endif |
459 | ) { | 431 | ) { |
@@ -504,7 +476,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location, | |||
504 | } | 476 | } |
505 | } | 477 | } |
506 | 478 | ||
507 | #if TILE_CHIP >= 10 | 479 | #ifdef __tilegx__ |
508 | /* Track moveli arguments for -m32 mode. */ | 480 | /* Track moveli arguments for -m32 mode. */ |
509 | bt_update_moveli(&bundle, moveli_args); | 481 | bt_update_moveli(&bundle, moveli_args); |
510 | #endif | 482 | #endif |
@@ -546,18 +518,26 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location, | |||
546 | } | 518 | } |
547 | } | 519 | } |
548 | 520 | ||
521 | /* Initializes a backtracer to start from the given location. | ||
522 | * | ||
523 | * If the frame pointer cannot be determined it is set to -1. | ||
524 | * | ||
525 | * state: The state to be filled in. | ||
526 | * read_memory_func: A callback that reads memory. | ||
527 | * read_memory_func_extra: An arbitrary argument to read_memory_func. | ||
528 | * pc: The current PC. | ||
529 | * lr: The current value of the 'lr' register. | ||
530 | * sp: The current value of the 'sp' register. | ||
531 | * r52: The current value of the 'r52' register. | ||
532 | */ | ||
549 | void backtrace_init(BacktraceIterator *state, | 533 | void backtrace_init(BacktraceIterator *state, |
550 | BacktraceMemoryReader read_memory_func, | 534 | BacktraceMemoryReader read_memory_func, |
551 | void *read_memory_func_extra, | 535 | void *read_memory_func_extra, |
552 | VirtualAddress pc, VirtualAddress lr, | 536 | unsigned long pc, unsigned long lr, |
553 | VirtualAddress sp, VirtualAddress r52) | 537 | unsigned long sp, unsigned long r52) |
554 | { | 538 | { |
555 | CallerLocation location; | 539 | CallerLocation location; |
556 | VirtualAddress fp, initial_frame_caller_pc; | 540 | unsigned long fp, initial_frame_caller_pc; |
557 | |||
558 | if (read_memory_func == NULL) { | ||
559 | read_memory_func = bt_read_memory; | ||
560 | } | ||
561 | 541 | ||
562 | /* Find out where we are in the initial frame. */ | 542 | /* Find out where we are in the initial frame. */ |
563 | find_caller_pc_and_caller_sp(&location, pc, | 543 | find_caller_pc_and_caller_sp(&location, pc, |
@@ -630,12 +610,15 @@ void backtrace_init(BacktraceIterator *state, | |||
630 | /* Handle the case where the register holds more bits than the VA. */ | 610 | /* Handle the case where the register holds more bits than the VA. */ |
631 | static bool valid_addr_reg(bt_int_reg_t reg) | 611 | static bool valid_addr_reg(bt_int_reg_t reg) |
632 | { | 612 | { |
633 | return ((VirtualAddress)reg == reg); | 613 | return ((unsigned long)reg == reg); |
634 | } | 614 | } |
635 | 615 | ||
616 | /* Advances the backtracing state to the calling frame, returning | ||
617 | * true iff successful. | ||
618 | */ | ||
636 | bool backtrace_next(BacktraceIterator *state) | 619 | bool backtrace_next(BacktraceIterator *state) |
637 | { | 620 | { |
638 | VirtualAddress next_fp, next_pc; | 621 | unsigned long next_fp, next_pc; |
639 | bt_int_reg_t next_frame[2]; | 622 | bt_int_reg_t next_frame[2]; |
640 | 623 | ||
641 | if (state->fp == -1) { | 624 | if (state->fp == -1) { |