kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }