大运天成赖搏击

进步最重要

导航

Embedding with GNU: the gdb Remote Serial Protocol

 

 

 

 

 

 

 

 

 

In September, I introduced the
topic  of  the  GNU  debugger,
gdb. 1 I   discussed   how   its
remote   debugging   feature
could be used to debug code
running  in  an  embedded  sys-
tem  connected  to  a  PC  by  a  serial
cable,  network  connection,  or  some
other means. While commercial prod-
ucts with this capability are also avail-
able, in my opinion the freely available
gdb is the preferred solution because
it  provides  portable,  sophisticated
debugging  over  a  broad  range  of
embedded  systems,  including  devices
with  communications  interfaces  or
resource constraints too restrictive for
general commercial support.
I  also  mentioned  in  that  article
that, to make remote debugging possi-
ble,  gdb  requires  the  services  of  a
debugging  stub—a  small  library  of
code  in  the  debugging  target  that
manages    registers    and    memory,
responds  to  breakpoints,  and  reports
application status to gdb via the com-
munications  link.  That  article  con-
tained excerpts from a debugging stub
for  the  Hitachi  SH-2  microcontroller,
but I didn’t actually put enough of the
pieces  together  to  show  how  a  com-
plete debugging stub would work.
I’ll  fix  that  this  month  by  present-
ing  in  detail  the  GDB  Remote  Serial
Protocol—gdb’s    standard    remote
communications  protocol.  Once  you
are comfortable with how your proces-
sor  handles  breakpoint  and  other
108  NOVEMBER 1999  Embedded Systems Programming
B I L L   G A T L I F F
f  e  a  t  u  r  e
Embedding
with GNU: the
gdb Remote
Serial Protocol
In this installment of a series on GNU-based embedded development, the
author wraps up his discussion of using the GNU debugger, gdb, to debug
embedded applications remotely.
I
Embedded Systems Programming  NOVEMBER 1999   109
exceptions,  then  knowledge  of  a  few
basic Remote Serial Protocol messages
is all you need to get your embedded
system talking to gdb.
The protocol defined
The  GDB  Remote  Serial  Protocol
(RSP)  is  a  simple,  ASCII  message-
based protocol suitable for use on ser-
ial  lines,  local  area  networks,  or  just
about   any   other   communications
medium that can support at least half-
duplex data exchange.
RSP  packets  begin  with  a  dollar
sign  ($),  followed  by  one  or  more
ASCII bytes that make up the message
being sent, and end with a pound sign
(#) and two ASCII hex characters rep-
resenting  the  message’s  checksum.
For  example,  the  following  is  a  com-
plete RSP packet:
$m4015bc,2#5a
The    receiver    of    the    packet
responds immediately with either a “+”
or  a  “-”  to  indicate  that  the  message
was received either intact or in error,
respectively.
A  typical  transaction  involves  gdb
issuing a command to a debugging tar-
get, which then responds with data, a
simple acknowledgement, or a target-
specific  error  code.  If  the  latter  is
returned, gdb will report the code to
the  user  and  halt  whatever  activity  is
currently in progress.
The  console    output  message,
which  debugging  targets  use  to  print
text  on  the  gdb  console,  is  the  lone
exception  to  the  typical  command-
response   sequence.   Except   when
another   command   is   already   in
progress,  this  message  can  be  sent
from the debugging stub to gdb at any
time.
The following paragraphs describe
the RSP’s essential commands. For the
purposes of this tutorial, I have divid-
ed the messages into three categories:
register-  and  memory-related  com-
mands,  program  control  commands,
and other commands.
Register- and memory-
related commands
Here are the commands to read from
and write to registers.
Read registers (“g”)
Example: $g#67
The  debugger  will  issue  this  com-
mand  whenever  it  needs  to  know
everything  about  the  debugging  tar-
get’s  current  register  state.  An  exam-
ple target response would be:
+ $123456789abcdef0...#xx
(Register 0 is 0x12345678, register 1 is
0x9abcdef0, and so on.)
The response is an ordered stream
of  bytes  representing  register  data
ordered per the definition in the tar-
get’s  macro  file,  gdb/config/<arch>/
tm-<arch>.h  (for  example,  gdb/con-
fig/sh/tm-sh.h for the Hitachi SH).
Write registers (“G”)
Example: $G123456789abcdef0...#xx
(Set register 0 to 0x12345678, register
1 to 0x9abcdef0, and so on.)
This message is the complement to
the  read  registers command.  With
this   command,   gdb   supplies   an
ordered  stream  of  bytes  representing
data to be stored in the target proces-
sor’s registers immediately before pro-
gram execution resumes. An example
target response:
+ $OK#9a
Write register N (“P”)
Example: $P10=0040149c#b3
(Set register 16 to the value 0x40149c.)
When  it  wants  to  set  the  value  of
only  one  or  two  registers,  gdb  sends
this  command  instead  of  sending  a
complete register set to the debugging
target. The register numbering is the
same as that used in the read regis-
ters and write registers commands.
An example target response:
+ $OK#9a
Below  are  the  commands  to  read
from and write to memory.
Read memory (“m”)
Example: $m4015bc,2#5a
(Read  two  bytes,  starting  at  address
0x4015bc.)
A read memory command is sent by
gdb  to  determine  the  values  of  local
and  global  variables,  the  value  of  an
opcode  about  to  be  replaced  by  a
breakpoint instruction, and any other
kind of information the user requests.
The  debugger  generally  is  aware  of
any   endian   issues   present   in   the
debugging  target,  so  the  target  need
only  return  the  result  as  a  simple
stream  of  bytes;  gdb  will  reformat
them as appropriate.
Debugging stubs on targets that are
sensitive  to  data  widths  should  opti-
mize the implementation of the write
memory and read memory commands as
the  target  architecture  dictates.  For
example,  certain  peripheral  configu-
ration  registers  in  the  Hitachi  SH-2
processor family can only be properly
read  and  written  in  16-bit  or  32-bit
units, so a debugging stub for this tar-
get should use 16-bit or 32-bit accesses
whenever possible. An example target
response:
+ $2f86#06
Write memory (“M”)
Example: M4015cc,2:c320#6d
In my opinion the freely available gdb is the preferred solution
because it provides portable, sophisticated debugging over a broad
range of embedded systems.
C O R B I S / T O M   B R A K E F I E L D
gdb rsp
(Write  the  value  0xc320  to  address
0x4015cc.)
This command is the complement
to  the  read   memory command.  An
example target response:
+ $OK#9a
Program control commands
Program  control  commands  are  mes-
sages  that  gdb  uses  to  control  the
behavior  of  the  application  being
debugged.  As  such,  these  commands
are  somewhat  more  complicated  to
implement than the more basic regis-
ter-  and  memory-related  commands
we’ve already covered.
Get last signal (“?”)
Example: $?#3f
This  command  is  used  to  find  out
how the target reached its current state.
The  response  is  the  same  as  the  “Last
signal” response documented below.
Step (“s”)
Example: $s#73
When it wants the target to execute
exactly one assembly language instruc-
tion,  gdb  issues  a  step command  to
the  debugging  target.  The  debugger
sends  this  command  when  the  user
types stepior stepat the gdb console.
An  example  target  response  follows
the continue command description.
Continue (“c”)
Example: $c#63
A  continue  command  is  issued
when  gdb  releases  the  application  to
run at full speed, as happens when the
user  enters  a  continue command  at
the  gdb  console.  An  example  target
response follows.
Responses  to  the  step  and  continue  com-
mands.  A  debugging  stub  does  not
immediately  respond  to  the  step or
continue  commands,  other  than  to
send  the  “+”  that  signifies  proper
reception  of  the  packet.  Instead,  the
stub  provides  a  response  when  the
next   breakpoint   is   reached,   the
requested  instruction  has  been  exe-
cuted  (in  the  case  of  the  step com-
mand),  an  exception  occurs,  or  the
application exits.
There  are  two  ways  to  respond  to
these  commands:  a  brief  “last  signal”
response, or a more useful “expedited
response.”
“Last signal” response (“S”)
Example: $S05#b8
This  is  the  minimum  reply  to  the
last signal, step, and continue com-
mands. The “05” in the response can
be any one of the signal values used in
the  standard  POSIX  signal()  func-
tion call. For example, “5” is a break-
point  exception,  “10”  is  a  bus  error,
and so forth.
Expedited response (“T”)
Example: $T0510:1238;F:FFE0...#xx
This  message  combines  the  infor-
mation in a last signalresponse (the
“05” in the example message) with key
register values that gdb may be imme-
diately  interested  in.  Designed  to
improve  gdb’s  performance  during
code stepping, this message allows gdb
to  avoid  a  read  registers request  if
the  values  it  needs  (the  target’s  pro-
gram counter and status register, gen-
erally) are included in this message.
Registers are identified by the same
numbering  scheme  used  in  the  read
registers and write registers com-
mands;  in  the  example  provided,  the
value of register 16 (10 hex) is 0x1238,
and register 15 (F hex) contains 0xffe0.
Other commands
Console output (“O”)—optional
Example:
$O48656c6c6f2c20776f726c64210a#55
(Prints  “Hello,  world!\n”  on  the  gdb
console)
110  NOVEMBER 1999  Embedded Systems Programming
gdb rsp
This command allows a debugging
stub to send a text message to the gdb
console.  The  text  to  be  displayed  is
sent in its hex byte equivalent (‘H’ ==
0x48)  and  gdb  will  queue  successive
messages  until  it  sees  a  newline  (‘\n’,
0x0a) character.
This  message  always  originates  in
the debugging target; gdb never sends
a  console    output  message  to  the
debugging target.
Empty response (“”)
If a debugging stub encounters a com-
mand  it  doesn’t  support  or  under-
stand,  it  should  return  an  empty
response. This allows gdb to select an
alternate command if one is available.
Example: <an unrecognized command>
Target response: + $#00
Error response (“E”)
When a debugging stub encounters an
error  during  command  processing,  it
should send an error response back to
gdb. Bus errors and/or illegal address-
es  during  memory  operations  are
examples  of  commands  which  may
generate  an  error  response  from  a
debugging stub.
Example: <a command that produces
an error>
Target reponse: +$E01#xx
There  aren’t  any  predefined  error
codes  in  gdb;  when  gdb  receives  an
error message, it prints it on the con-
sole   and   halts   the   operation   in
progress.
Putting it all together
At this point, I’ve covered individually
all  the  pieces  necessary  to  get  an
embedded  system  talking  to  gdb.  In
the last article, I covered traps, single-
stepping, and a few gdb features; and
in  the  previous  section  I  covered  the
communications  protocol  that  gdb
expects  a  debugging  stub  to  use.  All
we have left to do now is to throw all of
these pieces together, right?
Actually,  we  must  deal  with  one
more   minor   consideration   before
we’re  really  ready  to  start  debugging
code: the chicken-and-egg problem of
actually  getting  the  debugging  stub
into the embedded system for the first
time,  so  that  gdb  has  something  with
which to communicate when we turn
on the power.
Several  methods  of  attacking  this
problem  exist. 2 To  me,  the  best  way
always seems to be to place a minimal
stub  into  some  kind  of  nonvolatile
memory  in  the  target,  and  use  that
code to both boot the system and help
gdb download the rest of the applica-
tion  into  RAM.  Once  gdb  starts  the
application,  debugging  control  then
transfers  to  a  second  debugging  stub
linked with the application itself.
Embedded Systems Programming  NOVEMBER 1999   111
gdb rsp
The   biggest   advantage   of   this
approach  is  that  it  allows  you  to  con-
tinue   developing   the   application-
linked  debugging  stub  without  need-
ing to reprogram the resident stub in
the   target’s   nonvolatile   memory,
which is a real bonus if the only non-
volatile memory available is one-time-
programmable  ROM.  Furthermore,
because  the  resident  stub  needs  to
know  only  the  simplest  commands—
read   memory,  write   memory,  write
register N, and continue—the likeli-
hood of a serious bug being present in
this code is fairly low.
Another  approach  is  to  place  a
complete debugging stub into the tar-
get’s  nonvolatile  memory,  and  use  it
for all debugging activities. This elimi-
nates  the  need  to  link  a  debugging
stub  with  the  target  application,  but
may make it more difficult to change
the stub if errors are found or new fea-
tures are added.
If you’re using a commercial micro-
processor evaluation board, you might
not need to provide a debugging stub
at  all—gdb  may  already  support  the
vendor’s protocol, or you may be able
to add support to gdb after spending a
few  minutes  reverse-engineering  the
protocol  with  a  serial-port  analyzer.
Check the vendor’s license agreement
if  you  take  this  approach:  you  may
need  to  sign  a  non-disclosure  agree-
ment first, and you will definitely need
to  seek  permission  before  releasing
your  gdb  improvements  to  the  com-
munity at large.
Testing a debugging stub
Once you think you have a debugging
stub ready to go, you’ll want to test it
as   thoroughly   as   possible   before
putting  it  to  work.  Remember,  the
only thing worse than a buggy applica-
tion is a buggy development tool.
The following is a test procedure I
recommend  you  use  whenever  you
make changes to your debugging stub,
to  make  sure  things  are  working  the
way they should.
First, for convenience, add the fol-
lowing lines to your .gdbinit file:
set remotedebug 1
set remotelogfile gdb_logfile
These commands make gdb display all
RSP messages exchanged between the
host and the target, as well as log them
to the file gdb_logfile.
Next,  connect  gdb  to  the  remote
target,  and  enter  the  target  remote
[port] command.  As  gdb  makes  the
connection,    watch    the    messages
exchanged to make sure that your stub
provides the proper responses to gdb’s
requests.
During  startup,  your  debugging
stub  should  load  values  into  each  of
the  target  processor’s  registers.  Use
gdb’s  info   registers command  to
confirm that gdb can properly receive
and display these values.
Next,  use  gdb’s  set command  to
change a few register values, and make
sure  that  the  stub  both  properly
responds  to  gdb’s  write    register
command,  and  returns  the  correct
results in subsequent read registers
commands  initiated  when  you  type
info registers.
Next,  do  the  same  thing  for  a  few
memory  locations—have  the  stub  set
the locations at startup, and then veri-
fy  that  gdb  can  read  and  write  these
locations on request. For example, try
the following:
print *(long*)0x1234
set *(long*)0x1234=5678
print *(long*)0x1234
If  everything  works  so  far,  you’re
ready to try out gdb’s load command.
The console will get extremely noisy as
gdb  displays  the  multitude  of  write
memory commands it uses to transfer a
test  application  to  the  target.  You’ll
want  to  refer  to  the  log  file  then,  to
ensure  that  everything  happened  as
expected.  Once  this  has  been  com-
pleted, check a few memory locations
in the application’s code space to con-
firm  that  the  expected  values  are
there.
The test application should contain
some gdb console output if your stub
112  NOVEMBER 1999  Embedded Systems Programming
gdb rsp
supports  this  command.  Enter  con-
tinue at the gdb console, and see that
the output appears as you expected.
Reset the target, and reload the test
application. Set a breakpoint immedi-
ately before the line that performs the
console output. Enter continue again,
and  verify  both  that  the  application
stops  where  it’s  supposed  to  and  that
the  console  output  appears  properly
when execution resumes.
Next  (and  this  can  be  combined
with the above test), reload the appli-
cation,  set  a  breakpoint,  and  step
through  a  few  source  lines  with  the
step and stepi commands. Make sure
that  local  variables  (viewed  with  the
display command) change as expect-
ed, and that they don’t change unex-
pectedly,  particularly  when  stepping
through opcodes that branch or jump.
Also,  monitor  the  program  counter,
stack  pointer,  and  other  register  val-
ues, to make sure they change as your
code dictates they should.
At this point, your stub is ready to
go.
Final thoughts
In  my  opinion,  gdb  has  no  equal  in
the  debugging  tool  community,  free
or otherwise. In addition to its stability
and  long  list  of  useful  features,  gdb
provides  the  flexibility  that  today’s
embedded developers need at a price
that’s hard to beat. For those willing to
invest the time necessary to develop a
debugging stub, the rewards are both
a  thorough  understanding  of  their
embedded  target’s  architecture,  and
the  services  of  a  powerful,  extensible
debugger. esp
Bill Gatliff is a freelance embedded develop-
er   and   senior   design   engineer   with
Komatsu  Mining  Systems,  Inc.  in  Peoria,
IL,  and  is  a  semi-regular  presenter  at  the
Embedded Systems Conferences. He can be
reached at bgat@usa.net.
References
1. Gatliff, Bill, “Embedding with GNU:
GNU Debugger,” Embedded Systems
Programming, September 1999, p. 80.
2 Actually, there are no fewer than seven
different ways of accomplishing this,
depending on which services the target
can provide itself vs. which services it
needs external help with. For a more
thorough presentation on this subject,
see the 1999 Embedded Systems
Conference Proceedings for a paper
entitled “gdb: An Open Source
Debugger for Embedded Development,”
by Stan Shebs, PhD, of Cygnus
Solutions.
Embedded Systems Programming  NOVEMBER 1999   113

posted on 2013-03-01 17:43  linucos  阅读(1144)  评论(0编辑  收藏  举报