Debugging untrusted code with gdb on Windows

This page describes the basics for using a custom build of the Gnu debugger (gdb) to debug Native Client applications on 64-bit Windows.


NOTE: We are in the process of implementing a modified version of GDB that can do a better job of debugging Native Client modules on Windows. In the mean time, this page explains how you can get some of the benefits through an interim solution.

Building

Debugging on x86-64

Currently you can download a pre-built build of gdb using the nacl_sdk.

Steps:
  1. Download the latest NaCl SDK
  2. Unzip nacl_sdk.zip
  3. Open a terminal and change directory to nacl_sdk (as just extracted from nacl_sdk.zip)
  4. Type: naclsdk update gdb_builds
The debugger will be installed into nacl_sdk\gdb_builds\gdb-win-builds as gdb-win64-remote-x86-64.exe

If you still want to build your own debugger, here are the instructions:
  1. Note that you can skip the next 10 steps by downloading the attached zipfile which contains a gdb.exe built for windows 64 to debug a linux-x86-64 binary.
  2. Download the latest MinGW64-bit toolchain. One location is http://sourceforge.net/projects/mingw-w64/.  Make sure that the zip file you download is a binary file, not source, unless you want to compile it from sources, and is a w64 version of mingw (which otherwise is 32 bit). The file type is embedded into the name.  For example, this file -- mingw-w64-bin_i686_mingw_20110827.zip -- contains 'w64-bin' to indicate that it contains binaries and is the 64 bit version. You should be able to download the correct file from here: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Automated%20Builds/.
  3. Unzip the file you downloaded.
  4. Install MinGW 64-bit by copying the extracted files and directories to an appropriate location.
  5. Download MSYS. It is part of some MinGW installations, but not the 64 bit toolchain installation above. One source for it is http://sourceforge.net/projects/mingw-w64/files/External%20binary%20packages%20%28Win64%20hosted%29/MSYS%20%2832-bit%29/
  6. Unzip MSYS (extract it). You should use 7zip to do this. Using WinZip will likely result in a 'Windows unknown error 0x800004005' failure. If you installed MinGW to a directory such as C:\src\MinGW64\, you could just extract MSYS to c:\src\MinGW64\msys.
  7. Download and unpack the gdb sources from ftp://sourceware.org/pub/gdb/snapshots/current/. The following steps are known to work with gdb version 7.3.50.20110902.
  8. Start msys by running the msys.bat file in [MINGW_DIR]\msys\
  9. Change directory to the gdb source root, e.g.
           # MSYS wants Unix-style paths; type ‘mount’ for more info
           cd /c/work/gdb-7.3.50.20110902/
  10. Assuming you’ve put MinGW in c:\work\mingw64, do this to build gdb:
           mkdir build
           cd build
           # Ensure that 64-bit compiler are used!
           export PATH=/c/work/mingw64/bin:$PATH
           ../configure --host=x86_64-w64-mingw32 --target=x86_64-linux --prefix=`pwd`
           make -j16
           make install
  11. You now have gdb.exe in /c/work/gdb-7.3.50.20110902/build/gdb/.

Debugging on i386

The instructions for building a version of gdb to debug a 32-bit nexe are very similar to the instructions for building a 64 bit build. Instead of MinGW for 64 bit machines, you need plain old mingw32 which can be obtained here: http://sourceforge.net/projects/mingw/files/latest/download
For step 10, you need to specify a 32 bit linux architecture as your target instead of a 64 bit architecture.

Using gdb to debug

Follow these instructions to debug a NaCl module running in Chrome on 64-bit Windows.
  1. Build your project in debug mode (see SDK instructions: http://code.google.com/chrome/nativeclient/docs/compiling.html#Debug)
  2. Start Chrome
       <PATH TO CHROME>\chrome.exe --enable-nacl-debug --no-sandbox ^
           <URL TO PAGE CONTAINING NEXE>

    This causes Chrome to start, navigate to the page, load the nexe, and wait for the debugger to connect before continuing.
  3. use objdump to find the address of the text segment in the nexe: nacl64-objdump.exe -D -S <NEXE_PROJECT_NAME>_x86_64.nexe > dump_output.txt
  4. Open dump_output.txt and find the line that says: "Disassembly of section .text:" The following line that has text starts with the address of the text segment for example: 0000000000020080 Note that this address is not guaranteed to be the same for all nexes.
  5. Start gdb and connect to the debug server:
       target remote localhost:4014
       set architecture i386:x86-64
  6. At this point you need the base address, which is stored in register 15. Add to that the text section address from step 5 and you're ready to load symbols info registers    add-symbol-file <NEXE_PROJECT_NAME>_x86_64_dbg.nexe [r15+text_section_address]
  7. gdb needs to be able to find the nexe file and the source code. An easy approach is to have both the nexe and the sources in the same directory and start gdb from that directory. Another better approach is to expand gdb’s search path by using the ‘dir’ command without gdb. See the next step for an example    dir <NACL_SDK_ROOT>/pepper_15/toolchain/win_x86_newlib
  8. For ease of use you can put all these command in a text file - say, <NEXE_PROJECT_NAME>.gdb - and invoke gdb with --command=<NEXE_PROJECT_NAME>.gdb
  9. Once gdb has started and executed the command you can use ‘c’, Ctrl-c, set breakpoints, inspect heap/stack variables, etc.
  10. Note that the page will not load until you issue the continue command (c or continue). Before you do that, you probably will want to set a breakpoint in code you are interested in. You can set breakpoints based on function names, or filenames/line numbers, using the break command. For example, if you are interested in line 80 of hello_world.cc, you could do "break hello_world.cc:80" before continuing.

Setting up Visual Studio

Add the gdb script from the previous section to the Visual Studio project to make it easy to retrieve and modify.
I’ve modified the build.scons to copy the gdb script into a directory containing the nexe and the sources. This is the directory where I start gdb.exe.
It is convenient to have Visual Studio run a bat file on execution, i.e., when the developer presses Ctrl-F5. This bat file should also be added to the project to make it easy to find and modify. Here is an example:

@echo off

start c:\work\102105\chrome.exe --incognito --enable-nacl --no-sandbox ^
   --show-fps-counter --enable-nacl-debug ^
   http://localhost:5103/apps_nacl/tentacles/out/tentacles.html

cd c:\work\apps_nacl\tentacles\out
c:\work\gdb\gdb-7.3.50.20110902\build\gdb\gdb.exe --command=tentacles.gdb

Using out-of-process debug server

The 32 bit version of the debug server can be found in the main Pepper Bundle of the SDK, under debugger\nacl-gdb-server\Release
The 64 bit version can be found in the same bundle, under debugger\nacl-gdb-server\Release

Start out-of-process debug server by:
$>nacl-gdb_server [options] --program "program to debug"
where options are: --port <number> : port to listen for a TCP connection, default is 4014 --cm : compatibility mode - if specified, behaves exactly as in-process debug stub
Example: $>nacl-gdb_server --port 4014 --cm --program "c:\chrome.exe --incognito http://localhost:5103/hello_world_c/hello_world.html"
Note: there's no need to specify --no-sandbox flag. Type Ctrl-C or 'quit' to exit.

Example output:

nacl-gdb_server v0.5 64-bits
...
<<<<[10/19/11 21:18:57.367] [TR100.2] Starting process [D:\src\\chrome-win32\chro me.exe --incognito http://localhost:5103/hello_world_c/hello_world.html]... >>>> <<<<[10/19/11 21:18:59.324] [OutputDebugString] [{7AA7C9CF-89EC-4ed3-8DAD-6DC84302AB11} -versio n 1 -event AppCreate -nap 000000000024E070 -mem_start 0000000C00000000 -user_entry_pt 000000000 002CBC0 -initial_entry_pt 000000000FC00200] pid=6428 tid=5040 >>>> <<<<[10/19/11 21:18:59.328] [OutputDebugString] [{7AA7C9CF-89EC-4ed3-8DAD-6DC84302AB11} -versio n 1 -event ThreadCreate -natp 00000000414F06C0] pid=6428 tid=4800 >>>> <<<<[10/19/11 21:18:59.328] [TR100.5] NaClThreadStart mem_base=0000000C00000000 entry_point=000 000000002CBC0 thread_id=4800 >>>> <<<<[10/19/11 21:18:59.329] [TR100.6] CompatibilityMode: setting breakpoint at 0000000C0002CBC0 >>>> <<<<[10/19/11 21:18:59.331] [TR100.7] Halted: pid=6428 tid=4800 debugevent=dwDebugEventCode=0x1 dwProcessId=0x191C dwThreadId=0x12C0 NaClEventId=0 >>>> CreateSockAddr : on INADDR_LOOPBACK <<<<[10/19/11 21:18:59.338] [TR100.1] Started listening on port 4014 ... >>>> <<<<[10/19/11 21:18:59.339] [TR100.8] CompatibilityMode: hit breakpoint>>>> You can start gdb and connect to the debug server now. Look at the line with "[TR100.5] NaClThreadStart mem_base=0000000C00000000". This is your NaCl base address: gdb> add-symbol-file <NEXE_PROJECT_NAME>_x86_64_dbg.nexe [0xC00000000 +text_section_address]
Make sure you are running 32-bit debug server on 32-bit windows, and 64-bit debug server on 64-bit Windows.

Č
ċ
ď
gdb-remote-x86-64.zip
(39444k)
Andrey Khalyavin,
Oct 4, 2011, 2:49 PM
Comments