Gdb for LegOS

Introduction

I've been trying to get gdb going with LegOS for some time now. I've hit a brick wall with it, so I thought I'd open up the development and try and get some more progress made.

I'm stuck because of a combination of:

I'm presenting here what I've achieved so far in the hope that it might be useful to others, and so that I can solicit volunteers to help make progress. It would be a pity to abandon the work I've put in so far.

Even with its many limitations, you might still find this useful. It must be better than inserting 'cputs' everywhere!

Everything here describes the set up for Linux only. I see no reason it shouldn't work just as well (or just as badly!) on Windows.

What Works

These things work reasonably well:

What Doesn't Work

These are the things I know that don't work at all, or work badly. There's probably more, but these should be fixed to make gdb at least usable.

How its Supposed to Work

The idea is to run a version of gdb targeted at the H8/300 CPU on a linux host. This uses the IR Tower to communicate with a debugger stub executing on legOS on the brick. The debugger stub interprets commands sent by gdb and sends results back.

Host Side

Target Side

Download

Download the legOS gdb tarball file gdblegos.tar. This contains sources for the debug stub, and gdbsrv.py. You will also need Python and the Python lnp extension, available here.

Install

  1. cd into your LEGOS_ROOT directory and type tar xf gdblegos.tar. This tar file doesn't overwrite any standard legOS files. This installs the file rcx-stub.c in $LEGOS_ROOT/kernel, rcx-stub.h in $LEGOS_ROOT/include and gdbsrv.py in $LEGOS_ROOT.
  2. The debug stub can be run as part of your application by adding it to your Makefile. I prefer to run it as part of the kernel. To do this, add rcx-stub.c to the KSOURCES macro of Makefile.kernel and rebuild the legOS kernel.
  3. The stub uses lnp host & RCX ports 0x02. If you want to change these, redefine DBG_HOST_PORT and DBG_TARGET_PORT in rcx-stub.h, then rebuild the kernel.
  4. If you have rebuilt your legOS kernel, download it to the RCX in the usual way.
  5. To run gdbsrv.py you will need the Python interpreter and the Python lnp extension pylnp. Pylnp can be downloaded from here.
You've finished with the kernel. You now need to build a debuggable program.

Building Debuggable Programs

Prepare your application for debugging.

  1. It must be compiled with the -g flag. It also helps to turn off the -fomit-frame-pointer and -O2 options. To prevent a non-optimized kernel from being built, I added the following to Makefile.common
     
    COPTDBG  =-g -fno-builtin
    CFLAGSDBG=$(COPTDBG) $(CWARN) $(CINC)
     
    Then modify the application Makefile .o.c rule to read:
     
    %.o: %.c
    	$(CC) $(CFLAGSDBG) -c $*.c -o $*.o
     

    **BUG** Turning off the optimizer causes compile errors when calling motor_a_dir legOS functions. I think this is something to do with inline directives. Running gdb with the optimizer is not a disaster, but it can get confusing.

  2. Your application should call debugInit() near the top of main. This initializes the debugger, and sets up lnp handlers,
  3. To build a COFF file that gdb can read, you need to discover the address at which legOS relocates your application code. The only way I know of getting this information is to write an application that displays the address of its first function. Here's an example:
     
    // Print out start address. Used to find offset for generating coff
    // files.
    #include <unistd.h>
    #include <conio.h>
    
    int main(int argc, char *argv[]) {
        cputw((int)main);
        return 0;
    }  
     
    This displays the relocation address on the LCD (0xb054 on my version of the kernel). Fortunately, you only need to this after a kernel change.

    **BUG** There must be an easier way to get the relocation address than this!

  4. You need to add a rule to build the COFF file used by gdb. Add these lines to Makefile.user:
     
    # Put this line somewhere near the top
    COFFFLAGS=-T$(LEGOS_ROOT)boot/legOS.lds -relax -L$(LEGOS_ROOT)/lib \
              -Ttext <EDITME> --oformat coff-h8300
    
    # Modify the .ds1.o rule to produce a coff file as well.
    %.ds1: %.o $(DOBJECTS) $(DYNAMIC_LDS)
    	$(LD) $(DLDFLAGS) $*.o $(DOBJECTS) $(LIBS) -o $*.ds1 -Ttext $(BASE1)
    	$(LD) $(COFFFLAGS) $*.o $(DOBJECTS) $(LIBS) -o $*.coff 
    
     
    You need to replace <EDITME> with the relocation address discovered earlier. This should produce a .coff file, in addition to the usual .lx file.
  5. Now download the .lx file to the brick in the usual manner.
Now you're ready for a debug session.

A Debug Session

  1. Build a debuggable program as described above, and download it to the brick as usual.
  2. Start the linux lnpd LNP daemon.
  3. Run the linux gdb server gdbsrv.py. You must have Python & the LNP extension installed. (**BUG** Someone might like to recode gdbsrv.py as a C program to remove the Python dependency). Gdbsrv.py defaults to TCP/IP port 6789 and LNP host/target ports 2. These can be overridden on the command line. The -v option turns on some debug info. This is handy for finding out what gdb is sending to legOS. If you restart lnpd, you must restart gdbsrv.py. Normally lnpd and gdbsrv.py can be left running in the background.
  4. Start the H8/300 targeted gdb program. Version 4.17 works best (this is the one supplied with egcs toolchain). The latest version (4.18) works, but it doesn't print stack frames. (**BUG** This bug needs to be reported to the gdb team). Once started, gdb should display the message:
     
    GNU gdb 4.17
    Copyright 1998 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "--host=i686-pc-linux-gnu --target=h8300-hitachi-hms"...
    (gdb) 
     
    Note the --target line.
  5. Gdb needs to be told about its target. Type the command target remote localhost:6789. This sends a message to the debug stub on the brick, via gdbsrv.py and lnpd. The port number (6789) must match that used by gdbsrv.py.
  6. The legOS application needs to respond to the message from gdb. There are a couple of ways of doing this:
  7. When you hit a breakpoint, gdb should wake up and tell you where your program is. Bingo! Gdb is now talking to the debug stub in legOS, which is waiting for commands from gdb. You can examine memory, print the stack frame, set breakpoints & watches, all the usual things (but see the Known Bugs section below before getting too excited). Be patient, the IR tower only runs as 2400 baud, and there'e a fair bit of traffic flowing between gdb & legOS.

If It Doesn't Work

First check the bugs list below. Then try these:

Known Bugs/TODO List

These are the bugs I know about. Some of these come from the h8/300 tool chain, some from the debug stub.

An Alternate Way of Inserting Breakpoints

Markus L. Noga came up with the ingenious idea of using the legOS task manager and a 'branch here' instruction. It works like this: The main problem with this is that the breakpointed task is really continuing to run, even if its in an infinite 'bra here' instruction. . Gdb believes that its stopped, so it tends to restore the original instruction as part of the breakpoint handling code. This means that the task is restarted even while your in the breakpoint.

Disclaimer

You are free to use this information in any way you see fit, subject to the LegOS disclaimers & copyrights. I make no representations about the suitability of this information for any purpose. It is provided "AS-IS" without warranty of any kind, either express or implied. So there.

Contact Me

Question, Comments, Suggestions & Bugs to
lsmithso@hare.demon.co.uk. Or see my Home Page.


(c) Copyright L. Smithson 2000.
$Id: gdb.html,v 1.4 2005/12/06 12:47:54 lsmithso Exp $