Home

Awesome

BugStalker

Modern debugger for Linux x86-64. Written in Rust for Rust programs.

debugger-demo


Table of Contents


Supported rustc versions


Features


Installation

First check if the necessary dependencies (pkg-config and libunwind-dev) are installed:

For example, ubuntu/debian:

apt install pkg-config libunwind-dev

For example, fedora:

dnf install pkg-config libunwind-devel

Now install debugger:

cargo install bugstalker

That's all, bs command is available now!

<details> <summary>Problem with libunwind?</summary> If you have any issues with `libunwind`, you can try to install `bs` with native unwinder (currently, I don't recommend this method because libunwind is better :))
cargo install bugstalker --no-default-features
</details>

Distro Packages

<details> <summary>Packaging status</summary>

Packaging status

</details>

Arch Linux

pacman -S bugstalker

Nix package manager

There's flake which you can use to start using it. Just enable flakes then you're able to use it with:

nix run github:godzie44/BugStalker

bugstalker also provides a package which you can include to your NixOS config. For example:

<details>
{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    bugstalker.url = "github:godzie44/BugStalker";
  };

  outpus = {nixpkgs, bugstalker, ...}: {
    nixosConfigurations.your_hostname = nixpkgs.lib.nixosSystem {
      modules = [
        ({...}: {
          environment.systemPackages = [
            # assuming your system runs on a x86-64 cpu
            bugstalker.packages."x86_64-linux".default
          ];
        })
      ];
    };
  };
}
</details>
Home-Manager

There's a home-manager module which adds programs.bugstalker to your home-manager config. You can add it by doing the following:

<details>
{
  description = "NixOS configuration";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    home-manager.url = "github:nix-community/home-manager";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";
    bugstalker.url = "github:godzie44/BugStalker";
  };

  outputs = inputs@{ nixpkgs, home-manager, bugstalker, ... }: {
    nixosConfigurations = {
      hostname = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          ./configuration.nix
          home-manager.nixosModules.home-manager
          {
            home-manager.sharedModules = [
              bugstalker.homeManagerModules.default
              ({...}: {
                programs.bugstalker = {
                  enable = true;
                  # the content of `keymap.toml`
                  keymap = {
                    common = {
                      up = ["k"];
                    }
                  };
                };
              })
            ];
          }
        ];
      };
    };
  };
}
</details>

Start debugger session

To start with program from binary file use:

bs my_cool_program

Or with arguments:

bs my_cool_program -- --arg1 val1 --arg2 val2

Or attach to program by its pid:

bs -p 123

Help

Print help for view all available commands.

Start and restart

demo

Stopping and continuing

The Debugger stops your program when breakpoints are hit, or after watchpoint are hit, or after steps commands, or when the OS signal is coming. BugStalker always stops the whole program, meaning that all threads are stopped. Thread witch initiated a stop become a current selected thread.

Continue execution

demo

Breakpoints

demo

Watchpoints

demo

Watchpoint is a "data breakpoint". This means that the program stops when the variable (or expression, or just raw memory region) observed by watchpoint is changed. Currently, watchpoints feature based on x86-64 hardware breakpoints. Therefore, there are two limitations:

You can set watchpoint at variables (global or locals), or at expression based on variables. Watchpoints for local variables will be removed automatically, when variable out of scope. If watchpoint observes a global variable, then it will live as long as the debugger is running.

Lets look at examples:

Steps

demo

Signals

demo

BugStalker will catch signals sent from OS to debugee program and stop execution. For example, try to send SIGINT (ctrl+c) to the debugee program to stop it.

Change current selected thread

demo

Examining the stack

When your program has stopped, the first thing you need to know is where it stopped and how it got there.

Each time your program performs a function call, the information about where in your program the call was made from is saved in a block of data called a stack frame. The frame also contains the arguments of the call and the local variables of the function that was called. All the stack frames are allocated in a region of memory called the call stack.

Stack frames

The call stack is divided up into contiguous pieces called stack frames. Each frame is the data associated with one call to one function. The frame contains the arguments given to the function, the function's local variables, and the address at which the function is executed.

Backtrace

demo

Select a frame

demo

Most commands for examining the stack and other data in your program works on whichever stack frame is selected at the moment.

Examining source files

demo

BugStalker can print parts of your program's source code. When your program stops, the debugger spontaneously prints the line where it stopped. There is source commands for print more.

Examining data

demo

Of course, you need a way to examine data of your program.

These commands accept expressions as input or have a special mode (var locals print all local variables, args all print all arguments).

Expression

BugStalker has a special syntax for explore program data. You can dereference references, get structure fields, slice arrays or get elements from vectors by its index (and much more!).

Operator available in expressions:

Write expressions is simple, and you can do it right now! Some examples:

Other commands

Of course, the debugger provides many more commands:

Tui interface

demo

One of the most funny BugStalker features is switching between old school terminal interface and pretty tui at any moment.

Configuration

There is a keymap.toml file with tui keybindings configuration. You can find the default configuration files at https://github.com/godzie44/BugStalker/tree/master/src/ui/tui/config/preset/keymap.toml.

To override any of the defaults, begin by creating the corresponding file (from the file linked above) to: ~/.config/bs/keymap.toml. You can change keybindings configuration file by exporting the KEYMAP_FILE environment variable.

Oracles

demo console

demo tui

Oracle is a module that expands the capabilities of the debugger. Oracles can monitor the internal state of a program to display interesting information. For example, tokio oracle is able to provide information about tokio runtime during program debugging without the need to change the source code. You must run the debugger with enabled oracle, for example, for tokio oracle:

bs --oracle tokio ...

Then use oracle command for view oracle information:

Oracles also available in tui. Currently, there is only one builtin oracle - tokio oracle.

Contributing

Feel free to suggest changes, ask a question or implement a new feature. Any contributions are very welcome.

How to contribute.