CLI tool
nakst/gf avatar
nakst/gf

nakst/gf: a native GDB frontend for Linux and the BSDs

A GDB frontend for Lïnux.

3,429 stars106 forksObjective-CMIT

At a glance

What is it?
gf wraps GDB in an X11 interface with source view, watch expressions and a configurable layout. It is a single C++ file you compile yourself, and that shapes who should use it.
Who is it for?
Adopt gf if you already debug C or C++ with GDB on Linux or a BSD, want a graphical source view and watch window, and are willing to compile it yourself from the repository. Do not adopt it if you need Windows support, a packaged binary, or a debugger that manages its own build system; the repository ships build scripts, not installers, and the README never documents a rollback path for a broken configuration.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 107 days ago.
What is it written in?
Mainly Objective-C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What gf replaces, and for whom

GDB's command line is precise but it is not spatial. When you are stepping through a C or C++ program, you spend most of your attention on three things at once: the source line you are on, the values in scope, and the call stack that got you there. gf renders those three as panes in an X11 window and keeps GDB underneath as the actual debugger. The README describes it as "A GDB Frontend", and the screenshots show a source view, breakpoints list, call stack, bitmap viewer and command prompt in one window.

The audience is narrow on purpose. The build scripts cover Linux, FreeBSD, NetBSD, OpenBSD, OpenIndiana and macOS, so this is a Unix debugger, not a cross-platform IDE. The primary language of the repository is Objective-C, and the main implementation lives in a single file, gf2.cpp, alongside luigi2.h and windows.cpp. Anyone expecting a plugin for an existing editor will not find one here; gf is the application, and GDB is the engine it drives.

How gf talks to GDB and where settings come from

gf does not reimplement a debugger. It starts GDB, forwards its own command line arguments to it, and renders the results. That single design decision explains most of the behaviour. Any standard GDB command works, because GDB is the one executing it.

Settings load in two passes. On startup gf reads ~/.config/gf2_config.ini, then .project.gf, so a per-project file can override your global preferences. The format is INI-style, and the sections map to subsystems: [gdb] for the debugger, [shortcuts] for keys, [ui] for fonts and layout, [commands] for preset command lists, [vim] for editor integration, and [pipe] for the control and log pipes. The layout string is built from h(), v() and t() calls, and the README warns that this value is not validated, so a malformed string is your problem to find. Two pipes give external tools a way in: a control pipe that accepts f, l and c commands to change the loaded file, jump to a line, or send a GDB command, and a log pipe that displays messages in a Log window you place in the layout yourself.

Building gf from source and running a first session

There is no package to install. The README's build section starts with cloning the repository, then running a platform script. On Linux that is ./build.sh; FreeBSD, NetBSD and OpenBSD have their own scripts, and the repository also contains build_macos.sh and build_openindiana.sh.

bash
git clone https://github.com/nakst/gf.git
cd gf
./build.sh

After a successful build you run the binary directly. Any arguments you pass are forwarded to GDB, which is how you point gf at a target without changing your config.

bash
./gf2 ./bin/app

The README lists one setup step that trips people up. If you launch gf from a different directory than the one you compiled in, press Ctrl+Shift+P to synchronize the working directory with GDB. Without that, GDB resolves relative paths against the wrong place. The README also suggests adding two lines to ~/.gdbinit: set breakpoint pending on and set disassembly-flavor intel.

For a config that does something useful on first run, the preset commands section is the fastest path. Commands are separated by semicolons and the final one can run asynchronously with a trailing &.

ini
[commands]
Compile=shell gcc -o bin/app src/main.c
Run normal=file bin/app;run&
Set breakpoints=b main;b LoadFile;b AssertionFailure

Those entries appear in the Commands tab. Selecting Run normal loads the binary and starts it without blocking the interface.

The layout string is powerful and unforgiving

The layout parameter is where gf's design shows both its flexibility and its rough edge. You compose the window from horizontal splits, vertical splits and tab panes, and the README gives a full example rather than a grammar reference.

ini
layout=h(75,v(75,Source,Console),v(50,t(Watch,Breakpoints,Commands,Struct,Exe),t(Stack,Files,Registers,Data,Thread))))

The constraint is stated plainly: horizontal and vertical splits must have exactly two children, so anything more complex has to be nested. The string must contain no whitespace. And because the value is not validated, a mistake produces a broken or empty interface rather than an error message. That is a real cost for a feature this central to the tool. A user who wants a different pane arrangement is editing a nested expression by hand and testing it by restarting the application.

The same file holds the smaller preferences: scale, font_path, font_size_interface, font_size_code, width and height in [ui], plus toggle keys like maximize, restore_watch_window, selectable_source and center_execution_pointer. Font changes require that FreeType was available at compile time, and subpixel rendering needs a rebuild with extra_flags=-DUI_FREETYPE_SUBPIXEL ./build.sh. So a font setting can silently do nothing if the binary was built without the dependency.

Reverse debugging and the rr integration

The README documents one workflow that most graphical debuggers do not expose at all: replaying a trace recorded by rr. Running gf2 --rr-replay puts the interface into a mode where reverse continue and reverse step are available on Ctrl+Shift+F5, Ctrl+Shift+F10 and Ctrl+Shift+F11. The [shortcuts] section can bind the same commands to different keys, since reverse-next and reverse-step are ordinary GDB commands.

This is the strongest argument for gf over a plain terminal session. Reverse execution is awkward to drive from a prompt because you constantly lose track of where you are in the trace. Having the source view and stack update in place while you step backwards is the case where the graphical layer earns its keep. The limitation is that it depends on rr having recorded the trace first, and rr is a separate project. gf does not record anything itself.

Where gf is the wrong tool

The repository contains no Windows build script, and the README's platform list stops at the Unix family. If your team debugs on Windows, gf is not a candidate, and there is no indication in the README that this is planned.

Distribution is the second constraint. There are no releases in the repository, so there is no binary to download and no version number to pin. You clone, you build, and you track master. For an individual developer that is fine. For a team that needs reproducible tooling across machines, it means either building gf yourself as part of your environment setup or accepting that every developer's gf is a different commit.

The third case is subtler. gf forwards its arguments to GDB and renders GDB's output, so it inherits GDB's configuration surface entirely. If your workflow depends on a Python script loaded through .gdbinit, or on a GDB extension that prints structured output, gf will run it, but the README does not describe how arbitrary command output is rendered in the interface. The documented escape hatch is log_all_output=1, which sends all GDB output to the Log window, provided you have placed that window in your layout string. That is a workaround, not a feature.

What to compare it against

The obvious alternative is GDB's own text user interface, enabled with the tui command or Ctrl+X, Ctrl+A. It solves the same core problem: showing source, registers and the command prompt together in one terminal. The difference is control. TUI is one fixed arrangement inside your terminal emulator, resized with the terminal, and it does not persist a layout between sessions. gf gives you a window you arrange with h(), v() and t(), saved in an INI file, with fonts and scaling you choose. TUI needs nothing installed beyond GDB itself, which matters on a remote machine where you have no X server. gf needs X11 and a display.

The second comparison is an editor-integrated debugger. That approach keeps you in the editor you already use and drives GDB through a protocol. gf inverts it: the debugger is the application, and the README's Vim integration is limited to a server_name key in the [vim] section, plus the control pipe that lets an editor tell gf which file and line to show. If your editing environment is the thing you refuse to leave, the control pipe is the integration point to evaluate, and it is a one-way channel for file, line and GDB commands.

Editorial conclusion

Adopt gf if you already debug C or C++ with GDB on Linux or a BSD, want a graphical source view and watch window, and are willing to compile it yourself from the repository. Do not adopt it if you need Windows support, a packaged binary, or a debugger that manages its own build system; the repository ships build scripts, not installers, and the README never documents a rollback path for a broken configuration. Before relying on it, verify first that your machine has the X11 and FreeType development files the build needs, that a build of gf2.cpp succeeds on your distribution, and that your existing ~/.gdbinit does not conflict with the settings gf loads from ~/.config/gf2_config.ini.

Frequently asked questions

What does GDB stand for in Linux?

The README does not expand the acronym. It points readers new to GDB at an external article on handmade.network and otherwise assumes familiarity with the debugger, since gf forwards commands to GDB and renders its output.

How do I build nakst/gf on Linux?

The README's build section says to clone the repository and run ./build.sh, which compiles the application. FreeBSD, NetBSD, OpenBSD, OpenIndiana and macOS each have their own build script in the repository, and the resulting binary is run as ./gf2.

Where does nakst/gf keep its configuration?

Settings load on startup from ~/.config/gf2_config.ini and then from .project.gf, so a project file can override the global one. The file is INI-style, with sections for GDB arguments, shortcuts, the interface, preset commands, Vim and pipes.

Can nakst/gf step backwards through a program?

Only when replaying a trace recorded by rr. The README states that gf2 --rr-replay is used for that, with Ctrl+Shift+F5, Ctrl+Shift+F10 and Ctrl+Shift+F11 bound to reverse continue and reverse step. gf does not record traces itself.

Why does nakst/gf show the wrong working directory?

The README notes this happens when you start gf in a different directory from the one you compiled in. Pressing Ctrl+Shift+P synchronizes the working directory with GDB after you start your target executable.

Official sources

  1. Issues
  2. License: MIT
  3. nakst/gf on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nakst-gf.svg)](https://hysenlabs.com/projects/nakst-gf)