Backward Debugging Callback Timing Issue

Summary

When implementing a custom debugger plugin with TTD (Time-Travel Debugging) support using DBG_FLAG_TTD, the ev_set_backwards(false) callback is sent before ev_resume, causing the backward flag to be reset before the debugger can use it.

IDA Version

IDA Pro 9.2+

Steps to Reproduce

  1. Create a custom debugger plugin with DBG_FLAG_TTD flag
  2. Implement ev_set_backwards and ev_resume callbacks
  3. User initiates “Backward Continue” from Debug menu
  4. Observe callback sequence in debugger logs

Expected Behavior

When user clicks “Backward Continue”, the callback sequence should be:

ev_set_backwards(true)   <- Signal backward direction
ev_set_resume_mode(...)  <- Set step/continue mode
ev_resume                <- Execute with backward flag still true
ev_set_backwards(false)  <- Reset for next operation (AFTER resume)

Actual Behavior

The actual callback sequence is:

ev_set_backwards(true)   <- Signal backward direction
ev_set_backwards(false)  <- IMMEDIATE reset (BEFORE resume!)
ev_set_resume_mode(1)    <- RESMOD_INTO (not RESMOD_BACKINTO)
ev_resume                <- Flag is already false!

Root Cause Analysis

After analyzing windbg_user.dll (the built-in WinDbg debugger backend), we found that:

  1. WinDBG works because it runs synchronously inside IDA’s kernel during invoke_callbacks(). The flag check in continue_after_event happens during ev_resume processing, before the reset callback is dispatched.

  2. Plugin callbacks receive all callbacks sequentially through the notification system. The reset arrives before we process the resume.

Additional Issue: RESMOD_INTO vs RESMOD_BACKINTO

For “Backward Continue”, IDA sends ev_set_resume_mode(RESMOD_INTO) instead of RESMOD_BACKINTO. This means the plugin cannot rely on resume mode alone to determine direction for backward continue operations.

Operation Expected Actual
Forward Step Into RESMOD_INTO RESMOD_INTO ✓
Backward Step Into RESMOD_BACKINTO RESMOD_BACKINTO ✓
Forward Continue RESMOD_NONE (step+continue)
Backward Continue RESMOD_BACKINTO? RESMOD_INTO

Thanks for this detailed report! We’ll take a closer look at this behavior.