SoM-5282EM GDB Support for the Eclipse MI interface

Nathan Z. Gustavson

January 30, 2006



Introduction

Debugging Linux applications is traditionally done using gdb, the GNU debugger. This is a large, powerful, low level program which can be used do debug any hardware achitecture, provided it's has a port written for it. Writing a port consists of creating several .c and .h modules inside of the gdb program, and is largely undocumented. In the case of the MCF-5282 processor, a gdb port already existed, but didn't work quite right. This document is a record of the work done to build up gdb for the 5282 to a working state, and, from there, how to use it.

History of the Coldfire gdb target

Initially, gdb support for the Coldfire was released as a patch for gdb 4.18 which provided debugging via the BDM interface, or using gdbserver. This all worked very well, but gdb 4.18 was released before the invention of the MI (machine interface), which didn't come into play until the 6.x series. The MI was designed to be a more reliable, lightweight method for programs to interact with gdb directly, rather than using the old ASCII interface. Now, with the maturation of the Eclipse CDT, open tools are available for interfacing with gdb, but rely on this interface, hence the push to move the 5282 tools to a newer version.

On 2004-05-30 a patch was released for gdb 6.1. This patch makes the BDM interface work correctly, but when gdbserver was used, it refused to set breakpoints saying“software breakpoints not supported” which made it pretty useless for remote debugging.

This problem has already been solved by Andrea Tarani, who had released a patch to the uClinux mailing list.

http://mailman.uclinux.org/pipermail/uclinux-dev/2004-March/024885.html

From the archives it is unclear what gdb series this is intended for, but it seems to most likely be referring to 6.0, or be intended to be applied to any of them.

Problems

After applying the patches detailed above to gdb 6.1, the problems discussed above did go away as advertised. This also provided a MI, which Eclipse could hook to. Unfortunately, initial experimentation with Eclipse revealed another problem, which wasn't as obvious just using the ASCII setting.

The Eclipse CDT attempts to backtrace a debugged the program before it has entered it's “main” function. When this was done on a remote Coldfire target, it would lock gdb, and cause a long pause followed by a remote kernel oops.

Analysis

In a normal, “healthy” backtrace, get_prev_frame is called inside, or under, the main function of the debugged program. GDB then looks at the current pc value and compares it to it's dwarf debug information. Here it identifies the main arguments as being the highest level frames and doesn't bother to even attempt to unwind past them. Hence unwinds correctly halt after the retrieving the oldest frame.

However, when the frame exists outside of a defined Dwarf section, the architecture modules attempt to figure out a previous pc value based on the frame and stack pointers during the unwind. For reasons still unidentified, this does not work with the uClinux Coldfire platform. What happens, is it identifies the frame pointer as being invalid (but not zero), then tries to pull the previous pc off the stack. What it actually pulls, however, is argc. It appears to be looking for a zero value at this memory location to signify the end of an unwind, but it doesn't receive it, so it continues the backtrace. GDB then parses back through the stack in successive iterations, pulling the argv pointer, than who knows what, dereferencing memory locations on the remote target indefinately until it crashes.

The most direct solution would be to figure out why gdb is expecting a zero frame or stack pointer, and why the remote OS isn't providing it. The expectation of a 0 frame pointer at the end of the frame list seems to be pretty standard across architecures. This option was pursued for some time, but abandoned before completion when it became apparent that this solution does not even necessarily exist, since it would be asking gdb to interprete information that is not in any kind of defined state.

Another possible solution (Suggested by Daniel Jacobson) is to implement a Dwarf CFI entry symbol in the startup section of Coldfire code, which would have the same effect as the Dwarf code inside main, preventing the target from attempting to unwind itself in the first place. This is probably the cleanest and most robust approach, and should probably be implemented across most architectures.

http://sourceware.org/cgi-bin/cvsweb.cgi/src/libgloss/m32c/crt0.S?rev=1.2&content-type=text/x-cvsweb-markup&cvsroot=src

ftp://ftp.freestandards.org/pub/dwarf/dwarf-2.0.0.pdf

A third alternative is to use the deprecated_inside_entry_file function, which was designed to identify startup frames and refuse to unwind them directly in get_prev_frame. In gdb 6.1, this is a depreciated solution as it was found to cause problems in some architectures. Also, it's certainly not required on many targets, so it's high level call in frame.c is probably not ideal.

Solution

The third solution from the analysis was chosen.

This is a bit “quick and dirty” but it fixes the backtrace problem and makes the Coldfire gdb compatible with Eclipse. The Dwarf approach was decided against because it wouldn't fit in the current timeline for the project.

Note that it's seems a little slower than desired for some reason, and could probably use some future tweaks when time permits.

Taking the specific conditional out of the deprecated_inside_entry_file function that is catching the problem and moving into the architecture specific files (if possible) would probably elimate some code and would certainly make more sense to the programs model.

building m68k-elf-gdb

In theory, GDB provides a powerful self-configuring environment which generates it's own Makefiles, builds itself and installs itself.

My personal experience, however, is that this only works if you know what your doing. Although the authors have done a very good job making it robust, it still has it's occasional hiccup.

The following are step by step instructions for building gdb on a Linux or Cygwin(Windows) platform.

  1. Get a copy of the tarball you intend to use. At the time of this writing, gdb-6.4 was the newest, but patches don't yet exist to support our target. For historical reasons, this build uses gdb-6.1.

    ftp://sources.redhat.com/pub/gdb/old-releases/gdb-6.1.tar.bz2
  2. Unpack the tarball into an area where you have write permissions (on a Windows machine this is probably anywhere at all). Unpacking can be most quickly, easily, and cleanly done in a single tar command;

    tar -xjvf gdb-6.1.tar.bz2

    but could also be done by a number of high level compression/decompression programs.

  3. Now you need patches. EMAC has created a single unified patch for updating a clean gdb-6.1 source directory to a working state called SoM-5282-GDB-6.1.patch, which can be downloaded from the SoM ftp.

From this point on you will need to be on a command prompt inside a standard *nix shell. Bash works nicely.

cd into the newly created gdb-6.1 directory and patch it.

i.e.

	patch -p1 < (path to the patch)/SoM-5282-GDB-6.1.patch 
  1. Now your ready to configure and build for your target. You may be tempted to type gdb-6.1/configure at the command line DO NOT DO THIS! gdb want you to build it from a separate directory, and will do nasty things to you if you build it directly in it's source directory. Instead, back up out of the directory and create a new directory to hold all the files your build will create.

Create this new directory and build the target there

i.e

	mkdir ../build
	cd ../build
	CC=gcc-3.3 ../gdb-6.1/configure  --target=m68k-bdm-elf
	make CC=gcc-3.3 

Here gcc-3.3 is explicitly specified. You may be ok with other toolchains, but this is the one it has been tested with.

  1. The debugger has now been built and is ready to install, note that you will need root permissions to do this on most *nix machines

    make install


Notes and Miscellanous

The following are interesting tidbits of information that don't fit cleanly in the above explanation, but are useful to write down nonetheless.


Tracking down the problem, debugging the debugger.

Debugging was done using the standard Linux gdb to debug the cross gdb that was being developed.

This works very will from within Eclipse's high level CDT, which provides separate windows for source, disassembly, memory contents, etc, and allows a simultanous connection to the cross gdb's ascii interface. Using this method in conjuction with the “set debug remote” and “set debug frame” commands, the problem areas were more quickly identified.


A brief description of GDB frames

Taken from a thread by Jim Blandy on the gdb mailing list



GDB's current frame model is the result of an incremental cleanup of

working code, not a fresh design, so it's a little weird.



The natural model would be to have a frame object, with methods that

read and write that frame's registers. Reading and writing the

youngest frame's registers would simply read and write the processor's

current registers. Older frames may have some registers saved on the

stack by younger frames, so accessing the older frames' registers

would do a mix of memory accesses and register accesses, as

appropriate.

GDB's model is that you "unwind" a frame's registers from the next

younger frame. That is, to access the registers of frame #1 (the

next-to-youngest frame), you actually apply frame_unwind_register to

frame #0 (the youngest frame). Okay, whatever. But then the obvious

question is: how do you access the registers of the youngest frame

itself? How do you 'unwind' them when they're not wound up?



Thus the sentinel frame, the "-1st" frame.