Skip to content

Debugging & Troubleshooting

Ezz Aldeen Bayoumi edited this page Jun 7, 2026 · 3 revisions

Debugging & Troubleshooting

This page explains how to use Brovan's debugging commands to investigate emulator bugs, missing features, and sample-specific failures.

The goal is to make it easier to answer questions like:

  • What code path is the sample taking?
  • Which module or function is being accessed?
  • Where does execution stop or diverge?
  • Is the problem a bug in Brovan, or an unimplemented feature?

Recommended workflow

When something fails, start with a focused run that captures the smallest useful amount of information.

A common pattern is:

Brovan.exe -c "showinstrs [relevant-code-range-here];debug;start;exit" sample.exe > logs.txt

This gives you:

  • instruction output for the area you care about
  • debugger and scheduler logs
  • a saved log file you can attach to an issue

If the relevant code range is not known yet, start with debug first, then narrow the range once you see where execution goes.

The debug command

The debug command is the main way to inspect emulator activity.

It shows:

  • functions being accessed across modules
  • thread scheduler logs
  • useful execution context for tracking emulator behavior

This is usually the first command to use when a sample hangs, crashes, or behaves differently than expected.

When to use it

Use debug when you want to:

  • follow module/function activity
  • understand scheduler behavior
  • see where execution stalls
  • confirm whether a code path is being reached
  • identify the last successful action before a failure

The showinstrs command

showinstrs prints instructions from a specific range.

This is useful when you want to inspect the exact code around a crash, an exception, or an unimplemented feature.

Range examples

You can specify an address range:

showinstrs 0x1000-0x2000

You can also specify a symbol-based range:

showinstrs ntdll.dll!NtCreateFile-ntdll.dll!NtCreateFile+0x10

When to use it

Use showinstrs when you want to:

  • inspect the instructions leading to a failure
  • understand what code path the sample is executing
  • verify whether a hook or syscall path is correct
  • find the exact instruction sequence that triggers a bug

calltrace and callstack

These commands help you understand how execution reached the current point.

calltrace

Use calltrace when you want to follow the history of calls that led to a bug or unexpected behavior.

It is especially useful for:

  • tracing a failure back to its origin
  • checking which function chain was executed
  • seeing how control moved through the emulator

callstack

Use callstack when you want the current stack context. is is a useful extension of calltrace.

It is especially useful for:

  • identifying where execution is right now
  • checking stack depth
  • comparing expected and actual call flow
  • debugging crashes and bad returns

Finding missing features

Sometimes a sample fails because Brovan does not yet implement something it needs.

The debugging commands above can help reveal:

  • a missing syscall or API behavior
  • incomplete memory handling
  • scheduler issues
  • instruction-level behavior that differs from real execution
  • unsupported edge cases in a specific module

When that happens, the logs usually point to the exact feature or code path that needs work.

How to report a good issue

When opening an issue, it is usually best to include the exact command you used and the log output it produced.

A good starting point is:

Brovan.exe -c "showinstrs [relevant-code-range-here];debug;start;exit" sample.exe > logs.txt

Then include:

  • what you were trying to run
  • what happened
  • what you expected to happen
  • the sample name or repro steps
  • the relevant log excerpt
  • whether the problem seems to be a bug or a missing feature

If you already know the problem area, mention it directly. For example:

  • scheduler loop
  • syscall emulation
  • module/function resolution
  • instruction handling
  • memory protection behavior

Tips for useful logs

A few small habits make debugging much easier:

  • keep the repro as small as possible
  • capture only the logs needed for the issue
  • save the exact command line you used
  • note whether the problem is deterministic
  • include the first error, not only the final crash

If a sample fails in the middle of execution, logs from the first failure point are usually more useful than the end of the run.

Example troubleshooting flow

  1. Run the sample with debug enabled.
  2. Find the function, module, or scheduler event where execution starts to go wrong.
  3. Use showinstrs on the surrounding code range.
  4. Check calltrace and callstack to understand how you reached that point.
  5. Open an issue with the command line, logs, and the suspected missing feature or bug.

Notes for contributors

If you are fixing a bug, try to include:

  • the smallest repro possible
  • the exact command used
  • the expected behavior
  • the observed behavior
  • any relevant module names or function names

This makes it much easier to verify the fix and avoid regressions.


Debugging is much easier when the issue report includes enough context to reproduce the problem quickly.