Contents|Index|Previous|Next
The
GDB remote serial protocol
The
following documentation discusses the remote serial protocol for hosts
and targets.
To debug a program running on
another machine (the debugging target machine), you must first arrange
for all the usual prerequisites for the program to run by itself. For example,
for a C program, you need:
-
A startup routine to set up
the C runtime environment; these usually have a name like ‘crt0’.
The startup routine may be supplied by your hardware supplier, or you may
have to write your own.
-
You probably need a C subroutine
library to support your program’s subroutine calls, notably managing input
and output.
-
A way of getting your program
to the other machine—for example, a download program. These are often supplied
by the hardware manufacturer, but you may have to write your own from hardware
documentation.
The next step is to arrange
for your program to use a serial port to communicate with the machine where
GDB is running (the host machine). In general terms, the scheme
has the following protocol.
-
On the host
GDB already understands
how to use this protocol; when everything else is set up, you can simply
use the ‘target remote’
command (see Specifying
a debugging target).
-
On the target
You must link with your
program a few special-purpose subroutines that implement the GDB remote
serial protocol. The file containing these subroutines is called a debugging
stub. On certain remote targets, you can use an auxiliary program gdbserver
instead of linking a stub into your program. See Using
the gdbserver
program for details.
The debugging stub is specific
to the architecture of the remote machine; for example, use ‘sparc-stub.c’
to debug programs on SPARC boards. The following working remote stubs are
distributed with GDB.
sparc-stub.c
m68k-stub.c
For Motorola 680x0 architectures.
i386-stub.c
For Intel 386 and compatible
architectures.
The ‘README’
file in the GDB distribution may list other recently added stubs.
What
the stub can do for you
The debugging stub for your
architecture supplies the following three subroutines.
set_debug_traps
This routine arranges for
handle_exception
to run when your program stops. You must call this subroutine explicitly
near the beginning of your program.
handle_exception
This is the central workhorse,
but your program never calls it explicitly—the setup code arranges for
handle_exception
to run when a trap is triggered.
handle_exception
takes control when your program stops during execution (for example, on
a breakpoint), and mediates communications with GDB on the host machine.
This is where the communications protocol is implemented; handle_
exception acts
as the GDB representative on the target machine; it begins by sending summary
information on the state of your program, then continues to execute, retrieving
and transmitting any information GDB needs, until you execute a GDB command
that makes your program resume; at that point, handle_exception
returns control to your own code on the target machine.
breakpoint
Use this auxiliary subroutine
to make your program contain a breakpoint. Depending on the particular
situation, this may be the only way for GDB to get control. For instance,
if your target machine has some sort of interrupt button, you won’t need
to call this; pressing the interrupt button transfers control to handle_exception—in
effect, to GDB. On some machines, simply receiving characters on the serial
port may also trigger a trap; again, in that situation, you don’t need
to call breakpoint
from your own program—simply running ‘target
remote’ from the
host GDB session gets control.
Call breakpoint
if none of these is true, or if you simply want to make certain your program
stops at a predetermined point for the start of your debugging session.
What
you must do for the stub
The debugging stubs that
come with GDB are set up for a particular chip architecture, but they have
no information about the rest of your debugging target machine.
First of all, you need to
tell the stub how to communicate with the serial port.
-
int getDebugChar()
Write this subroutine to
read a single character from the serial port. It may be identical to getchar
for your target system; a different name is used to allow you to distinguish
the two if you wish.
-
void putDebugChar(int)
Write this subroutine to
write a single character to the serial port. It may be identical to putchar
for your target system; a different name is used to allow you to distinguish
the two if you wish.
If you want GDB to be able to
stop your program while it is running, you need to use an interrupt-driven
serial driver, and arrange for it to stop when it receives a ˆC
(‘\003’,
the Control-C
character). That is the character which GDB uses to tell the remote system
to stop.
Getting the debugging target
to return the proper status to GDB probably requires changes to the standard
stub; one quick and dirty way is to just execute a breakpoint instruction
(the “dirty” part is that GDB reports a SIGTRAP
instead of a SIGINT).
Other routines you need to
supply are the following.
void exceptionHandler(intexception_number,void*exception_address)
Write this function to install
exception_address
in the exception handling tables.
You need to do this because
the stub does not have any way of knowing what the exception handling tables
on your target system are like (for example, the processor’s table might
be in ROM, containing entries which point to a table in RAM). exception_number
is the exception number which should be changed; its meaning is architecture-dependent
(for example, different numbers might represent divide by zero, misaligned
access, etc). When this exception occurs, control should be transferred
directly to exception_address,
and the processor state (stack, registers, and so on) should be just as
it is when a processor exception occurs. So if you want to use a jump instruction
to reach exception_address,
it should be a simple jump, not a jump to subroutine.
For the 386, exception_address
should be installed as an interrupt gate so that interrupts are masked
while the handler runs. The gate should be at privilege level 0 (the most
privileged level). The SPARC and 68k stubs are able to mask interrup themselves
without help from exceptionHandler.
void flush_i_cache()
(SPARC and SPARClite only)
Write this subroutine to flush the instruction cache, if any, on your target
machine. If there is no instruction cache, this subroutine may be a no-op.
On target machines that
have instruction caches, GDB requires this function to make certain that
the state of your program is stable.
You must also make sure the
following library routine is available.
void *memset(void *, int, int)
This is the standard library
function, memset,
which sets an area of memory to a known value. If you have one of the free
versions of libc.a,
memset
can be found there; otherwise, you must either obtain it from your hardware
manufacturer, or write your own.
If you do not use the GNU C
compiler, you may need other standard library subroutines as well; this
varies from one stub to another, but in general the stubs are likely to
use any of the common library subroutines which gcc
generates as inline code.
Putting
it all together
In summary, when your program
is ready to debug, you must use the following steps.
1.
Make sure you have the supporting
low-level routines (see What you must
do for the stub): getDebugChar,
putDebugChar,
flush_i_cache,
memset,
exceptionHandler.
2.
Insert these lines near
the top of your program:
set_debug_traps();
breakpoint();
3.
For the 680x0 stub only,
you need to provide a variable called exceptionHook.
Normally you just use void
(*exceptionHook)() = 0;,
but if before calling set_debug_traps,
you set it to point to a function in your program, that function is called
when GDB continues after stopping on a trap (for example, bus error). The
function indicated by exceptionHook
is called with one parameter: an int
which is the exception number.
4.
Compile and link together:
your program, the GDB debugging stub for your target architecture, and
the supporting subroutines.
5.
Make sure you have a serial
connection between your target machine and the GDB host, and identify the
serial port on the host.
6.
Download your program to
your target machine (or get it there by whatever means the manufacturer
provides), and start it.
7.
To start remote debugging,
run GDB on the host machine, and specify as an executable file the program
that is running in the remote machine. This tells GDB how to find your
program’s symbols and the contents of its pure text.
Then establish communication
using the target remote
command. Its argument specifies how to communicate with the target machine—either
via a devicename attached to a direct serial line, or a TCP port (usually
to a terminal server which in turn has a serial line to the target). For
example, to use a serial line connected to the device named ‘/dev/ttyb’,
use target remote
/dev/ttyb.
To use a TCP connection,
use an argument of the form host:port.
For example, to connect to port 2828 on a terminal server named manyfarms,
use target remote
manyfarms:2828.
Now you can use all the usual
commands to examine and change data and to step and continue the remote
program.
To resume the remote program
and stop debugging it, use the detach
command.
Whenever GDB is waiting for
the remote program, if you type the interrupt character (often, Ctrl-C),
GDB attempts to stop the program. This may or may not succeed, depending
in part on the hardware and the serial drivers the remote system uses.
If you type the interrupt character once again, GDB displays the following
prompt:
Interrupted while waiting
for the program.
Give up (and stop debugging
it)? (y or n)
If you type y,
GDB abandons the remote debugging session. (If you decide you want to try
again later, you can use target
remote again to
connect once more.) If you type n,
GDB goes back to waiting.
Communication
protocol
The stub files provided with
GDB implement the target side of the communication protocol, and the GDB
side is implemented in the GDB source file ‘remote.c’.
Normally, you can simply allow these subroutines to communicate, and ignore
the details. (If you’re implementing your own stub file, you can still
ignore the details: start with one of the existing stub files. ‘sparc-stub.c’
is the best organized, and therefore the easiest to read.)
However, there may be occasions
when you need to know something about the protocol—for example, if there
is only one serial port to your target machine, you might want your program
to do something special if it recognizes a packet meant for GDB.
All GDB commands and responses
(other than acknowledgements, which are single characters) are sent as
a packet which includes a check-sum. A packet is introduced with the character,
‘$’,
and ends with the character, ‘#’,
followed by a two-digit checksum: $packetinfo#checksum.
checksum
is computed as the modulo 256 sum of the packetinfo
characters.
When either the host or the
target machine receives a packet, the first response expected is an acknowledgement:
a single character, either ‘+’
(to indicate the package was received correctly) or ‘-’
(to request retransmission). The host (GDB) sends commands, and the target
(the debugging stub incorporated in your program) sends data in response.
The target also sends data when your program stops.
Command packets are distinguished
by their first character, which identifies the kind of command.
The following are some of
the commands currently supported (for a complete list of commands, look
in ‘gdb/remote.c.’):
g
Requests the values of CPU
registers.
G
Sets the values of CPU registers.
maddr,count
Read countbytes at location,
addr.
Maddr,count:...
Write count
bytes at location, addr.
cc addr
Resume execution at the
current address (or at addr,
if supplied).
s s addr
Step the target program
for one instruction, from either the current program counter or from addr,
if supplied.
k
?
Report the most recent signal.
To allow you to take advantage of the GDB signal handling commands, one
of the functions of the debugging stub is to report CPU traps as the corresponding
POSIX signal values.
T
Allows the remote stub to
send only the registers that GDB needs to make a quick decision about single-stepping
or conditional breakpoints. This eliminates the need to fetch the entire
register set for each instruction being stepped through.
GDB now implements a write-through
cache for registers and only re-reads the registers if the target has run.
If you have trouble with
the serial connection, you can use the command, set
remotedebug. This
makes GDB report on all packets sent back and forth across the serial line
to the remote machine. The packet-debugging information is printed on the
GDB standard output stream. set
remotedebug off
turns it off, and show
remotedebug shows
you its current state.
Using
the gdbserver
program
gdbserver
is a control program for Unix-like systems, which allows you to connect
your program with a remote GDB via target
remote—but without
linking in the usual debugging stub.
gdbserver
is not a complete replacement for the debugging stubs, because it requires
essentially the same operating-system facilities that GDB itself does.
In fact, a system that can run gdbserver
to connect to a remote GDB could also run GDB locally! gdbserver
is sometimes useful nevertheless, because it is a much smaller program
than GDB itself. It is also easier to port than all of GDB, so you may
be able to get started more quickly on a new system by using gdbserver.
Finally, if you develop code for real-time systems, you may find that the
tradeoffs involved in real-time operation make it more convenient to do
as much development work as possible on another system, for example by
cross-compiling. You can use gdbserver
to make a similar choice for debugging.
GDB and gdbserver
communicate via either a serial line or a TCP connection, using the standard
GDB remote serial protocol.
-
On the target machine
You need to have a copy
of the program you want to debug. gdbserver
does not need your program’s symbol table, so you can strip the program
if necessary to save space. GDB on the host system does all the symbol
handling. To use the server, you must tell it how to communicate with GDB;
the name of your program; and the arguments for your program. The syntax
has the following example's format.
target> gdbserver commprogram
[args...].
comm is
either a device name (to use a serial line) or a TCP hostname and portnumber.
For example, to debug Emacs with the argument, foo.txt,
and communicate with GDB over the serial port, /dev/com1,
use the following.
target> gdbserver /dev/com1
emacs foo.txt.
gdbserver
waits passively for the host GDB to communicate with it. To use a TCP connection
instead of a serial line, use the following.
target> gdbserver host:2345
emacs foo.txt.
The only difference from the
previous example is the first argument, specifying that you are communicating
with the host GDB via TCP. The ‘host:2345’
argument means that gdbserveris
to expect a TCP connection from machine ‘host’
to local TCP port 2345. (Currently, the ‘host’
part is ignored.) You can choose any number you want for the port number
as long as it does not conflict with any TCP ports already in use on the
target system (for example, 23
is reserved for telnet).
If you choose a port number that conflicts with another service, gdbserver
prints an error message and exits.
You must use the same port
number with the host GDB target
remote command.
-
On the GDB host machine
You need an unstripped copy
of your program, since GDB needs symbols and debugging information.
Start up GDB as usual, using
the name of the local copy of your program as the first argument. (You
may also need the ‘--baud’
option if the serial line is running at anything other than 9600 bps.)
After that, use target
remote to establish
communications with gdbserver.
Its argument is either a
device name (usually a serial device like /dev/ttyb)
or a TCP port descriptor in the form, host:PORT.
For example, (gdb)
target remote /dev/ttyb
communicates with the server via serial line, /dev/ttyb.
target remote the-target:2345
communicates
via a TCP connection to port 2345 on host, the-target.
For TCP connections, you must start up gdbserver
prior to using the target
remote command.
Otherwise you may get an error whose text depends on the host system, but
which usually looks something like ‘Connection
refused’.
Using
the gdbserve.nlm
program
gdbserve.nlm
is a control program for NetWare systems, which allows you to connect your
program with a remote GDB via target
remote.
GDB and gdbserve.nlm
communicate via a serial line, using the standard GDB remote serial protocol.
-
On the target machine
You need to have a copy
of the program you want to debug. gdbserve.nlm
does not need your program’s symbol table, so you can strip the program
if necessary to save space. GDB on the host system does all the symbol
handling. To use the server, you must tell it: how to communicate with
GDB, the name of your program, and the arguments for your program. The
syntax is the following.
load gdbserve
[ BOARD=board ] [ PORT=port ]
[ BAUD=baud ] program [ args ... ]
board
and port
specify the serial line; baud
specifies the baud rate used by the connection. port
and node default
to 0, baud
defaults to 9600 bps. For example, to debug Emacs with the argument ‘foo.txt’and
communicate with GDB over serial port number 2 or board 1 using a 19200
bps connection, use the following.
load gdbserve BOARD=1 PORT=2
BAUD=19200 emacs foo.txt
-
On the GDB host machine
You need an unstripped copy
of your program, since GDB needs symbols and debugging information. Start
up GDB as usual, using the name of the local copy of your program as the
first argument. (You may also need the ‘--baud’
option if the serial line is running at anything other than 9600 bps.
After that, use target
remote to establish
communications with gdbserve.nlm.
Its argument is a device name (usually a serial device, like /dev/ttyb).
For example, (gdb)
target remote /dev/ttyb
communicates with the server via serial line, /dev/ttyb.
GDB
with a remote i960 (Nindy)
Nindy is a ROM Monitor
program for Intel 960 target systems. When GDB is configured to control
a remote Intel 960 using Nindy, you can tell GDB how to connect to the
960 in the following ways:
-
Through command line options
specifying serial port, version of the Nindy protocol, and communications
speed;
-
By responding to a prompt on
startup;
-
By using the target
command at any point during your GDB session. See Commands
for managing targets.
Startup
with Nindy
If you simply start gdb
without using any command-line options, you are prompted for what serial
port to use, before you reach the ordinary GDB prompt:
Attach /dev/ttyNN -- specify
NN, or "quit" to quit:
Respond to the prompt with whatever
suffix (after /dev/tty)
identifies the serial port you want to use. You can, if you choose, simply
start up with no Nindy connection by responding to the prompt with an empty
line. If you do this and later wish to attach to Nindy, use target
(see Commands
for managing targets).
Options
for Nindy
The following are the startup
options for beginning your GDB session with a Nindy-960 board attached.
-rport
Specify the serial port
name of a serial interface to be used to connect to the target system.
This option is only available when GDB is configured for the Intel 960
target architecture. You may specify port
as any of: a full pathname (e.g., -r
/dev/ttya), a
device name in ‘/dev’
(e.g., -rttya),
or simply the unique suffix for a specific tty (e.g., -ra).
-O
(An uppercase letter “O”,
not a zero.) Specify that GDB should use the “old” Nindy monitor protocol
to connect to the target system. This option is only available when GDB
is configured for the Intel 960 target architecture.
Warning:
If you specify ‘-O’,
but are actually trying to connect to a target system that expects the
newer protocol, the connection fails, appearing to be a speed mismatch.
GDB repeatedly attempts to reconnect at several different line speeds.
You can abort this process with an interrupt.
-brk
Specify that GDB should
first send a BREAK
signal to the target system, in an attempt to reset it, before connecting
to a Nindy target.
Warning:
Many target systems do not
have the hardware that this requires; it only works with a few boards.
The standard ‘-b’
option controls the line speed used on the serial port.
Nindy
reset command
reset
For a Nindy target, this
command sends a “break” to the remote target system; this is only useful
if the target has been equipped with a circuit to perform a hard reset
(or some other interesting action) when a break is detected.
Top|Contents|Index|Previous|Next