Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arch/tile: refactor backtracing code

This change is the result of some work to make the backtrace code more
shareable between kernel, libc, and gdb.

For the kernel, some good effects are to eliminate the hacky
"VirtualAddress" typedef in favor of "unsigned long", to eliminate a
bunch of spurious kernel doc comments, to remove the dead "bt_read_memory"
function, and to use "__tilegx__" in #ifdefs instead of "TILE_CHIP".

Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>

+93 -131
+23 -59
arch/tile/include/asm/backtrace.h
··· 12 12 * more details. 13 13 */ 14 14 15 - #ifndef _TILE_BACKTRACE_H 16 - #define _TILE_BACKTRACE_H 17 - 18 - 15 + #ifndef _ASM_TILE_BACKTRACE_H 16 + #define _ASM_TILE_BACKTRACE_H 19 17 20 18 #include <linux/types.h> 21 19 22 - #include <arch/chip.h> 23 - 24 - #if defined(__tile__) 25 - typedef unsigned long VirtualAddress; 26 - #elif CHIP_VA_WIDTH() > 32 27 - typedef unsigned long long VirtualAddress; 28 - #else 29 - typedef unsigned int VirtualAddress; 30 - #endif 31 - 32 - 33 - /** Reads 'size' bytes from 'address' and writes the data to 'result'. 20 + /* Reads 'size' bytes from 'address' and writes the data to 'result'. 34 21 * Returns true if successful, else false (e.g. memory not readable). 35 22 */ 36 23 typedef bool (*BacktraceMemoryReader)(void *result, 37 - VirtualAddress address, 24 + unsigned long address, 38 25 unsigned int size, 39 26 void *extra); 40 27 41 28 typedef struct { 42 - /** Current PC. */ 43 - VirtualAddress pc; 29 + /* Current PC. */ 30 + unsigned long pc; 44 31 45 - /** Current stack pointer value. */ 46 - VirtualAddress sp; 32 + /* Current stack pointer value. */ 33 + unsigned long sp; 47 34 48 - /** Current frame pointer value (i.e. caller's stack pointer) */ 49 - VirtualAddress fp; 35 + /* Current frame pointer value (i.e. caller's stack pointer) */ 36 + unsigned long fp; 50 37 51 - /** Internal use only: caller's PC for first frame. */ 52 - VirtualAddress initial_frame_caller_pc; 38 + /* Internal use only: caller's PC for first frame. */ 39 + unsigned long initial_frame_caller_pc; 53 40 54 - /** Internal use only: callback to read memory. */ 41 + /* Internal use only: callback to read memory. */ 55 42 BacktraceMemoryReader read_memory_func; 56 43 57 - /** Internal use only: arbitrary argument to read_memory_func. */ 44 + /* Internal use only: arbitrary argument to read_memory_func. */ 58 45 void *read_memory_func_extra; 59 46 60 47 } BacktraceIterator; 61 - 62 - 63 - /** Initializes a backtracer to start from the given location. 64 - * 65 - * If the frame pointer cannot be determined it is set to -1. 66 - * 67 - * @param state The state to be filled in. 68 - * @param read_memory_func A callback that reads memory. If NULL, a default 69 - * value is provided. 70 - * @param read_memory_func_extra An arbitrary argument to read_memory_func. 71 - * @param pc The current PC. 72 - * @param lr The current value of the 'lr' register. 73 - * @param sp The current value of the 'sp' register. 74 - * @param r52 The current value of the 'r52' register. 75 - */ 76 - extern void backtrace_init(BacktraceIterator *state, 77 - BacktraceMemoryReader read_memory_func, 78 - void *read_memory_func_extra, 79 - VirtualAddress pc, VirtualAddress lr, 80 - VirtualAddress sp, VirtualAddress r52); 81 - 82 - 83 - /** Advances the backtracing state to the calling frame, returning 84 - * true iff successful. 85 - */ 86 - extern bool backtrace_next(BacktraceIterator *state); 87 48 88 49 89 50 typedef enum { ··· 99 138 }; 100 139 101 140 102 - /** Internal constants used to define 'info' operands. */ 141 + /* Internal constants used to define 'info' operands. */ 103 142 enum { 104 143 /* 0 and 1 are reserved, as are all negative numbers. */ 105 144 ··· 108 147 CALLER_SP_IN_R52_BASE = 4, 109 148 110 149 CALLER_SP_OFFSET_BASE = 8, 111 - 112 - /* Marks the entry point of certain functions. */ 113 - ENTRY_POINT_INFO_OP = 16 114 150 }; 115 151 116 152 117 - /** Current backtracer state describing where it thinks the caller is. */ 153 + /* Current backtracer state describing where it thinks the caller is. */ 118 154 typedef struct { 119 155 /* 120 156 * Public fields ··· 150 192 151 193 } CallerLocation; 152 194 195 + extern void backtrace_init(BacktraceIterator *state, 196 + BacktraceMemoryReader read_memory_func, 197 + void *read_memory_func_extra, 198 + unsigned long pc, unsigned long lr, 199 + unsigned long sp, unsigned long r52); 153 200 154 201 202 + extern bool backtrace_next(BacktraceIterator *state); 155 203 156 - #endif /* _TILE_BACKTRACE_H */ 204 + #endif /* _ASM_TILE_BACKTRACE_H */
+7
arch/tile/include/asm/opcode-tile_32.h
··· 1502 1502 decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]); 1503 1503 1504 1504 1505 + /* Given a set of bundle bits and a specific pipe, returns which 1506 + * instruction the bundle contains in that pipe. 1507 + */ 1508 + extern const struct tile_opcode * 1509 + find_opcode(tile_bundle_bits bits, tile_pipeline pipe); 1510 + 1511 + 1505 1512 1506 1513 #endif /* opcode_tile_h */
+7
arch/tile/include/asm/opcode-tile_64.h
··· 1502 1502 decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]); 1503 1503 1504 1504 1505 + /* Given a set of bundle bits and a specific pipe, returns which 1506 + * instruction the bundle contains in that pipe. 1507 + */ 1508 + extern const struct tile_opcode * 1509 + find_opcode(tile_bundle_bits bits, tile_pipeline pipe); 1510 + 1511 + 1505 1512 1506 1513 #endif /* opcode_tile_h */
+43 -60
arch/tile/kernel/backtrace.c
··· 14 14 15 15 #include <linux/kernel.h> 16 16 #include <linux/string.h> 17 - 18 17 #include <asm/backtrace.h> 19 - 20 - #include <arch/chip.h> 21 - 22 18 #include <asm/opcode-tile.h> 19 + #include <arch/abi.h> 23 20 24 - 25 - #define TREG_SP 54 26 - #define TREG_LR 55 27 - 28 - 29 - #if TILE_CHIP >= 10 21 + #ifdef __tilegx__ 30 22 #define tile_bundle_bits tilegx_bundle_bits 31 23 #define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE 32 24 #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES ··· 39 47 typedef int bt_int_reg_t; 40 48 #endif 41 49 42 - /** A decoded bundle used for backtracer analysis. */ 50 + /* A decoded bundle used for backtracer analysis. */ 43 51 struct BacktraceBundle { 44 52 tile_bundle_bits bits; 45 53 int num_insns; ··· 48 56 }; 49 57 50 58 51 - /* This implementation only makes sense for native tools. */ 52 - /** Default function to read memory. */ 53 - static bool bt_read_memory(void *result, VirtualAddress addr, 54 - unsigned int size, void *extra) 55 - { 56 - /* FIXME: this should do some horrible signal stuff to catch 57 - * SEGV cleanly and fail. 58 - * 59 - * Or else the caller should do the setjmp for efficiency. 60 - */ 61 - 62 - memcpy(result, (const void *)addr, size); 63 - return true; 64 - } 65 - 66 - 67 - /** Locates an instruction inside the given bundle that 59 + /* Locates an instruction inside the given bundle that 68 60 * has the specified mnemonic, and whose first 'num_operands_to_match' 69 61 * operands exactly match those in 'operand_values'. 70 62 */ ··· 83 107 return NULL; 84 108 } 85 109 86 - /** Does this bundle contain an 'iret' instruction? */ 110 + /* Does this bundle contain an 'iret' instruction? */ 87 111 static inline bool bt_has_iret(const struct BacktraceBundle *bundle) 88 112 { 89 113 return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL; 90 114 } 91 115 92 - /** Does this bundle contain an 'addi sp, sp, OFFSET' or 116 + /* Does this bundle contain an 'addi sp, sp, OFFSET' or 93 117 * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET? 94 118 */ 95 119 static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust) ··· 100 124 find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2); 101 125 if (insn == NULL) 102 126 insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2); 103 - #if TILE_CHIP >= 10 127 + #ifdef __tilegx__ 104 128 if (insn == NULL) 105 129 insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2); 106 130 if (insn == NULL) ··· 113 137 return true; 114 138 } 115 139 116 - /** Does this bundle contain any 'info OP' or 'infol OP' 140 + /* Does this bundle contain any 'info OP' or 'infol OP' 117 141 * instruction, and if so, what are their OP? Note that OP is interpreted 118 142 * as an unsigned value by this code since that's what the caller wants. 119 143 * Returns the number of info ops found. ··· 137 161 return num_ops; 138 162 } 139 163 140 - /** Does this bundle contain a jrp instruction, and if so, to which 164 + /* Does this bundle contain a jrp instruction, and if so, to which 141 165 * register is it jumping? 142 166 */ 143 167 static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg) ··· 151 175 return true; 152 176 } 153 177 154 - /** Does this bundle modify the specified register in any way? */ 178 + /* Does this bundle modify the specified register in any way? */ 155 179 static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg) 156 180 { 157 181 int i, j; ··· 171 195 return false; 172 196 } 173 197 174 - /** Does this bundle modify sp? */ 198 + /* Does this bundle modify sp? */ 175 199 static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle) 176 200 { 177 201 return bt_modifies_reg(bundle, TREG_SP); 178 202 } 179 203 180 - /** Does this bundle modify lr? */ 204 + /* Does this bundle modify lr? */ 181 205 static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle) 182 206 { 183 207 return bt_modifies_reg(bundle, TREG_LR); 184 208 } 185 209 186 - /** Does this bundle contain the instruction 'move fp, sp'? */ 210 + /* Does this bundle contain the instruction 'move fp, sp'? */ 187 211 static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle) 188 212 { 189 213 static const int vals[2] = { 52, TREG_SP }; 190 214 return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL; 191 215 } 192 216 193 - /** Does this bundle contain a store of lr to sp? */ 217 + /* Does this bundle contain a store of lr to sp? */ 194 218 static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle) 195 219 { 196 220 static const int vals[2] = { TREG_SP, TREG_LR }; 197 221 return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL; 198 222 } 199 223 200 - #if TILE_CHIP >= 10 201 - /** Track moveli values placed into registers. */ 224 + #ifdef __tilegx__ 225 + /* Track moveli values placed into registers. */ 202 226 static inline void bt_update_moveli(const struct BacktraceBundle *bundle, 203 227 int moveli_args[]) 204 228 { ··· 214 238 } 215 239 } 216 240 217 - /** Does this bundle contain an 'add sp, sp, reg' instruction 241 + /* Does this bundle contain an 'add sp, sp, reg' instruction 218 242 * from a register that we saw a moveli into, and if so, what 219 243 * is the value in the register? 220 244 */ ··· 236 260 } 237 261 #endif 238 262 239 - /** 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 240 264 * given address. 241 265 */ 242 266 static void find_caller_pc_and_caller_sp(CallerLocation *location, 243 - const VirtualAddress start_pc, 267 + const unsigned long start_pc, 244 268 BacktraceMemoryReader read_memory_func, 245 269 void *read_memory_func_extra) 246 270 { ··· 264 288 tile_bundle_bits prefetched_bundles[32]; 265 289 int num_bundles_prefetched = 0; 266 290 int next_bundle = 0; 267 - VirtualAddress pc; 291 + unsigned long pc; 268 292 269 - #if TILE_CHIP >= 10 293 + #ifdef __tilegx__ 270 294 /* Naively try to track moveli values to support addx for -m32. */ 271 295 int moveli_args[TILEGX_NUM_REGISTERS] = { 0 }; 272 296 #endif ··· 343 367 int info_operand = info_operands[i]; 344 368 if (info_operand < CALLER_UNKNOWN_BASE) { 345 369 /* Weird; reserved value, ignore it. */ 346 - continue; 347 - } 348 - if (info_operand & ENTRY_POINT_INFO_OP) { 349 - /* This info op is ignored by the backtracer. */ 350 370 continue; 351 371 } 352 372 ··· 425 453 if (!sp_determined) { 426 454 int adjust; 427 455 if (bt_has_addi_sp(&bundle, &adjust) 428 - #if TILE_CHIP >= 10 456 + #ifdef __tilegx__ 429 457 || bt_has_add_sp(&bundle, &adjust, moveli_args) 430 458 #endif 431 459 ) { ··· 476 504 } 477 505 } 478 506 479 - #if TILE_CHIP >= 10 507 + #ifdef __tilegx__ 480 508 /* Track moveli arguments for -m32 mode. */ 481 509 bt_update_moveli(&bundle, moveli_args); 482 510 #endif ··· 518 546 } 519 547 } 520 548 549 + /* Initializes a backtracer to start from the given location. 550 + * 551 + * If the frame pointer cannot be determined it is set to -1. 552 + * 553 + * state: The state to be filled in. 554 + * read_memory_func: A callback that reads memory. 555 + * read_memory_func_extra: An arbitrary argument to read_memory_func. 556 + * pc: The current PC. 557 + * lr: The current value of the 'lr' register. 558 + * sp: The current value of the 'sp' register. 559 + * r52: The current value of the 'r52' register. 560 + */ 521 561 void backtrace_init(BacktraceIterator *state, 522 562 BacktraceMemoryReader read_memory_func, 523 563 void *read_memory_func_extra, 524 - VirtualAddress pc, VirtualAddress lr, 525 - VirtualAddress sp, VirtualAddress r52) 564 + unsigned long pc, unsigned long lr, 565 + unsigned long sp, unsigned long r52) 526 566 { 527 567 CallerLocation location; 528 - VirtualAddress fp, initial_frame_caller_pc; 529 - 530 - if (read_memory_func == NULL) { 531 - read_memory_func = bt_read_memory; 532 - } 568 + unsigned long fp, initial_frame_caller_pc; 533 569 534 570 /* Find out where we are in the initial frame. */ 535 571 find_caller_pc_and_caller_sp(&location, pc, ··· 610 630 /* Handle the case where the register holds more bits than the VA. */ 611 631 static bool valid_addr_reg(bt_int_reg_t reg) 612 632 { 613 - return ((VirtualAddress)reg == reg); 633 + return ((unsigned long)reg == reg); 614 634 } 615 635 636 + /* Advances the backtracing state to the calling frame, returning 637 + * true iff successful. 638 + */ 616 639 bool backtrace_next(BacktraceIterator *state) 617 640 { 618 - VirtualAddress next_fp, next_pc; 641 + unsigned long next_fp, next_pc; 619 642 bt_int_reg_t next_frame[2]; 620 643 621 644 if (state->fp == -1) {
+7 -7
arch/tile/kernel/stack.c
··· 36 36 #define KBT_LOOP 3 /* Backtrace entered a loop */ 37 37 38 38 /* Is address on the specified kernel stack? */ 39 - static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp) 39 + static int in_kernel_stack(struct KBacktraceIterator *kbt, unsigned long sp) 40 40 { 41 41 ulong kstack_base = (ulong) kbt->task->stack; 42 42 if (kstack_base == 0) /* corrupt task pointer; just follow stack... */ ··· 45 45 } 46 46 47 47 /* Is address valid for reading? */ 48 - static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address) 48 + static int valid_address(struct KBacktraceIterator *kbt, unsigned long address) 49 49 { 50 50 HV_PTE *l1_pgtable = kbt->pgtable; 51 51 HV_PTE *l2_pgtable; ··· 97 97 } 98 98 99 99 /* Callback for backtracer; basically a glorified memcpy */ 100 - static bool read_memory_func(void *result, VirtualAddress address, 100 + static bool read_memory_func(void *result, unsigned long address, 101 101 unsigned int size, void *vkbt) 102 102 { 103 103 int retval; ··· 124 124 { 125 125 const char *fault = NULL; /* happy compiler */ 126 126 char fault_buf[64]; 127 - VirtualAddress sp = kbt->it.sp; 127 + unsigned long sp = kbt->it.sp; 128 128 struct pt_regs *p; 129 129 130 130 if (!in_kernel_stack(kbt, sp)) ··· 163 163 } 164 164 165 165 /* Is the pc pointing to a sigreturn trampoline? */ 166 - static int is_sigreturn(VirtualAddress pc) 166 + static int is_sigreturn(unsigned long pc) 167 167 { 168 168 return (pc == VDSO_BASE); 169 169 } ··· 260 260 void KBacktraceIterator_init(struct KBacktraceIterator *kbt, 261 261 struct task_struct *t, struct pt_regs *regs) 262 262 { 263 - VirtualAddress pc, lr, sp, r52; 263 + unsigned long pc, lr, sp, r52; 264 264 int is_current; 265 265 266 266 /* ··· 331 331 332 332 void KBacktraceIterator_next(struct KBacktraceIterator *kbt) 333 333 { 334 - VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp; 334 + unsigned long old_pc = kbt->it.pc, old_sp = kbt->it.sp; 335 335 kbt->new_context = 0; 336 336 if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) { 337 337 kbt->end = KBT_DONE;
+6 -5
arch/tile/kernel/tile-desc_32.c
··· 2413 2413 2414 2414 2415 2415 2416 - /* Given a set of bundle bits and the lookup FSM for a specific pipe, 2417 - * returns which instruction the bundle contains in that pipe. 2416 + /* Given a set of bundle bits and a specific pipe, returns which 2417 + * instruction the bundle contains in that pipe. 2418 2418 */ 2419 - static const struct tile_opcode * 2420 - find_opcode(tile_bundle_bits bits, const unsigned short *table) 2419 + const struct tile_opcode * 2420 + find_opcode(tile_bundle_bits bits, tile_pipeline pipe) 2421 2421 { 2422 + const unsigned short *table = tile_bundle_decoder_fsms[pipe]; 2422 2423 int index = 0; 2423 2424 2424 2425 while (1) ··· 2466 2465 int i; 2467 2466 2468 2467 d = &decoded[num_instructions++]; 2469 - opc = find_opcode (bits, tile_bundle_decoder_fsms[pipe]); 2468 + opc = find_opcode (bits, (tile_pipeline)pipe); 2470 2469 d->opcode = opc; 2471 2470 2472 2471 /* Decode each operand, sign extending, etc. as appropriate. */