Startup Code Debugging Workaround

VisualGDB supports a special workaround for embedded targets that do not properly implement halt-after-reset behavior. If after loading the memory and restarting, the target immediately starts running, and gets past main() before the debugger can set any breakpoints, follow the steps below to work around this behavior:

  1. Add the following code to your main source file:
    static int SysprogsDebuggerIsAttached;
     
    void __attribute__((noinline)) WaitForSysprogsDebugger()
    {
        while (!SysprogsDebuggerIsAttached)
        {
        }
    }
  2. Call WaitForSysprogsDebugger() from main().
  3. Enable VisualGDB Project Properties -> Embedded Debug Tweaking -> Enable a workaround for debugging startup code:Then, select one of the following modes as the startup debugging workaround mode:
    • Hardcoded breakpoint instruction. In this mode VisualGDB will start debugging and wait for a hardcoded breakpoint to trigger inside WaitForSysprogsDebugger(). Once the breakpoint triggers, VisualGDB will set SysprogsDebuggerIsAttached to 1 and will continue executing. You can hardcode the breakpoint (and script skipping over it) as shown below:
      Platform Line at the beginning of WaitForSysprogsDebugger() Additional debugger command
      ARM
      asm("bkpt 255");
      set $pc = $pc + 2;
      ESP8266/ESP32
      asm("break 1, 1");
      set $epc2 = $pc + 3;
    • Timed break-in.  VisualGDB will let the program start, then will stop GDB and check the call stack. If the program was stopped in WaitForSysprogsDebugger(), VisualGDB will set SysprogsDebuggerIsAttached to 1 and will continue execution.
    • Software/hardware breakpoint in wait function. In this mode VisualGDB will set a breakpoint in WaitForSysprogsDebugger(). And will set SysprogsDebuggerIsAttached to 1 once it triggers. This mode can be used for backward compatibility where the breakpoints work from the beginning, but WaitForSysprogsDebugger() cannot be removed from the executable for compatibility reasons.