<CPU>-<vendor>-<OS>

Questioning about the "target triplet" <CPU>-<vendor>-<OS> used by the GNU build system to describe a target

When building gdb targeting a different platform, one must choose --host, --build, and --target parameters.

The target parameter has the following format [1]:

<CPU>-<vendor>-<OS>

You can get the target of your gcc with:

gcc -dumpmachine

As examples:

x86_64-linux-gnu        (Intel laptop running Ubuntu)
arm-linux-gnueabihf     (Raspberry Pi running Raspbian)

What is the meaning of each field?

Based on information found at [2].

x86_64-mycompany-linux
|      |         |
|      |         | operating system
|      |         | (+ ABI sometimes, e.g., gnueabihf = GNU EABI Hard Float)
|      |
|      | vendor
|      | mostly irrelevant, often just 'unknown' or unused
|      | do not mistake 'linux-gnu' for <vendor>-<os>, when it is in reality just the <os> field
|
| CPU architecture
| definitions are found in <prefix>/config/cpu/<cpu>

There is a long shell script (config.sub) to disambiguate target triplets.

Build gdb

We build gdb [3] on a Raspberry Pi 3 targeting x86_64 debugging:

sudo apt-get install libncurses5-dev
sudo apt-get install libexpat1-dev
sudo apt-get install python-dev
mkdir build; cd build
../gdb-7.9.1/configure --target=x86_64-unknown-linux --with-expat --with-python
make -j4

Then to start debugging:

gdb/gdb /path/to/my/x86/bin/with/symbols
(gdb) set sysroot /path/to/my/x86/lib/ld-linux.so

It is obvious that gdb is unable to run the binary locally. Debugging can only be remote.

Alternatively, you can also use the target directly to load the shared libraries with (but better be the network connection fast):

(gdb) set sysroot remote:/

Note: if you do not activate expat with --with-expat, XML support will not be available in gdb, and you will get the warning:

warning: Can not parse XML target description; XML support was disabled at compile time

The consequence is that gdb will fail to load dynamic libraries even if you set the right sysroot and the ld breakpoint is correct.

Update 2016.12.11 When building gdb-7.12, make complains that makeinfo is not found (to build .texi docs). From an idea of [4], you can create a dummy makeinfo. Additional required packages:

sudo apt-get install bison

Bonus

If your target can only be reached via IPv6 local-link, an SSH tunnel must be created since gdb does not support IPv6 yet:

ssh root@fe80::250:b6ff:fe0e:23d9%eth1 -L 3333:localhost:3333
gdbserver 0.0.0.0:3333 /path/to/my/x86/bin/without/symbols

...and inside gdb:

target remote :3333

IPv6 local-link is easy to use because the MAC address of the target is automatically converted into a local-link address. An online converter is [5].

Too many symbols?

The Raspberry Pi only has 1GB of RAM, and loading large binary requires larger amount of memory.

If only the function names in the backtrace are needed, the debug data can be dropped:

cp myBinaryWithFullDebugData myBinaryWithJustFunctionSymbols
strip -g myBinaryWithJustFunctionSymbols

save gdb-index keeps all the debug data, but loads faster and consumes less memory. See the shell script from the Chromium project at [6].

Not finding any dynamically loaded libraries?

[7] [8]

Not using a binary?

Tell gdb which architecture to expect with:

set architecture i386:x86_64:intel

gdb multiarch

As gdb is independent from the compiler used in the binary, it can also be built with multiple target supports. This is known as gdb multiarch [9].

For gdb without ncurses interface and with all possible targets:

../gdb-7.9.1/configure --with-expat --with-python --without-ncurses --enable-targets-all --prefix=/opt/gdb

Corrupted stack? Really?

When gdb is unable to find the debug symbols of libc6, it is unable to unwind the stack.

(gdb) bt
#0  0x762b7f70 in raise () from /mnt/target/lib/arm-linux-gnueabihf/libc.so.6
#1  0x762b9324 in abort () from /mnt/target/lib/arm-linux-gnueabihf/libc.so.6
#2  0x00000020 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

Check the value of debug-file-directory:

(gdb) show set debug-file-directory
The directory where separate debug symbols are searched for is "/usr/lib/debug".

It seems that setting the sysroot does not set this path accordingly.

(gdb) set debug-file-directory /mnt/target/usr/lib/debug

References

[1]GDB Wiki, "building GDB and GDBserver for cross debugging", https://sourceware.org/gdb/wiki/BuildingCrossGDBandGDBserver
[2]OSDev, Target Triplet, http://wiki.osdev.org/Target_Triplet
[3]GDB releases, ftp://sourceware.org/pub/gdb/releases/
[4]Dummy makeinfo, https://sourceware.org/bugzilla/show_bug.cgi?id=18113
[5]Ben's blog, MAC address to IPv6 link-local address online converter, http://ben.akrin.com/?p=1347
[6]Chromium, gdb-add-index, https://chromium.googlesource.com/chromium/chromium/+/master/build/gdb-add-index
[7]Faye Williams, GDB: Unable to find dynamic linker breakpoint function, http://www.fayewilliams.com/2013/01/31/gdb-unable-to-find-dynamic-linker-breakpoint-function/
[8]Sysprogs, Resolving library symbol load errors when debugging with cross-toolchains, https://sysprogs.com/w/resolving-library-symbol-load-errors-when-debugging-with-cross-toolchains/
[9]Neil Williams, https://lists.debian.org/debian-embedded/2011/01/msg00012.html