Previous - Up - Next

12.2   Using GDB with Simics

This chapter describes how to use gdb-remote, a Simics module that lets you connect a GDB session running on your host machine to the simulated machine using GDB's remote debugging protocol, and use GDB to debug software running on the target machine.

If you load the gdb-remote module in Simics, you can use the remote debugging feature of GDB, the GNU debugger, to connect one or more GDB processes to Simics over TCP/IP. In order to do this, you need a GDB compiled to support the simulation's target architecture on whichever host you're running. The gdb-remote module only supports version 5.0 or later of GDB, but other versions may work as well. Unfortunately GDB's remote protocol does not include any version checking, so the behavior is undefined if you use other versions. For information on how to obtain and compile GDB, see section 12.2.3.

To connect a GDB session to Simics, start your Simics session and run the new-gdb-remote command, optionally followed by a TCP/IP port number, which defaults to 9123 otherwise. This will automatically load the gdb-remote module.

When a configuration is loaded, Simics will start listening to incoming TCP/IP connections on the specified port. Run the simulated machine up to the point where you want to connect GDB. To inspect a user process or dynamically loaded parts of the kernel, the easiest solution might be to insert magic instructions at carefully chosen points. For static kernel debugging, a simple breakpoint on a suitable address will solve the problem.


Note: When debugging the start-up phase of an operating system, it might happen that gdb gets confused by the machine state and disconnects when you try to connect. In this case, execute a few instructions and try again.

Once Simics is in the desired state, start your GDB session, load any debugging information into it, and then connect it to Simics using the target remote host:port command, where host is the host Simics is running on, and port is the TCP/IP port number as described above. Here is a short sample session using bagle, a Sun UltraSPARC machine running Linux:

(gdb) set architecture sparc:v9a
(gdb) symbol-file vmlinux
Reading symbols from vmlinux...done.
(gdb) target remote localhost:9123
Remote debugging using localhost:9123
time_init () at /usr/src/linux/include/asm/time.h:52
(gdb)


Note: For some architectures, you need to give a command to GDB before connecting (the set architecture command in the session above). These are tabulated in the reference manual's section on gdb-remote, and will also be printed on the Simics console when you run new-gdb-remote.

From this point, you can use GDB to control the target machine by entering normal GDB commands such as continue, step, stepi, info regs, breakpoint, etc.

Note that while a remote GDB session is connected to Simics, the Simics prompt behaves a little differently when it comes to stopping and resuming the simulation. While the GDB session is at prompt, it is impossible to continue the simulation from within Simics (e.g., by using the continue command). However, once you continue the execution from GDB, you can stop it from GDB (by pressing control-C), which causes the simulation to stop and makes both GDB and Simics return to their prompts, or you can stop the simulation from the Simics prompt (also by pressing control-C). This only makes Simics return to prompt, while GDB will still think the target program is running. In this state, you should continue the simulation from the Simics prompt before attempting to use GDB.

You can also force GDB back to prompt using the gdb0.signal 2 command in Simics, which tells the GDB session that the simulated machine got a SIGINT signal. gdb0 here refers to the configuration object created on the fly when the GDB session connected to Simics. You can connect several GDB sessions to one Simics; each connection will be associated to one gdbnn object.

Since GDB isn't the most stable software, especially when using remote debugging, it unfortunately hangs now and then. To force Simics to disconnect a dead connection, you can use the gdb0.disconnect command.

Note that the gdb-remote module does not have any high-level information about the OS being run inside Simics. This means that in order to examine memory or disassemble code, the data or code you want to look at has to be in the active TLB.


Note: When using gdb-remote with targets supporting multiple address sizes (such as x86-64 and SPARC), you must have a GDB compiled for the larger address size. For SPARC, run GDB's configure script with the --target=sparc64-sun-solaris2.8 option.

12.2.1   Remote GDB and Shared Libraries

It takes some work to figure out how to load symbol tables at the correct offsets for relocatable object modules in GDB. This is done automatically for normal (non-remote) targets, but for the remote target, you have to do it yourself. You need to find out the actual address at which the shared module is mapped in the current context on the simulated machine, and then calculate the offset to use for GDB's add-symbol-file command.

To find the addresses of the shared libraries mapped into a process' memory space under Solaris, use the /usr/proc/bin/pmap pid command. The start address of the text segment can be obtained from the Addr field in the .text line of the output from dump -h file.

Under Linux, the list of memory mappings can be found in the file /proc/pid/maps (plain text format). The VMA column of the .text line of the output from objdump -h file contains the start address of the text segment.

Using these two values, map address and text address, you should use map address + text address as the offset to add-symbol-file (it has to be done this way to compensate for how GDB handles symbol loading).

The following example uses a SPARC running Linux (sim-sh# denotes the shell in the simulated computer):

sim-sh# ps
  PID TTY          TIME CMD
    :
  461 ttyS0    00:00:00 bash
sim-sh# cat /proc/461/maps
0000000000010000-0000000000060000 r-xp 0000000000000000 08:11 90115  /bin/bash
000000000006e000-0000000000076000 rwxp 000000000004e000 08:11 90115  /bin/bash
    :
0000000070040000-0000000070138000 r-xp 0000000000000000 08:11 106505 /lib/libc-2.1.3.so
0000000070138000-0000000070140000 ---p 00000000000f8000 08:11 106505 /lib/libc-2.1.3.so
0000000070140000-000000007014e000 rwxp 00000000000f0000 08:11 106505 /lib/libc-2.1.3.so
    :
sim-sh# objdump -h /lib/libc-2.1.3.so

/lib/libc-2.1.3.so:     file format elf32-sparc

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
    :
 14 .text         000ce338  000000000001e400  000000000001e400  0001e400  2**9

From this output, we derive that the bash process with PID 461 has /lib/libc-2.1.3.so located at starting address 0x70040000. The .text symbols starts at address 0x1e400, so if we connect GDB to Simics we have to add the symbols with an offset of 0x70040000 + 0x1e400 = 0x7005e400. Before running the following commands, we stopped Simics using control-C while it was executing code in the bash process:

(gdb) dir ~/glibc-2.1.2/malloc
Source directories searched: /home/joe/glibc-2.1.2/malloc:$cdir:$cwd
(gdb) add-symbol-file libc.so.6 0x7005e400
add symbol table from file "libc.so.6" at
        .text_addr = 0x7005e400
(y or n) y
Reading symbols from libc.so.6...done.
(gdb) target remote localhost:9123
Remote debugging using localhost:9123
__libc_malloc (bytes=0x14) at malloc.c:2691
2691        if (victim == q)
(gdb) next
2693          q = next_bin(q);
(gdb)

12.2.2   Using GDB with Hindsight

gdb-remote supports an extension to the GDB remote protocol that allows the debugger to control the Hindsight functions in Simics. An unmodified GDB does not know about this extension, however; if you compile GDB yourself, you will need to start from patched sources, available at https://www.simics.net/pub/ (see section 12.2.3). Some Simics packages come with a pre-compiled GDB with Hindsight support; you can find it in host/sys/bin/.

The patch adds a number of Hindsight commands to GDB; they all have the reverse- prefix, and are more or less just the reverse version of the standard commands:

reverse-continue
Run in reverse until a breakpoint or watchpoint is hit, or to the point where Hindsight runs out of history.
reverse-next
Run in reverse and stop at the previous source code line. Will skip subfunction calls.
reverse-nexti
Run in reverse and stop at the previous instruction. Will skip subfunction calls.
reverse-step
Run in reverse and stop at the previous source code line. Will enter subfunction calls.
reverse-stepi
Run in reverse and stop at the previous instruction. Will enter subfunction calls.
reverse-finish
Run in reverse till the point where the current function is called.

Normal break- and watchpoints set with break and watch will also be triggered when running in reverse using reverse-continue

A small example of how to use reverse-next:

22        for (i = 0; i < 10; i++)
(gdb) p i
$2 = 0
(gdb) n
24            c = foo (i) + c;
(gdb) p i
$3 = 1
(gdb) reverse-next
22        for (i = 0; i < 10; i++)
(gdb) p i
$4 = 0

The amount of history that Hindsight keeps is limited; it is only possibly to reverse back to the point where Hindsight was started. If GDB recognizes that Hindsight has ran out of history, it will report an error. Note that this is not a fatal error, and the debugging session can continue, without the possibility to reverse further than to the point where GDB reported the error.

(gdb) reverse-continue 
Continuing.

No more history to reverse further.
_start () at start.c:17
17      {

12.2.3   Compiling GDB

If you do not want to (or cannot) use one of the GDB executables in host/sys/bin/, you will most likely have to compile GDB from source, even if your system already has GDB installed. The reason for this is that a given GDB executable is specialized both for the architecture of the computer you run it on (host), and the architecture of the computer that runs the programs you want to debug (target). Any GDB already installed on your computer will have target identical to host, but this is often not what you want when your target is a simulated machine.

The first step is to get the GDB source code. You can either get the unmodified GDB from ftp://ftp.gnu.org/, or a Hindsight-aware GDB from https://www.simics.net/pub/. In either case, the source will be packaged in a .tar.gz file.

The second step is to make sure you have all the tools necessary to compile GDB, such as GNU Make and a C compiler. On a Linux or Solaris system, you probably have them already. On Windows, you will have to install Cygwin; get it at http://www.cygwin.com/.

That done, unpack and configure GDB like this:

~> tar zxfv gdb-6.3.tar.gz
~> cd gdb-6.3
~/gdb-6.3> ./configure --target=powerpc64-elf-linux

(On Windows, be sure to enter these commands in the bash shell installed as part of Cygwin.)

The --target flag to configure specifies which target architecture your new GDB binary will be specialized for (in this example, a 64-bit PowerPC). These flags are tabulated in the reference manual's section on gdb-remote, and will also be printed on the Simics console when you run new-gdb-remote.

~/gdb-6.3> make

The build process takes a while; when done, it will have left a gdb executable in the "gdb" subdirectory. You can execute it directly from that location:

~/gdb-6.3> ./gdb/gdb

Previous - Up - Next