diff options
Diffstat (limited to 'arch/tile/kernel/backtrace.c')
-rw-r--r-- | arch/tile/kernel/backtrace.c | 81 |
1 files changed, 34 insertions, 47 deletions
diff --git a/arch/tile/kernel/backtrace.c b/arch/tile/kernel/backtrace.c index 1b0a410ef5e7..77265f3b58d6 100644 --- a/arch/tile/kernel/backtrace.c +++ b/arch/tile/kernel/backtrace.c | |||
@@ -30,18 +30,18 @@ | |||
30 | 30 | ||
31 | 31 | ||
32 | /** A decoded bundle used for backtracer analysis. */ | 32 | /** A decoded bundle used for backtracer analysis. */ |
33 | typedef struct { | 33 | struct BacktraceBundle { |
34 | tile_bundle_bits bits; | 34 | tile_bundle_bits bits; |
35 | int num_insns; | 35 | int num_insns; |
36 | struct tile_decoded_instruction | 36 | struct tile_decoded_instruction |
37 | insns[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]; | 37 | insns[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]; |
38 | } BacktraceBundle; | 38 | }; |
39 | 39 | ||
40 | 40 | ||
41 | /* This implementation only makes sense for native tools. */ | 41 | /* This implementation only makes sense for native tools. */ |
42 | /** Default function to read memory. */ | 42 | /** Default function to read memory. */ |
43 | static bool | 43 | static bool bt_read_memory(void *result, VirtualAddress addr, |
44 | bt_read_memory(void *result, VirtualAddress addr, size_t size, void *extra) | 44 | size_t size, void *extra) |
45 | { | 45 | { |
46 | /* FIXME: this should do some horrible signal stuff to catch | 46 | /* FIXME: this should do some horrible signal stuff to catch |
47 | * SEGV cleanly and fail. | 47 | * SEGV cleanly and fail. |
@@ -58,11 +58,11 @@ bt_read_memory(void *result, VirtualAddress addr, size_t size, void *extra) | |||
58 | * has the specified mnemonic, and whose first 'num_operands_to_match' | 58 | * has the specified mnemonic, and whose first 'num_operands_to_match' |
59 | * operands exactly match those in 'operand_values'. | 59 | * operands exactly match those in 'operand_values'. |
60 | */ | 60 | */ |
61 | static const struct tile_decoded_instruction* | 61 | static const struct tile_decoded_instruction *find_matching_insn( |
62 | find_matching_insn(const BacktraceBundle *bundle, | 62 | const struct BacktraceBundle *bundle, |
63 | tile_mnemonic mnemonic, | 63 | tile_mnemonic mnemonic, |
64 | const int *operand_values, | 64 | const int *operand_values, |
65 | int num_operands_to_match) | 65 | int num_operands_to_match) |
66 | { | 66 | { |
67 | int i, j; | 67 | int i, j; |
68 | bool match; | 68 | bool match; |
@@ -90,8 +90,7 @@ find_matching_insn(const BacktraceBundle *bundle, | |||
90 | } | 90 | } |
91 | 91 | ||
92 | /** Does this bundle contain an 'iret' instruction? */ | 92 | /** Does this bundle contain an 'iret' instruction? */ |
93 | static inline bool | 93 | static inline bool bt_has_iret(const struct BacktraceBundle *bundle) |
94 | bt_has_iret(const BacktraceBundle *bundle) | ||
95 | { | 94 | { |
96 | return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL; | 95 | return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL; |
97 | } | 96 | } |
@@ -99,8 +98,7 @@ bt_has_iret(const BacktraceBundle *bundle) | |||
99 | /** Does this bundle contain an 'addi sp, sp, OFFSET' or | 98 | /** Does this bundle contain an 'addi sp, sp, OFFSET' or |
100 | * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET? | 99 | * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET? |
101 | */ | 100 | */ |
102 | static bool | 101 | static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust) |
103 | bt_has_addi_sp(const BacktraceBundle *bundle, int *adjust) | ||
104 | { | 102 | { |
105 | static const int vals[2] = { TREG_SP, TREG_SP }; | 103 | static const int vals[2] = { TREG_SP, TREG_SP }; |
106 | 104 | ||
@@ -120,8 +118,7 @@ bt_has_addi_sp(const BacktraceBundle *bundle, int *adjust) | |||
120 | * 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. |
121 | * Returns the number of info ops found. | 119 | * Returns the number of info ops found. |
122 | */ | 120 | */ |
123 | static int | 121 | static int bt_get_info_ops(const struct BacktraceBundle *bundle, |
124 | bt_get_info_ops(const BacktraceBundle *bundle, | ||
125 | int operands[MAX_INFO_OPS_PER_BUNDLE]) | 122 | int operands[MAX_INFO_OPS_PER_BUNDLE]) |
126 | { | 123 | { |
127 | int num_ops = 0; | 124 | int num_ops = 0; |
@@ -143,8 +140,7 @@ bt_get_info_ops(const BacktraceBundle *bundle, | |||
143 | /** 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 |
144 | * register is it jumping? | 141 | * register is it jumping? |
145 | */ | 142 | */ |
146 | static bool | 143 | static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg) |
147 | bt_has_jrp(const BacktraceBundle *bundle, int *target_reg) | ||
148 | { | 144 | { |
149 | const struct tile_decoded_instruction *insn = | 145 | const struct tile_decoded_instruction *insn = |
150 | find_matching_insn(bundle, TILE_OPC_JRP, NULL, 0); | 146 | find_matching_insn(bundle, TILE_OPC_JRP, NULL, 0); |
@@ -156,8 +152,7 @@ bt_has_jrp(const BacktraceBundle *bundle, int *target_reg) | |||
156 | } | 152 | } |
157 | 153 | ||
158 | /** Does this bundle modify the specified register in any way? */ | 154 | /** Does this bundle modify the specified register in any way? */ |
159 | static bool | 155 | static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg) |
160 | bt_modifies_reg(const BacktraceBundle *bundle, int reg) | ||
161 | { | 156 | { |
162 | int i, j; | 157 | int i, j; |
163 | for (i = 0; i < bundle->num_insns; i++) { | 158 | for (i = 0; i < bundle->num_insns; i++) { |
@@ -177,30 +172,26 @@ bt_modifies_reg(const BacktraceBundle *bundle, int reg) | |||
177 | } | 172 | } |
178 | 173 | ||
179 | /** Does this bundle modify sp? */ | 174 | /** Does this bundle modify sp? */ |
180 | static inline bool | 175 | static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle) |
181 | bt_modifies_sp(const BacktraceBundle *bundle) | ||
182 | { | 176 | { |
183 | return bt_modifies_reg(bundle, TREG_SP); | 177 | return bt_modifies_reg(bundle, TREG_SP); |
184 | } | 178 | } |
185 | 179 | ||
186 | /** Does this bundle modify lr? */ | 180 | /** Does this bundle modify lr? */ |
187 | static inline bool | 181 | static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle) |
188 | bt_modifies_lr(const BacktraceBundle *bundle) | ||
189 | { | 182 | { |
190 | return bt_modifies_reg(bundle, TREG_LR); | 183 | return bt_modifies_reg(bundle, TREG_LR); |
191 | } | 184 | } |
192 | 185 | ||
193 | /** Does this bundle contain the instruction 'move fp, sp'? */ | 186 | /** Does this bundle contain the instruction 'move fp, sp'? */ |
194 | static inline bool | 187 | static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle) |
195 | bt_has_move_r52_sp(const BacktraceBundle *bundle) | ||
196 | { | 188 | { |
197 | static const int vals[2] = { 52, TREG_SP }; | 189 | static const int vals[2] = { 52, TREG_SP }; |
198 | return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL; | 190 | return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL; |
199 | } | 191 | } |
200 | 192 | ||
201 | /** Does this bundle contain the instruction 'sw sp, lr'? */ | 193 | /** Does this bundle contain the instruction 'sw sp, lr'? */ |
202 | static inline bool | 194 | static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle) |
203 | bt_has_sw_sp_lr(const BacktraceBundle *bundle) | ||
204 | { | 195 | { |
205 | static const int vals[2] = { TREG_SP, TREG_LR }; | 196 | static const int vals[2] = { TREG_SP, TREG_LR }; |
206 | return find_matching_insn(bundle, TILE_OPC_SW, vals, 2) != NULL; | 197 | return find_matching_insn(bundle, TILE_OPC_SW, vals, 2) != NULL; |
@@ -209,11 +200,10 @@ bt_has_sw_sp_lr(const BacktraceBundle *bundle) | |||
209 | /** Locates the caller's PC and SP for a program starting at the | 200 | /** Locates the caller's PC and SP for a program starting at the |
210 | * given address. | 201 | * given address. |
211 | */ | 202 | */ |
212 | static void | 203 | static void find_caller_pc_and_caller_sp(CallerLocation *location, |
213 | find_caller_pc_and_caller_sp(CallerLocation *location, | 204 | const VirtualAddress start_pc, |
214 | const VirtualAddress start_pc, | 205 | BacktraceMemoryReader read_memory_func, |
215 | BacktraceMemoryReader read_memory_func, | 206 | void *read_memory_func_extra) |
216 | void *read_memory_func_extra) | ||
217 | { | 207 | { |
218 | /* Have we explicitly decided what the sp is, | 208 | /* Have we explicitly decided what the sp is, |
219 | * rather than just the default? | 209 | * rather than just the default? |
@@ -253,7 +243,7 @@ find_caller_pc_and_caller_sp(CallerLocation *location, | |||
253 | 243 | ||
254 | for (pc = start_pc;; pc += sizeof(tile_bundle_bits)) { | 244 | for (pc = start_pc;; pc += sizeof(tile_bundle_bits)) { |
255 | 245 | ||
256 | BacktraceBundle bundle; | 246 | struct BacktraceBundle bundle; |
257 | int num_info_ops, info_operands[MAX_INFO_OPS_PER_BUNDLE]; | 247 | int num_info_ops, info_operands[MAX_INFO_OPS_PER_BUNDLE]; |
258 | int one_ago, jrp_reg; | 248 | int one_ago, jrp_reg; |
259 | bool has_jrp; | 249 | bool has_jrp; |
@@ -475,12 +465,11 @@ find_caller_pc_and_caller_sp(CallerLocation *location, | |||
475 | } | 465 | } |
476 | } | 466 | } |
477 | 467 | ||
478 | void | 468 | void backtrace_init(BacktraceIterator *state, |
479 | backtrace_init(BacktraceIterator *state, | 469 | BacktraceMemoryReader read_memory_func, |
480 | BacktraceMemoryReader read_memory_func, | 470 | void *read_memory_func_extra, |
481 | void *read_memory_func_extra, | 471 | VirtualAddress pc, VirtualAddress lr, |
482 | VirtualAddress pc, VirtualAddress lr, | 472 | VirtualAddress sp, VirtualAddress r52) |
483 | VirtualAddress sp, VirtualAddress r52) | ||
484 | { | 473 | { |
485 | CallerLocation location; | 474 | CallerLocation location; |
486 | VirtualAddress fp, initial_frame_caller_pc; | 475 | VirtualAddress fp, initial_frame_caller_pc; |
@@ -558,8 +547,7 @@ backtrace_init(BacktraceIterator *state, | |||
558 | state->read_memory_func_extra = read_memory_func_extra; | 547 | state->read_memory_func_extra = read_memory_func_extra; |
559 | } | 548 | } |
560 | 549 | ||
561 | bool | 550 | bool backtrace_next(BacktraceIterator *state) |
562 | backtrace_next(BacktraceIterator *state) | ||
563 | { | 551 | { |
564 | VirtualAddress next_fp, next_pc, next_frame[2]; | 552 | VirtualAddress next_fp, next_pc, next_frame[2]; |
565 | 553 | ||
@@ -614,12 +602,11 @@ backtrace_next(BacktraceIterator *state) | |||
614 | 602 | ||
615 | #else /* TILE_CHIP < 10 */ | 603 | #else /* TILE_CHIP < 10 */ |
616 | 604 | ||
617 | void | 605 | void backtrace_init(BacktraceIterator *state, |
618 | backtrace_init(BacktraceIterator *state, | 606 | BacktraceMemoryReader read_memory_func, |
619 | BacktraceMemoryReader read_memory_func, | 607 | void *read_memory_func_extra, |
620 | void *read_memory_func_extra, | 608 | VirtualAddress pc, VirtualAddress lr, |
621 | VirtualAddress pc, VirtualAddress lr, | 609 | VirtualAddress sp, VirtualAddress r52) |
622 | VirtualAddress sp, VirtualAddress r52) | ||
623 | { | 610 | { |
624 | state->pc = pc; | 611 | state->pc = pc; |
625 | state->sp = sp; | 612 | state->sp = sp; |