# Debugging a Project

- Go to `Windows Specific` section if you are on Windows.
- Go to `Linux/macOS Specific` section if you are on Linux/macOS.
- Go to `macOS Specific` section if you are on macOS.

## Windows Specific

Debugging can be useful when you lack necessary information.
This section offers a set of PowerShell scripts that work with CDB (Microsoft's Console Debugger).
CDB accepts exactly the same commands as WinDBG.

### Start a Debugger

Read `REPO-ROOT/Project.md` to understand the solution folder and the unit test project name you are working with.
Additional information can be found in the first line of `REPO-ROOT/.github/Scripts/Execute.log`.
Execute the following PowerShell commands:

```
cd SOLUTION-ROOT
start powershell {& REPO-ROOT\.github\Scripts\copilotDebug_Start.ps1 -Executable PROJECT-NAME}
```

If the debugger is already started, this script will fail because the pipe name is occupied. That probably means the last time you forgot to stop the debugger. You can kill `cdb` and the process being debugged, before starting a new debugger.

The `start powershell {}` is necessary; otherwise the script will block the execution forever, causing you to wait infinitely.
The script will finish immediately, leaving a debugger running in the background. You can send commands to the debugger.
The process being debugged is paused at the beginning; you are given a chance to set breakpoints.
After you are ready, send the `g` command to start running.

### Stop a Debugger

- Kill `cdb` process first, if any.
  - The cdb path is stored in `$env:CDBPATH`.
- Kill the binary process that is blocked.

### Sending Commands to Debugger

```
& REPO-ROOT\.github\Scripts\copilotDebug_RunCommand.ps1 -Command "Commands"
```

The effect of commands lasts across multiple `copilotDebug_RunCommand.ps1` calls. For example, after you execute `.frame X`, you do not need to repeat it to use `dx` under the same call stack frame in later calls, as `.frame X` is already effective.

Multiple commands can be executed in sequence, separated by ";".
The debugger is configured to use source mode, which means you can see source files and line numbers in the call stack, and step in/out/over work line by line.
CDB accepts exactly the same commands as WinDBG, and here are some recommended commands:
- **g**: continue until hitting a breakpoint or crashing.
- **k**n: print current call stack.
- **kn LINES**: print first `LINES` of the current call stack.
- **.frame NUMBER**: inspect the call stack frame labeled with `NUMBER`. `kn` will show the number, file and line along with the call stack.
- **dv**: list all available variables in the current call stack frame.
- **dx EXPRESSION**: evaluate the `EXPRESSION` and print the result. `EXPRESSION` can be any valid C programming language expression. When you specify a type (especially when doing casting), full namespaces are required, do not start with `::`.
- **bp `FILE:LINE`**: set a breakpoint at the specified line in `FILE`, starting from 0. A pair of "`" characters are required around the target, this is not Markdown syntax.
- **bl**, **.bpcmds**, **be NUMBERS**, **bd NUMBERS**, **bc NUMBERS**, **bsc NUMBER CONDITION**: list, list with attached commands, enable, disable, delete, attach a command to breakpoint(s).
- **p**: step over, aka execute the complete current line.
- **t**: step in, aka execute the current line, if any function is called, goes into the function.
- **pt**: step out, aka run until the end of the current function.

An `.natvis` file is automatically provided with the debugger,
it formats some primitive types defined in the `Vlpp` project,
including `WString` and other string types, `Nullable`, `Variant`, container types, etc.
The formatting applies to the **dx** command,
when you want to see raw data instead of formatted printing,
use **dx (EXPRESSION),!**.

You can also use `dv -rX` to expand "X" levels of fields. The default option is `-r0`, which only expands one level of fields.

### Commands to Avoid

- Only use **dv** without any parameters.
- DO NOT use **dt**.
- DO NOT use **q**, **qd**, **qq**, **qqd** etc. to stop the debugger.

## Linux/macOS Specific

Like building and running, debugging must be performed from the same folder that contains `vmake`:
- If the repo has only one project, it is in `REPO-ROOT/Test/Linux`.
- If the repo has multiple projects, it is in `REPO-ROOT/Test/Linux/PROJECT-NAME`.
  - The `PROJECT-NAME` name follows `PROJECT-NAME.vcxproj`.
You are required to `cd` to such folder before launching `lldb`, otherwise relative paths to the binary and source files will be wrong.

`lldb` is going to block the terminal and wait for interaction, you should always start `lldb` in a PTY-backed tool session, for example:

```bash
lldb -- ./Bin/UnitTest /C
```

Keep the session ID returned by the tool. Send debugger commands as newline-terminated stdin, one round at a time, and wait for output between rounds.

End the session with:

```text
quit
```

If the debugged process is still running or stuck, send Ctrl-C (`\u0003`), then send:

```text
process kill
quit
```

For non-interactive one-shot debugging, wrap `lldb` with `timeout` so it cannot block forever.
