Embedding with GNU: the gdb Remote Serial Protocol

it2022-05-05  88

 

 

 

 

 

 

 

 

In September, I introduced thetopic  of  the  GNU  debugger,gdb. 1 I   discussed   how   itsremote   debugging   featurecould be used to debug coderunning  in  an  embedded  sys-tem  connected  to  a  PC  by  a  serialcable,  network  connection,  or  someother means. While commercial prod-ucts with this capability are also avail-able, in my opinion the freely availablegdb is the preferred solution becauseit  provides  portable,  sophisticateddebugging  over  a  broad  range  ofembedded  systems,  including  deviceswith  communications  interfaces  orresource constraints too restrictive forgeneral commercial support.I  also  mentioned  in  that  articlethat, to make remote debugging possi-ble,  gdb  requires  the  services  of  adebugging  stub—a  small  library  ofcode  in  the  debugging  target  thatmanages    registers    and    memory,responds  to  breakpoints,  and  reportsapplication status to gdb via the com-munications  link.  That  article  con-tained excerpts from a debugging stubfor  the  Hitachi  SH-2  microcontroller,but I didn’t actually put enough of thepieces  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  SerialProtocol—gdb’s    standard    remotecommunications  protocol.  Once  youare comfortable with how your proces-sor  handles  breakpoint  and  other108  NOVEMBER 1999  Embedded Systems ProgrammingB I L L   G A T L I F Ff  e  a  t  u  r  eEmbeddingwith GNU: thegdb RemoteSerial ProtocolIn this installment of a series on GNU-based embedded development, theauthor wraps up his discussion of using the GNU debugger, gdb, to debugembedded applications remotely.IEmbedded Systems Programming  NOVEMBER 1999   109exceptions,  then  knowledge  of  a  fewbasic Remote Serial Protocol messagesis all you need to get your embeddedsystem talking to gdb.The protocol definedThe  GDB  Remote  Serial  Protocol(RSP)  is  a  simple,  ASCII  message-based protocol suitable for use on ser-ial  lines,  local  area  networks,  or  justabout   any   other   communicationsmedium that can support at least half-duplex data exchange.RSP  packets  begin  with  a  dollarsign  ($),  followed  by  one  or  moreASCII bytes that make up the messagebeing 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#5aThe    receiver    of    the    packetresponds immediately with either a “+”or  a  “-”  to  indicate  that  the  messagewas received either intact or in error,respectively.A  typical  transaction  involves  gdbissuing a command to a debugging tar-get, which then responds with data, asimple acknowledgement, or a target-specific  error  code.  If  the  latter  isreturned, gdb will report the code tothe  user  and  halt  whatever  activity  iscurrently in progress.The  console    output  message,which  debugging  targets  use  to  printtext  on  the  gdb  console,  is  the  loneexception  to  the  typical  command-response   sequence.   Except   whenanother   command   is   already   inprogress,  this  message  can  be  sentfrom the debugging stub to gdb at anytime.The following paragraphs describethe RSP’s essential commands. For thepurposes 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 commandsHere are the commands to read fromand write to registers.Read registers (“g”)Example: $g#67The  debugger  will  issue  this  com-mand  whenever  it  needs  to  knoweverything  about  the  debugging  tar-get’s  current  register  state.  An  exam-ple target response would be: + $123456789abcdef0...#xx(Register 0 is 0x12345678, register 1 is0x9abcdef0, and so on.)The response is an ordered streamof  bytes  representing  register  dataordered 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, register1 to 0x9abcdef0, and so on.)This message is the complement tothe  read  registers command.  Withthis   command,   gdb   supplies   anordered  stream  of  bytes  representingdata to be stored in the target proces-sor’s registers immediately before pro-gram execution resumes. An exampletarget response:+ $OK#9aWrite register N (“P”)Example: $P10=0040149c#b3(Set register 16 to the value 0x40149c.)When  it  wants  to  set  the  value  ofonly  one  or  two  registers,  gdb  sendsthis  command  instead  of  sending  acomplete register set to the debuggingtarget. The register numbering is thesame as that used in the read regis-ters and write registers commands.An example target response: + $OK#9aBelow  are  the  commands  to  readfrom and write to memory.Read memory (“m”)Example: $m4015bc,2#5a(Read  two  bytes,  starting  at  address0x4015bc.)A read memory command is sent bygdb  to  determine  the  values  of  localand  global  variables,  the  value  of  anopcode  about  to  be  replaced  by  abreakpoint instruction, and any otherkind of information the user requests.The  debugger  generally  is  aware  ofany   endian   issues   present   in   thedebugging  target,  so  the  target  needonly  return  the  result  as  a  simplestream  of  bytes;  gdb  will  reformatthem as appropriate.Debugging stubs on targets that aresensitive  to  data  widths  should  opti-mize the implementation of the writememory and read memory commands asthe  target  architecture  dictates.  Forexample,  certain  peripheral  configu-ration  registers  in  the  Hitachi  SH-2processor family can only be properlyread  and  written  in  16-bit  or  32-bitunits, so a debugging stub for this tar-get should use 16-bit or 32-bit accesseswhenever possible. An example targetresponse: + $2f86#06Write memory (“M”)Example: M4015cc,2:c320#6dIn my opinion the freely available gdb is the preferred solutionbecause it provides portable, sophisticated debugging over a broadrange of embedded systems.C O R B I S / T O M   B R A K E F I E L Dgdb rsp(Write  the  value  0xc320  to  address0x4015cc.)This command is the complementto  the  read   memory command.  Anexample target response: + $OK#9aProgram control commandsProgram  control  commands  are  mes-sages  that  gdb  uses  to  control  thebehavior  of  the  application  beingdebugged.  As  such,  these  commandsare  somewhat  more  complicated  toimplement than the more basic regis-ter-  and  memory-related  commandswe’ve already covered.Get last signal (“?”)Example: $?#3fThis  command  is  used  to  find  outhow the target reached its current state.The  response  is  the  same  as  the  “Lastsignal” response documented below.Step (“s”)Example: $s#73When it wants the target to executeexactly one assembly language instruc-tion,  gdb  issues  a  step command  tothe  debugging  target.  The  debuggersends  this  command  when  the  usertypes stepior stepat the gdb console.An  example  target  response  followsthe continue command description. Continue (“c”)Example: $c#63A  continue  command  is  issuedwhen  gdb  releases  the  application  torun at full speed, as happens when theuser  enters  a  continue command  atthe  gdb  console.  An  example  targetresponse follows.Responses  to  the  step  and  continue  com-mands.  A  debugging  stub  does  notimmediately  respond  to  the  step orcontinue  commands,  other  than  tosend  the  “+”  that  signifies  properreception  of  the  packet.  Instead,  thestub  provides  a  response  when  thenext   breakpoint   is   reached,   therequested  instruction  has  been  exe-cuted  (in  the  case  of  the  step com-mand),  an  exception  occurs,  or  theapplication exits.There  are  two  ways  to  respond  tothese  commands:  a  brief  “last  signal”response, or a more useful “expeditedresponse.”“Last signal” response (“S”)Example: $S05#b8This  is  the  minimum  reply  to  thelast signal, step, and continue com-mands. The “05” in the response canbe any one of the signal values used inthe  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...#xxThis  message  combines  the  infor-mation in a last signalresponse (the“05” in the example message) with keyregister values that gdb may be imme-diately  interested  in.  Designed  toimprove  gdb’s  performance  duringcode stepping, this message allows gdbto  avoid  a  read  registers request  ifthe  values  it  needs  (the  target’s  pro-gram counter and status register, gen-erally) are included in this message.Registers are identified by the samenumbering  scheme  used  in  the  readregisters and write registers com-mands;  in  the  example  provided,  thevalue of register 16 (10 hex) is 0x1238,and register 15 (F hex) contains 0xffe0.Other commandsConsole output (“O”)—optionalExample:$O48656c6c6f2c20776f726c64210a#55(Prints  “Hello,  world!\n”  on  the  gdbconsole)110  NOVEMBER 1999  Embedded Systems Programminggdb rspThis command allows a debuggingstub to send a text message to the gdbconsole.  The  text  to  be  displayed  issent in its hex byte equivalent (‘H’ ==0x48)  and  gdb  will  queue  successivemessages  until  it  sees  a  newline  (‘\n’,0x0a) character.This  message  always  originates  inthe debugging target; gdb never sendsa  console    output  message  to  thedebugging target.Empty response (“”)If a debugging stub encounters a com-mand  it  doesn’t  support  or  under-stand,  it  should  return  an  emptyresponse. This allows gdb to select analternate command if one is available.Example: <an unrecognized command>Target response: + $#00Error response (“E”)When a debugging stub encounters anerror  during  command  processing,  itshould send an error response back togdb. Bus errors and/or illegal address-es  during  memory  operations  areexamples  of  commands  which  maygenerate  an  error  response  from  adebugging stub.Example: <a command that producesan error>Target reponse: +$E01#xxThere  aren’t  any  predefined  errorcodes  in  gdb;  when  gdb  receives  anerror message, it prints it on the con-sole   and   halts   the   operation   inprogress.Putting it all togetherAt this point, I’ve covered individuallyall  the  pieces  necessary  to  get  anembedded  system  talking  to  gdb.  Inthe last article, I covered traps, single-stepping, and a few gdb features; andin  the  previous  section  I  covered  thecommunications  protocol  that  gdbexpects  a  debugging  stub  to  use.  Allwe have left to do now is to throw all ofthese pieces together, right?Actually,  we  must  deal  with  onemore   minor   consideration   beforewe’re  really  ready  to  start  debuggingcode: the chicken-and-egg problem ofactually  getting  the  debugging  stubinto the embedded system for the firsttime,  so  that  gdb  has  something  withwhich to communicate when we turnon the power.Several  methods  of  attacking  thisproblem  exist. 2 To  me,  the  best  wayalways seems to be to place a minimalstub  into  some  kind  of  nonvolatilememory  in  the  target,  and  use  thatcode to both boot the system and helpgdb download the rest of the applica-tion  into  RAM.  Once  gdb  starts  theapplication,  debugging  control  thentransfers  to  a  second  debugging  stublinked with the application itself.Embedded Systems Programming  NOVEMBER 1999   111gdb rspThe   biggest   advantage   of   thisapproach  is  that  it  allows  you  to  con-tinue   developing   the   application-linked  debugging  stub  without  need-ing to reprogram the resident stub inthe   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  toknow  only  the  simplest  commands—read   memory,  write   memory,  writeregister N, and continue—the likeli-hood of a serious bug being present inthis code is fairly low.Another  approach  is  to  place  acomplete debugging stub into the tar-get’s  nonvolatile  memory,  and  use  itfor all debugging activities. This elimi-nates  the  need  to  link  a  debuggingstub  with  the  target  application,  butmay make it more difficult to changethe stub if errors are found or new fea-tures are added.If you’re using a commercial micro-processor evaluation board, you mightnot need to provide a debugging stubat  all—gdb  may  already  support  thevendor’s protocol, or you may be ableto add support to gdb after spending afew  minutes  reverse-engineering  theprotocol  with  a  serial-port  analyzer.Check the vendor’s license agreementif  you  take  this  approach:  you  mayneed  to  sign  a  non-disclosure  agree-ment first, and you will definitely needto  seek  permission  before  releasingyour  gdb  improvements  to  the  com-munity at large.Testing a debugging stubOnce you think you have a debuggingstub ready to go, you’ll want to test itas   thoroughly   as   possible   beforeputting  it  to  work.  Remember,  theonly thing worse than a buggy applica-tion is a buggy development tool.The following is a test procedure Irecommend  you  use  whenever  youmake changes to your debugging stub,to  make  sure  things  are  working  theway they should.First, for convenience, add the fol-lowing lines to your .gdbinit file:set remotedebug 1set remotelogfile gdb_logfileThese commands make gdb display allRSP messages exchanged between thehost and the target, as well as log themto the file gdb_logfile.Next,  connect  gdb  to  the  remotetarget,  and  enter  the  target  remote[port] command.  As  gdb  makes  theconnection,    watch    the    messagesexchanged to make sure that your stubprovides the proper responses to gdb’srequests.During  startup,  your  debuggingstub  should  load  values  into  each  ofthe  target  processor’s  registers.  Usegdb’s  info   registers command  toconfirm that gdb can properly receiveand display these values.Next,  use  gdb’s  set command  tochange a few register values, and makesure  that  the  stub  both  properlyresponds  to  gdb’s  write    registercommand,  and  returns  the  correctresults in subsequent read registerscommands  initiated  when  you  typeinfo registers.Next,  do  the  same  thing  for  a  fewmemory  locations—have  the  stub  setthe locations at startup, and then veri-fy  that  gdb  can  read  and  write  theselocations on request. For example, trythe following:print *(long*)0x1234set *(long*)0x1234=5678print *(long*)0x1234If  everything  works  so  far,  you’reready to try out gdb’s load command.The console will get extremely noisy asgdb  displays  the  multitude  of  writememory commands it uses to transfer atest  application  to  the  target.  You’llwant  to  refer  to  the  log  file  then,  toensure  that  everything  happened  asexpected.  Once  this  has  been  com-pleted, check a few memory locationsin the application’s code space to con-firm  that  the  expected  values  arethere.The test application should containsome gdb console output if your stub112  NOVEMBER 1999  Embedded Systems Programminggdb rspsupports  this  command.  Enter  con-tinue at the gdb console, and see thatthe output appears as you expected.Reset the target, and reload the testapplication. Set a breakpoint immedi-ately before the line that performs theconsole output. Enter continue again,and  verify  both  that  the  applicationstops  where  it’s  supposed  to  and  thatthe  console  output  appears  properlywhen execution resumes.Next  (and  this  can  be  combinedwith the above test), reload the appli-cation,  set  a  breakpoint,  and  stepthrough  a  few  source  lines  with  thestep and stepi commands. Make surethat  local  variables  (viewed  with  thedisplay command) change as expect-ed, and that they don’t change unex-pectedly,  particularly  when  steppingthrough opcodes that branch or jump.Also,  monitor  the  program  counter,stack  pointer,  and  other  register  val-ues, to make sure they change as yourcode dictates they should.At this point, your stub is ready togo.Final thoughtsIn  my  opinion,  gdb  has  no  equal  inthe  debugging  tool  community,  freeor otherwise. In addition to its stabilityand  long  list  of  useful  features,  gdbprovides  the  flexibility  that  today’sembedded developers need at a pricethat’s hard to beat. For those willing toinvest the time necessary to develop adebugging stub, the rewards are botha  thorough  understanding  of  theirembedded  target’s  architecture,  andthe  services  of  a  powerful,  extensibledebugger. espBill Gatliff is a freelance embedded develop-er   and   senior   design   engineer   withKomatsu  Mining  Systems,  Inc.  in  Peoria,IL,  and  is  a  semi-regular  presenter  at  theEmbedded Systems Conferences. He can bereached at bgat@usa.net.References1. Gatliff, Bill, “Embedding with GNU:GNU Debugger,” Embedded SystemsProgramming, September 1999, p. 80.2 Actually, there are no fewer than sevendifferent ways of accomplishing this,depending on which services the targetcan provide itself vs. which services itneeds external help with. For a morethorough presentation on this subject,see the 1999 Embedded SystemsConference Proceedings for a paperentitled “gdb: An Open SourceDebugger for Embedded Development,”by Stan Shebs, PhD, of CygnusSolutions.Embedded Systems Programming  NOVEMBER 1999   113

转载于:https://www.cnblogs.com/linucos/archive/2013/03/01/2939162.html

相关资源:各显卡算力对照表!

最新回复(0)