step.c (9042B)
1 /* Resume-mode state machine. 2 * 3 * STEP_INSN uses the displaced-step primitive directly via pending_pc_override 4 * and the outer session_resume's signal/wait. STEP_LINE / NEXT_LINE / STEP_OUT 5 * drive their own signal/wait cycles in-loop and set pending_done so the outer 6 * resume short-circuits. */ 7 8 #include <string.h> 9 10 #include "core/slice.h" 11 #include "dbg/dbg.h" 12 13 #define DBG_STEP_LINE_INSN_CAP 1024u 14 15 static KitStatus run_step_line_loop(KitJitSession* s); 16 17 /* DWARF line/CFI tables are authored in image-relative vaddrs (kit's 18 * debug emitter writes them, the JIT view applies relocs against final 19 * image vaddrs). Stop PCs and the values dropped onto the stack by 20 * BL/RET, on the other hand, live in runtime address space. Every 21 * DWARF call from the session translates at the boundary. */ 22 static uint64_t step_rt_to_img(KitJitSession* s, uint64_t pc) { 23 uint64_t v = kit_jit_runtime_to_image(s->jit, pc); 24 return v ? v : pc; 25 } 26 27 static KitStatus prepare_step_insn(KitJitSession* s) { 28 uint64_t pc = s->stop.regs.pc; 29 uint64_t scratch_entry = 0; 30 KitStatus st = dbg_displaced_prepare(s, pc, &scratch_entry); 31 if (st != KIT_OK) return st; 32 s->pending_has_pc = 1; 33 s->pending_pc_override = scratch_entry; 34 return KIT_OK; 35 } 36 37 /* Drive a single displaced-step cycle synchronously. Returns KIT_OK on 38 * success; the session is parked again at the post-step PC. */ 39 static KitStatus do_one_displaced(KitJitSession* s) { 40 KitStatus st = prepare_step_insn(s); 41 if (st != KIT_OK) return st; 42 st = dbg_session_signal_resume(s); 43 if (st != KIT_OK) return st; 44 return dbg_session_wait_stop(s); 45 } 46 47 static int stop_is_internal_completion(const KitJitSession* s) { 48 return s->stop.kind == KIT_STOP_BREAKPOINT && s->stop.bp_id == 0; 49 } 50 51 static KitStatus direct_call_target(KitJitSession* s, uint64_t* target) { 52 ArchDbgInsn insn; 53 if (!s->arch_dbg || !s->arch_dbg->direct_call_target) return KIT_NOT_FOUND; 54 if (dbg_arch_decode_insn(s, s->stop.regs.pc, &insn) != KIT_OK) 55 return KIT_NOT_FOUND; 56 return s->arch_dbg->direct_call_target(&insn, target); 57 } 58 59 static KitStatus direct_jump_target(KitJitSession* s, uint64_t* target) { 60 ArchDbgInsn insn; 61 if (!s->arch_dbg || !s->arch_dbg->direct_jump_target) return KIT_NOT_FOUND; 62 if (dbg_arch_decode_insn(s, s->stop.regs.pc, &insn) != KIT_OK) 63 return KIT_NOT_FOUND; 64 return s->arch_dbg->direct_jump_target(&insn, target); 65 } 66 67 static KitStatus dwarf_line_for(KitJitSession* s, uint64_t pc, KitSlice* file, 68 uint32_t* line) { 69 uint32_t col = 0; 70 *file = KIT_SLICE_NULL; 71 *line = 0; 72 return kit_dwarf_addr_to_line(s->dwarf, step_rt_to_img(s, pc), file, line, 73 &col); 74 } 75 76 static KitStatus dwarf_sub_for(KitJitSession* s, uint64_t pc, 77 KitDwarfSubprogram* out) { 78 memset(out, 0, sizeof(*out)); 79 return kit_dwarf_subprogram_at(s->dwarf, step_rt_to_img(s, pc), out); 80 } 81 82 static int line_changed(KitSlice base_file, uint32_t base_line, 83 KitSlice new_file, uint32_t new_line) { 84 if (new_line == 0) return 0; 85 if (base_line == 0) return 1; 86 if (new_line != base_line) return 1; 87 if (base_file.s != new_file.s) { 88 if (!base_file.s || !new_file.s) return 1; 89 if (!slice_eq(base_file, new_file)) return 1; 90 } 91 return 0; 92 } 93 94 static KitStatus try_step_into_direct_call(KitJitSession* s, int* did) { 95 uint64_t target = 0; 96 u32 bp_id = 0; 97 KitStatus st; 98 *did = 0; 99 st = direct_call_target(s, &target); 100 if (st == KIT_NOT_FOUND || st == KIT_UNSUPPORTED) return KIT_OK; 101 if (st != KIT_OK) return st; 102 st = dbg_bp_set_internal(s, target, &bp_id); 103 if (st != KIT_OK) return st; 104 *did = 1; 105 st = dbg_session_signal_resume(s); 106 if (st != KIT_OK) return st; 107 st = dbg_session_wait_stop(s); 108 if (st != KIT_OK) return st; 109 if (stop_is_internal_completion(s)) { 110 return run_step_line_loop(s); 111 } 112 return KIT_OK; 113 } 114 115 static KitStatus try_follow_direct_jump(KitJitSession* s, int* did) { 116 uint64_t target = 0; 117 u32 bp_id = 0; 118 KitStatus st; 119 *did = 0; 120 st = direct_jump_target(s, &target); 121 if (st == KIT_NOT_FOUND || st == KIT_UNSUPPORTED) return KIT_OK; 122 if (st != KIT_OK) return st; 123 st = dbg_bp_set_internal(s, target, &bp_id); 124 if (st != KIT_OK) return st; 125 *did = 1; 126 st = dbg_session_signal_resume(s); 127 if (st != KIT_OK) return st; 128 return dbg_session_wait_stop(s); 129 } 130 131 static KitStatus run_step_line_loop(KitJitSession* s) { 132 KitSlice base_file = KIT_SLICE_NULL; 133 uint32_t base_line = 0; 134 KitDwarfSubprogram base_sub; 135 int have_sub; 136 u32 i; 137 138 (void)dwarf_line_for(s, s->stop.regs.pc, &base_file, &base_line); 139 have_sub = (dwarf_sub_for(s, s->stop.regs.pc, &base_sub) == KIT_OK); 140 141 for (i = 0; i < DBG_STEP_LINE_INSN_CAP; ++i) { 142 KitSlice new_file = KIT_SLICE_NULL; 143 uint32_t new_line = 0; 144 KitDwarfSubprogram new_sub; 145 int have_new_sub; 146 int did_call = 0; 147 int did_jump = 0; 148 KitStatus st; 149 150 st = try_step_into_direct_call(s, &did_call); 151 if (st != KIT_OK) return st; 152 if (did_call) return KIT_OK; 153 154 st = try_follow_direct_jump(s, &did_jump); 155 if (st != KIT_OK) return st; 156 157 if (!did_jump && do_one_displaced(s) != KIT_OK) { 158 /* Lifter declined; surface whatever the current stop is. */ 159 return KIT_OK; 160 } 161 if (!stop_is_internal_completion(s)) { 162 /* User breakpoint, signal, or exit — surface. */ 163 return KIT_OK; 164 } 165 166 (void)dwarf_line_for(s, s->stop.regs.pc, &new_file, &new_line); 167 have_new_sub = (dwarf_sub_for(s, s->stop.regs.pc, &new_sub) == KIT_OK); 168 169 if (have_sub && have_new_sub) { 170 if (new_sub.low_pc != base_sub.low_pc) { 171 /* Left the original subprogram — STEP_LINE follows in. */ 172 return KIT_OK; 173 } 174 } 175 176 if (line_changed(base_file, base_line, new_file, new_line)) { 177 return KIT_OK; 178 } 179 } 180 return KIT_OK; 181 } 182 183 static KitStatus run_step_out(KitJitSession* s) { 184 KitUnwindFrame frame; 185 u32 bp_id = 0; 186 KitStatus st; 187 frame = s->stop.regs; 188 frame.pc = step_rt_to_img(s, frame.pc); /* CFI lookup is in image space */ 189 st = kit_dwarf_unwind_step(s->dwarf, &frame); 190 if (st != KIT_OK) { 191 if (!s->arch_dbg || !s->arch_dbg->link_register_return_address || 192 s->arch_dbg->link_register_return_address(&s->stop.regs, &frame.pc) != 193 KIT_OK) { 194 return st; 195 } 196 } 197 /* On success unwind_step or the link-register fallback writes frame.pc from 198 * the saved return-address register / stack slot — already a runtime PC, no 199 * inverse translation needed before the internal bp install. */ 200 if (frame.pc == 0) return KIT_NOT_FOUND; 201 st = dbg_bp_set_internal(s, frame.pc, &bp_id); 202 if (st != KIT_OK) return st; 203 st = dbg_session_signal_resume(s); 204 if (st != KIT_OK) return st; 205 return dbg_session_wait_stop(s); 206 } 207 208 static KitStatus run_next_line(KitJitSession* s) { 209 ArchDbgInsn insn; 210 211 if (!s->arch_dbg || !s->arch_dbg->is_call || 212 dbg_arch_decode_insn(s, s->stop.regs.pc, &insn) != KIT_OK) { 213 return run_step_line_loop(s); 214 } 215 if (!s->arch_dbg->is_call(&insn)) { 216 return run_step_line_loop(s); 217 } 218 219 /* Step OVER the call by setting an internal bp at the unwound return PC 220 * and CONTINUE-ing. After the bp fires, fall into the STEP_LINE loop to 221 * keep advancing until the source line actually changes. */ 222 { 223 KitUnwindFrame frame = s->stop.regs; 224 u32 bp_id = 0; 225 KitStatus st; 226 frame.pc = step_rt_to_img(s, frame.pc); 227 if (kit_dwarf_unwind_step(s->dwarf, &frame) != KIT_OK || frame.pc == 0) { 228 /* Fall back to stepping into the call. */ 229 return run_step_line_loop(s); 230 } 231 /* frame.pc is now a runtime return-address (from the stack). */ 232 if (dbg_bp_set_internal(s, frame.pc, &bp_id) != KIT_OK) { 233 return run_step_line_loop(s); 234 } 235 st = dbg_session_signal_resume(s); 236 if (st != KIT_OK) return st; 237 st = dbg_session_wait_stop(s); 238 if (st != KIT_OK) return st; 239 if (stop_is_internal_completion(s)) { 240 return run_step_line_loop(s); 241 } 242 return KIT_OK; 243 } 244 } 245 246 KitStatus dbg_step_resume(KitJitSession* s, KitResumeMode mode) { 247 switch (mode) { 248 case KIT_RESUME_ABORT: 249 return KIT_OK; 250 case KIT_RESUME_CONTINUE: 251 if (dbg_bp_lookup_index(s, s->stop.regs.pc) != 0) { 252 return prepare_step_insn(s); 253 } 254 return KIT_OK; 255 256 case KIT_RESUME_STEP_INSN: 257 return prepare_step_insn(s); 258 259 case KIT_RESUME_STEP_LINE: { 260 KitStatus st; 261 if (!s->dwarf) return KIT_INVALID; 262 st = run_step_line_loop(s); 263 if (st != KIT_OK) return st; 264 s->pending_done = 1; 265 return KIT_OK; 266 } 267 268 case KIT_RESUME_NEXT_LINE: { 269 KitStatus st; 270 if (!s->dwarf) return KIT_INVALID; 271 st = run_next_line(s); 272 if (st != KIT_OK) return st; 273 s->pending_done = 1; 274 return KIT_OK; 275 } 276 277 case KIT_RESUME_STEP_OUT: { 278 KitStatus st; 279 if (!s->dwarf) return KIT_INVALID; 280 st = run_step_out(s); 281 if (st != KIT_OK) return st; 282 s->pending_done = 1; 283 return KIT_OK; 284 } 285 } 286 return KIT_INVALID; 287 }