Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
dev:gdbstub [2008/06/04 07:41]
stefanha
dev:gdbstub [2010/03/28 21:27] (current)
stefanha
Line 2: Line 2:
  
 ===== Overview ===== ===== Overview =====
-You can use the [[http://​www.gnu.org/​software/​gdb/​|GNU Project Debugger (GDB)]] to debug gPXE.  ​In order to do this, you must either ​have two computers or run gPXE under virtualization (e.g. [[http://bellard.org/qemu/|QEMU]]).+You can use the [[http://​www.gnu.org/​software/​gdb/​|GNU Project Debugger (GDB)]] to debug gPXE.  ​You either ​need two computers or virtualization ​software ​(e.g. [[http://qemu.org/​|QEMU]]).  One host runs gPXE while the other runs GDB.
  
-When using two computers, one computer will run gPXE while the other will run GDB.  ​GDB communicates with gPXE over the serial ​port.  You will need a null modem serial cable to connect the two computers. +gPXE supports debugging via serial port or over the network.  ​For serial, you need a null modem serial cable.  ​For network, ​you need the machine to be connected to a network with UDP port 43770 traffic allowed.
- +
-===== Status ===== +
-This page documents the GDB remote debugging functionality in mainline gPXE.  ​These instructions apply to the latest git version of gPXE.  If you are not sure which version you are using, install [[http://​git.or.cz/​|git]] and grab the latest gPXE code: +
-<​code>​ +
-$ git clone git://​git.etherboot.org/​scm/​gpxe.git +
-</​code>​+
  
 ===== Building with GDB enabled ===== ===== Building with GDB enabled =====
Line 21: Line 15:
  */  */
  
-#​define  ​GDBSTUB ​                /* Remote GDB debugging */+#​define  ​GDBSERIAL ​              /* Remote GDB debugging ​over serial */ 
 +#​define ​ GDBUDP ​                 /* Remote GDB debugging over UDP 
 +                                  * (both may be set) */
  
 /* @END general.h */ /* @END general.h */
 </​code>​ </​code>​
  
-This file overrides ''​src/​config.h''​ but is not under version control.  ​That means you will never accidentally commit a patch that enables ''​GDBSTUB''​.+This file overrides ''​src/​config.h''​ but is not under version control.  ​Therefore ​you will never accidentally commit a patch that enables ​GDB debugging. 
 +Sometimes you also need to remove/​define ​''​GDBSERIAL''​ in ''​config/​general.h'' ​to get serial debugging to work. 
 +<​code>#​define GDBSERIAL ​              /* Remote GDB debugging over serial */ 
 +</​code>​
  
 Now build gPXE: Now build gPXE:
Line 34: Line 33:
 </​code>​ </​code>​
  
-You also need to build an ELF file that GDB can load symbols ​from:+Notice that the ''​bin''​ directory contains not only the gPXE image you built, but also a file with the same name but ending with ''​.tmp''​. ​ This file is an ELF with debugging symbols ​that we can load in GDB. 
 + 
 +===== Using GDB remote debugging ===== 
 +==== Breaking into the debugger ==== 
 +You can break into the debugger ​from the gPXE shell with the ''​gdbstub''​ command:
 <​code>​ <​code>​
-$ make bin/gpxe.hd.tmp+Usage: 
 +  gdbstub <​transport>​ [<​options>​...] 
 + 
 +Start remote debugging using one of the following transports:​ 
 +  serial ​          use serial port (if compiled in) 
 +  udp <​interface> ​ use UDP over network interface (if compiled in)
 </​code>​ </​code>​
  
-Once ''​bin/​gpxe.hd.tmp'' ​existsthe ''​make'' ​command will update it and you do not need to use ''​make bin/gpxe.hd.tmp'' ​again.+For example: 
 +<​code>​ 
 +gdbstub serial ​    # debug via serial port 
 +gdbstub udp net0   # debug over network interface ​'net0' 
 +</​code>​ 
 + 
 +gPXE will be waiting for a connection from a remote GDB. 
 + 
 +==== Connecting with GDB ==== 
 +First we load debugging symbols: 
 +<​code>​ 
 +$ cd gpxe/src 
 +$ gdb 
 +(gdb) file bin/​gpxe.hd.tmp ​  # or equivalent for your gPXE image filename 
 +</​code>​ 
 + 
 +The ''​.tmp''​ file must correspond to your gPXE image. ​ For example, ''​gpxe.dsk'' ​-> ''​gpxe.dsk.tmp'',​ ''​gpxe.pxe''​ -> ''​gpxe.pxe.tmp'', ​and ''​gpxe.usb''​ -> ''​gpxe.hd.tmp''​
 + 
 +Next you should set up the serial port in GDB if you are debugging via serial. ​ The ''​set remotebaud N''​ command is used to set the serial port baud rate to ''​N''​. ​ See [[http://​sourceware.org/​gdb/​current/​onlinedocs/​gdb/​Remote-Configuration.html#​Remote-Configuration|Remote Configuration]] in the GDB Manual. 
 + 
 +Now connect to gPXE, which is already waiting since we entered the ''​gdbstub''​ command in the gPXE shell: 
 +<​code>​ 
 +target remote /​dev/​ttyS0 ​           # for serial debugging 
 +target remote udp:​192.168.1.2:​43770 # for network debugging on gPXE 
 +                                    # host 192.168.1.2 
 +target remote 192.168.1.2:​43770 ​    # if you are forwarding over TCP 
 +                                    # using QEMU -serial 
 +</​code>​ 
 + 
 +You should soon see the normal GDB prompt and be able to start debugging. ​ If you have trouble, try the ''​set debug remote 1''​ GDB command to see the traffic between GDB and gPXE.
  
-===== Using GDB remote debugging ===== 
 ==== QEMU ==== ==== QEMU ====
-Run gPXE in QEMU with the serial port redirected to a TCP port:+To run gPXE in QEMU with the serial port redirected to a TCP port:
 <​code>​ <​code>​
-$ qemu -serial tcp::4444,server bin/​gpxe.usb+$ qemu -serial tcp::43770,server bin/​gpxe.usb
 </​code>​ </​code>​
  
-Now you can connect with GDB from another terminal:+==== Breaking into the debugger programmatically ==== 
 +You can break into the debugger without using the gPXE shell. ​ The following breaks into the debugger for serial debugging:
 <​code>​ <​code>​
-$ gdb +#include <gpxe/gdbserial.h>​ 
-(gdb) file bin/gpxe.hd.tmp +#include <gpxe/gdbstub.h> 
-(gdbtarget remote localhost:​4444+[...] 
 +gdbstub_start ​gdbserial_configure() ​);
 </​code>​ </​code>​
  
-==== Two computers ​==== +Here is the same thing for network debugging:​ 
-**(Untested)** Connect the two computers using a null modem serial cable.  ​The gPXE serial port settings ​can be changed ​in ''​src/config.h''​.  ​The GDB serial ​port settings can be changed ​using the [[http://​sourceware.org/​gdb/​current/​onlinedocs/​gdb_18.html#​SEC173|"​set remotebaud"​ command]].+<​code>​ 
 +#include <​gpxe/​gdbudp.h>​ 
 +#include <​gpxe/​gdbstub.h>​ 
 +[...] 
 +struct sockaddr_in sa 
 +    /* FILL IN LISTEN ADDR/PORT OR ZERO FOR DEFAULTS */ 
 +}; 
 +gdbstub_start ( gdbudp_configure ( "​net0",​ &sa ) ); 
 +</​code>​ 
 + 
 +===== Limitations ===== 
 +Interrupt ​(''​CTRL + C''​in GDB does not work.  ​Implementing this is not possible since gPXE does not use interrupts. ​ This means that you cannot hit ''​CTRL + C''​ if gPXE is in an infinite loop. 
 + 
 +Debugging works for 32-bit protected mode.  There is no support for 16-bit real-mode. 
 + 
 +Debugging ​can safely ​be used after ''​initialise()''​ and ''​startup()''​ have been called ​in ''​main()''​ If you need to use it during ​''​initialise()''​ or ''​startup()'',​ take special care and modify the code if necessary (e.g. by hardcoding calls to initialize the GDB stub before the thing you are debugging). 
 + 
 +Backtraces are sometimes wrong.  ​I believe this is because the optimization settings gPXE is built with confuse ​GDB
 + 
 +When debugging over the network, gPXE will drop network packets while you are in the debugger. ​ This means you should use serial ​debugging if you need to minimize side-effects on gPXE.  You may also try using a dedicated NIC for debugging so that traffic to the primary NIC is not dropped while you are in the debugger Note that traffic may still be dropped if you stay in the debugger so long that the receive buffers fill up (i.e. gPXE is not running while you are in the debugger).
  
-Boot the gPXE machine ​and connect with GDB from the other machine:+===== GDB usage ==== 
 +  * **Breakpoint** (''​b''​) marks code where execution should stop and break into the debugger. ​ To break on an instruction'​s virtual memory address, use ''​b *ADDR''​.
 <​code>​ <​code>​
-gdb +(gdb) b http_rx_response 
-(gdb) file bin/gpxe.hd.tmp +Breakpoint 1 at 0x25de: file net/​tcp/​http.c,​ line 157. 
-(gdb) target remote ​/dev/ttyS0+</​code>​ 
 + 
 +  * **Continue** (''​c''​) resumes execution until the next breakpoint. 
 +<​code>​ 
 +(gdb) 
 +Continuing. 
 + 
 +Breakpoint 1, http_rx_response (http=0x595e4,​ response=0x594b4 "HTTP/1.0 200 OK") at net/​tcp/​http.c:157 
 +157     ​static int http_rx_response ( struct http_request *http, char *response ) { 
 +(gdb) 
 +</code> 
 + 
 +  * **Step** (''​s''​),​ **next** (''​n''​),​ **finish** (''​fin''​),​ and **step instruction** (''​si''​) resume execution over a limited region of code.  Step executes until the next line of source code, it steps inside function calls. ​ Next executes until the next line of source code in the function, thereby stepping over function calls. ​ Finish executes the remainder of the current function. ​ Step instruction executes the current machine instruction. 
 + 
 +  * **Backtrace** (''​bt''​) shows the call stack. ​ Some stack frames may not be detected correctly by GDB due to the compiler optimisations used when building gPXE. 
 +<​code>​ 
 +(gdb) bt 
 +#0  http_rx_response (http=0x595e4,​ response=0x594b4 "HTTP/1.0 200 OK") at net/​tcp/​http.c:​157 
 +#1  0x0000282a in http_socket_deliver_iob (socket=<​value optimized out>, iobuf=0x5a3ac,​ meta=<​value optimized out>) 
 +    at net/​tcp/​http.c:​363 
 +#2  0x00034118 in xfer_deliver_iob_meta (xfer=<​value optimized out>, iobuf=0x5a3ac,​ meta=0xa4aa0) at core/​xfer.c:​143 
 +#3  0x00035247 in tcp_rx (iobuf=0x5a3ac,​ st_src=0xbe470,​ st_dest=<​value optimized out>, pshdr_csum=<​value optimized out>) 
 +    at net/​tcp.c:​768 
 +#4  0x00002510 in tcpip_rx (iobuf=0x5a3ac,​ tcpip_proto=<​value optimized out>, st_src=0xbe470,​ st_dest=0xbe450,​ 
 +    pshdr_csum=<​value optimized out>) at net/​tcpip.c:​54 
 +#5  0x000be470 in ?? () 
 +</​code>​ 
 + 
 +  * **Local variables** (''​info locals''​) can be displayed though their values may be unavailable due to compiler optimizations. 
 +<​code>​ 
 +(gdb) info locals 
 +spc = <value optimized out> 
 +rc = <value optimized out> 
 +</​code>​ 
 + 
 +  * **CPU registers** (''​i r''​) shows many but not all of the registers. 
 + 
 +  * **Print** (''​p''​) shows the value of program variables and arbitrary expressions in C-like syntax (see [[http://​sourceware.org/​gdb/​current/​onlinedocs/​gdb/​Data.html|GDB Manual]]). 
 +<​code>​ 
 +(gdb) p response ​                    
 +$1 = 0x594b4 "​HTTP/​1.0 200 OK" ​      
 +(gdb) p *http                        
 +$2 = {refcnt = {refcnt = 2, free = 0x28e8 <​http_free>​},​ xfer = {intf = {dest = 0x595c8, refcnt = 0x595e4}, op = 0x42e20}, 
 +  uri = 0x59554, socket = {intf = {dest = 0x59434, refcnt = 0x595e4}, op = 0x42e38}, process = {list = {next = 0x59608, 
 +      prev = 0x59608}, step = 0x286b <​http_step>,​ refcnt = 0x595e4}, response = 0, content_length = 0, rx_len = 0, 
 +  rx_state = HTTP_RX_RESPONSE,​ linebuf = {data = 0x594b4 "​HTTP/​1.0 200 OK", len = 15, ready = 1}}
 </​code>​ </​code>​
  
 ===== GDB documentation ===== ===== GDB documentation =====
-  * [[http://​sourceware.org/​gdb/​current/​onlinedocs/​gdb_toc.html|Debugging with GDB (official manual)]]+  * [[http://​sourceware.org/​gdb/​current/​onlinedocs/​gdb/index.html|Debugging with GDB (official manual)]]
   * [[http://​darkdust.net/​files/​GDB%20Cheat%20Sheet.pdf|A cheatsheet]],​ note that there are several others [[http://​google.com/​search?​q=gdb+cheat+sheet|available]].   * [[http://​darkdust.net/​files/​GDB%20Cheat%20Sheet.pdf|A cheatsheet]],​ note that there are several others [[http://​google.com/​search?​q=gdb+cheat+sheet|available]].
  
-===== Getting help ===== +
-You can email the [[https://​lists.sourceforge.net/​lists/​listinfo/​etherboot-developers|Etherboot-Developers]] list or ask on the [[http://​www.etherboot.org/​wiki/​contact|IRC channel]].+

QR Code
QR Code dev:gdbstub (generated for current page)