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 55a6a74974b..1dc71eabfc5 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) { |
