honeybadger

cosmopolitan libc

your build-anywhere run-anywhere c library

Debugging Actually Portable Executables on Windows

Screenshot of GDB debugging an APE binary on Windows 7

Background

The Cosmopolitan C Library builds binaries the same way for all platforms.
In other words, the programs we build on Linux run on Windows too.
The best practice is to create two separate files:

Prerequisites

You need to install MSYS2 on your Windows machine. You then then open up an MSYS2 mintty terminal and enter a command to install GDB.

pacman -S gdb

Since you'll be debugging programs written with Cosmopolitan Libc, you'll want to clone the full source repository.

pacman -S git
git clone https://github.com/jart/cosmopolitan cosmo
cd cosmo

You need to invoke your programs from the root of that repository. Don't cd into subdirectories. Cosmopolitan objects are always compiled using -fdebug-prefix-map="$(PWD)"= which ensures all DWARF data is relative to the root of the monolithic repository. That applies to both source tree builds, as well as anything built using the cosmopolitan.a amalgamation.

You'll also want a decent ~/.gdbinit file:

add-auto-load-safe-path ~/.gdbinit
set host-charset UTF-8
set target-charset UTF-8
set target-wide-charset UTF-8
set complaints 0
set confirm off
set history save on
set history filename ~/.gdb_history

# show source tui
define src
  layout src
  layout reg
end

# show assembly tui
define asm
  layout asm
  layout reg
end

src

# print backtrace w/ rbp
# fallback for when `bt` is broken
# we recommend -fno-omit-frame-pointer
# needed because ape won't use -funwind-tables
define et
  set $x = (void **)$rbp
  while $x
    x/2a $x
    set $x = (void **)$x[0]
  end
end

The above config puts GDB in TUI mode. It also defines two shortcut commands for switching between the source code and disassembly.

Lastly, you'll likely want an SSH server so you can copy files from Linux to Windows as quickly as possible. One that we recommend is Bitvise SSH Server. It's also useful when developing in the Cosmopolitan mono repo since tool/build/runit.c uses SSH to automate spawning tool/build/runitd.c for distributed low-latency regression testing.

Building

First you need to build your program. There are a several ways of doing this. The first is to use the Linux toolchain on Windows to build your program, as explained by this tutorial.

Another common strategy is to log on to your Linux computer, build the source tree there, and then scp executables back to Windows:

ssh linux
cd cosmo
make -j18
scp o//examples/hello.com windows:cosmo/
scp o//examples/hello.com.dbg windows:cosmo/

There's also the amalgamation approach, which is easier for many use cases, but is less tested compared to using the monolithic repository:

gcc -g -O -o hello.com.dbg hello.c \
  -static -fno-pie -no-pie -mno-red-zone -fno-omit-frame-pointer \
  -nostdlib -nostdinc -Wl,--gc-sections -Wl,-z,max-page-size=0x1000 -fuse-ld=bfd \
  -Wl,-T,ape.lds -include cosmopolitan.h crt.o ape.o cosmopolitan.a
objcopy -S -O binary hello.com.dbg hello.com
scp hello.com{,.dbg} windows:cosmo/

Debugging

Once you have the APE binary and the associated DWARF debug data, you can launch GDB on Windows as follows:

cd cosmo
gdb hello.com -ex 'add-symbol-file hello.com.dbg 0x401000'

That's the trick you need to get up and running, debugging your programs natively on Windows NT. You can now use GDB as you would normally. For example, some helpful commands are:

s                  # step
c                  # continue
finish             # continue to end of function
CTRL-C             # stop and return to debugger
break main         # break when function is entered
watch *0x31337     # break when memory address is changed
p var              # print variable or expression
x/10gx $rax        # print memory address in rax as ten 64-bit hex ints
bt                 # print backtrace
et                 # print backtrace (fallback method)
up                 # go up backtrace
down               # go down backtrace
asm                # show assembly
stepi              # step instruction
src                # go back to source code

Go Deeper

If you want to learn more about the significance of the magic number 0x401000 (which is the start of the .text section) then you can read the files in the ape/ directory, such as: