decode-insn.c (cc9b94029e9ef51787af908e9856b1eed314bc00) | decode-insn.c (c2249707ee53b5dd696f0fae8543a754684ea04a) |
---|---|
1/* 2 * arch/arm64/kernel/probes/decode-insn.c 3 * 4 * Copyright (C) 2013 Linaro Limited. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. --- 64 unchanged lines hidden (view full) --- 73 return true; 74} 75 76/* Return: 77 * INSN_REJECTED If instruction is one not allowed to kprobe, 78 * INSN_GOOD If instruction is supported and uses instruction slot, 79 * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. 80 */ | 1/* 2 * arch/arm64/kernel/probes/decode-insn.c 3 * 4 * Copyright (C) 2013 Linaro Limited. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. --- 64 unchanged lines hidden (view full) --- 73 return true; 74} 75 76/* Return: 77 * INSN_REJECTED If instruction is one not allowed to kprobe, 78 * INSN_GOOD If instruction is supported and uses instruction slot, 79 * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. 80 */ |
81static enum kprobe_insn __kprobes 82arm_probe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 81enum probe_insn __kprobes 82arm_probe_decode_insn(probe_opcode_t insn, struct arch_probe_insn *api) |
83{ 84 /* 85 * Instructions reading or modifying the PC won't work from the XOL 86 * slot. 87 */ 88 if (aarch64_insn_is_steppable(insn)) 89 return INSN_GOOD; 90 91 if (aarch64_insn_is_bcond(insn)) { | 83{ 84 /* 85 * Instructions reading or modifying the PC won't work from the XOL 86 * slot. 87 */ 88 if (aarch64_insn_is_steppable(insn)) 89 return INSN_GOOD; 90 91 if (aarch64_insn_is_bcond(insn)) { |
92 asi->handler = simulate_b_cond; | 92 api->handler = simulate_b_cond; |
93 } else if (aarch64_insn_is_cbz(insn) || 94 aarch64_insn_is_cbnz(insn)) { | 93 } else if (aarch64_insn_is_cbz(insn) || 94 aarch64_insn_is_cbnz(insn)) { |
95 asi->handler = simulate_cbz_cbnz; | 95 api->handler = simulate_cbz_cbnz; |
96 } else if (aarch64_insn_is_tbz(insn) || 97 aarch64_insn_is_tbnz(insn)) { | 96 } else if (aarch64_insn_is_tbz(insn) || 97 aarch64_insn_is_tbnz(insn)) { |
98 asi->handler = simulate_tbz_tbnz; | 98 api->handler = simulate_tbz_tbnz; |
99 } else if (aarch64_insn_is_adr_adrp(insn)) { | 99 } else if (aarch64_insn_is_adr_adrp(insn)) { |
100 asi->handler = simulate_adr_adrp; | 100 api->handler = simulate_adr_adrp; |
101 } else if (aarch64_insn_is_b(insn) || 102 aarch64_insn_is_bl(insn)) { | 101 } else if (aarch64_insn_is_b(insn) || 102 aarch64_insn_is_bl(insn)) { |
103 asi->handler = simulate_b_bl; | 103 api->handler = simulate_b_bl; |
104 } else if (aarch64_insn_is_br(insn) || 105 aarch64_insn_is_blr(insn) || 106 aarch64_insn_is_ret(insn)) { | 104 } else if (aarch64_insn_is_br(insn) || 105 aarch64_insn_is_blr(insn) || 106 aarch64_insn_is_ret(insn)) { |
107 asi->handler = simulate_br_blr_ret; | 107 api->handler = simulate_br_blr_ret; |
108 } else if (aarch64_insn_is_ldr_lit(insn)) { | 108 } else if (aarch64_insn_is_ldr_lit(insn)) { |
109 asi->handler = simulate_ldr_literal; | 109 api->handler = simulate_ldr_literal; |
110 } else if (aarch64_insn_is_ldrsw_lit(insn)) { | 110 } else if (aarch64_insn_is_ldrsw_lit(insn)) { |
111 asi->handler = simulate_ldrsw_literal; | 111 api->handler = simulate_ldrsw_literal; |
112 } else { 113 /* 114 * Instruction cannot be stepped out-of-line and we don't 115 * (yet) simulate it. 116 */ 117 return INSN_REJECTED; 118 } 119 120 return INSN_GOOD_NO_SLOT; 121} 122 | 112 } else { 113 /* 114 * Instruction cannot be stepped out-of-line and we don't 115 * (yet) simulate it. 116 */ 117 return INSN_REJECTED; 118 } 119 120 return INSN_GOOD_NO_SLOT; 121} 122 |
123#ifdef CONFIG_KPROBES |
|
123static bool __kprobes 124is_probed_address_atomic(kprobe_opcode_t *scan_start, kprobe_opcode_t *scan_end) 125{ 126 while (scan_start >= scan_end) { 127 /* 128 * atomic region starts from exclusive load and ends with 129 * exclusive store. 130 */ 131 if (aarch64_insn_is_store_ex(le32_to_cpu(*scan_start))) 132 return false; 133 else if (aarch64_insn_is_load_ex(le32_to_cpu(*scan_start))) 134 return true; 135 scan_start--; 136 } 137 138 return false; 139} 140 | 124static bool __kprobes 125is_probed_address_atomic(kprobe_opcode_t *scan_start, kprobe_opcode_t *scan_end) 126{ 127 while (scan_start >= scan_end) { 128 /* 129 * atomic region starts from exclusive load and ends with 130 * exclusive store. 131 */ 132 if (aarch64_insn_is_store_ex(le32_to_cpu(*scan_start))) 133 return false; 134 else if (aarch64_insn_is_load_ex(le32_to_cpu(*scan_start))) 135 return true; 136 scan_start--; 137 } 138 139 return false; 140} 141 |
141enum kprobe_insn __kprobes | 142enum probe_insn __kprobes |
142arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi) 143{ | 143arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi) 144{ |
144 enum kprobe_insn decoded; 145 kprobe_opcode_t insn = le32_to_cpu(*addr); 146 kprobe_opcode_t *scan_end = NULL; | 145 enum probe_insn decoded; 146 probe_opcode_t insn = le32_to_cpu(*addr); 147 probe_opcode_t *scan_end = NULL; |
147 unsigned long size = 0, offset = 0; 148 149 /* 150 * If there's a symbol defined in front of and near enough to 151 * the probe address assume it is the entry point to this 152 * code and use it to further limit how far back we search 153 * when determining if we're in an atomic sequence. If we could 154 * not find any symbol skip the atomic test altogether as we 155 * could otherwise end up searching irrelevant text/literals. 156 * KPROBES depends on KALLSYMS so this last case should never 157 * happen. 158 */ 159 if (kallsyms_lookup_size_offset((unsigned long) addr, &size, &offset)) { 160 if (offset < (MAX_ATOMIC_CONTEXT_SIZE*sizeof(kprobe_opcode_t))) 161 scan_end = addr - (offset / sizeof(kprobe_opcode_t)); 162 else 163 scan_end = addr - MAX_ATOMIC_CONTEXT_SIZE; 164 } | 148 unsigned long size = 0, offset = 0; 149 150 /* 151 * If there's a symbol defined in front of and near enough to 152 * the probe address assume it is the entry point to this 153 * code and use it to further limit how far back we search 154 * when determining if we're in an atomic sequence. If we could 155 * not find any symbol skip the atomic test altogether as we 156 * could otherwise end up searching irrelevant text/literals. 157 * KPROBES depends on KALLSYMS so this last case should never 158 * happen. 159 */ 160 if (kallsyms_lookup_size_offset((unsigned long) addr, &size, &offset)) { 161 if (offset < (MAX_ATOMIC_CONTEXT_SIZE*sizeof(kprobe_opcode_t))) 162 scan_end = addr - (offset / sizeof(kprobe_opcode_t)); 163 else 164 scan_end = addr - MAX_ATOMIC_CONTEXT_SIZE; 165 } |
165 decoded = arm_probe_decode_insn(insn, asi); | 166 decoded = arm_probe_decode_insn(insn, &asi->api); |
166 167 if (decoded != INSN_REJECTED && scan_end) 168 if (is_probed_address_atomic(addr - 1, scan_end)) 169 return INSN_REJECTED; 170 171 return decoded; 172} | 167 168 if (decoded != INSN_REJECTED && scan_end) 169 if (is_probed_address_atomic(addr - 1, scan_end)) 170 return INSN_REJECTED; 171 172 return decoded; 173} |
174#endif |
|