Leopard+ GDB

I recently upgraded for Leopard to Snow Leopard on my MacBook Pro (core 2 duo). I do a lot of my own C++ programming, and found a need to "debug" a program. The -g option in g++ creates a debug version of your program. But what I found was that I couldn't effectively debug using "gdb", the execution debugger. None of my function names were known to gdb, so I couldn't set breakpoints, or even "list" by function name. I discovered something very important about the new gdb, introduced in Leopard, and essentially reconstituted in Snow Leopard and above.

PROBLEM:

"gdb" could not read symbol information if the object files used to create the program were deleted. I frequently delete the object files after a compilation because I have different Makefiles designed to create different flavors of the program, each with different program names and -Doptions. Here is the Makefile used to create the

debug version:

MacBook.local:~/source dickguertin$ cat make.emg

SRC = em.c emain.c emsvc.c emsio.c emgetl.c emtrap.c emdevs.c emproc.c emacts.c empars.c emsort.c emsrch.c emfuns.c emserv.c emfmtp.c emcps.c xlong.c

OBJ = em.o emain.o emsvc.o emsio.o emgetl.o emtrap.o emdevs.o emproc.o emacts.o empars.o emsort.o emsrch.o emfuns.o emserv.o emfmtp.o emcps.o xlong.o

CC = g++

CFLAGS = -w -g -m32 -DEMG_ -DEMSIO_ -DEMTRAP_ -DPOSIX -DEMPATH=0 -DMACINTEL_

emg: ${OBJ}

${CC} -m32 -o emg ${OBJ} -lcurses

${SRC}: c.h emdef.h r12dsect.h r11dsect.h scdsect.h dsdsects.h pardsect.h frmdsect.h getline.h xlong.h

All the SRC files are compiled with the CFLAGS, and the resulting OBJ files are linked by the ${CC} line with its options to create "emg", my program. As you can see, there are several SRC components, and they can be combined in different ways with different options. Here's another, very simple version:

MacBook.local:~/source dickguertin$ cat make.emx

SRC = em.c emain.c emsvc.c

OBJ = em.o emain.o emsvc.o

CC = gcc

CFLAGS = -w -O -m32 -DPOSIX -DEMPATH=0 -DMACINTEL_

emx: ${OBJ}

${CC} -m32 -o emx ${OBJ}

${SRC}: c.h emdef.h xlong.h

So you can see why I need to eliminate OBJ files from one version to another. They are physically different because of -Doptions.

OBJect files for "emg" must be destroyed after they are used to create the program because any other versions would confuse "gdb". In Tiger, that wasn't a problem because "emg" contains ALL of its debugging information, with pointers back to SRC code, but NOT OBJect files. "emg" contained g++ function names, along with the associated SRC function name AND signature AND program address. That was sufficient for "gdb" to set breakpoints AND list source code. But in Leopard, Snow Leopard, and above, "emg" only contains the g++ function names AND associated program address. Like Tiger, it has pointers to SRC files, but has no way to match the g++ functions to the corresponding SRC functions. Without those names and the signatures, debugging is virtually impossible. What could be done?

SOLUTION:

I created a sub-directory in "source" that I called "emgdir". Within that I created symlinks back to "source" for all .c and .h files. I moved "make.ems" into "emgdir", and created a wrapper script to run it, which looks like this:

MacBook.local:~/source/emgdir dickguertin$ cat makemg

#!/bin/bash

rm -f emg

rm -f *.o

make -f make.emg

if [ ! -f "emg" ] ; then exit 1 ; fi

rm -f emg.sym

cat - <<EOF >gdbcmds

maint print psymbols emg.sym

quit

EOF

gdb -q -x gdbcmds emg 2>/dev/null

exit 0

Now I don't have to delete the OBJ files. But even with that, "gdb emg" would not allow me to set breakpoints or list according to SRC function names. From what I can tell, that appears to be caused by the fact that g++ still doesn't record the SRC function names AND signatures in its symbol table. The "maint print psymbols" command in "gdb" proves it. However, the g++ function names AND associated program address are there, along with lines that show which SRC contributed to a range of addresses. So given the g++ function name, it can find the program address, and from the range it can determine the SRC. Therefore, all I have to do is use a simple script in a separate Terminal window to lookup g++ functions, which have the SRC function name embedded in them, and give those to "gdb". Here's the "xsym" script created to search the "emg.sym" file:

#!/bin/bash

cd ~/source/emgdir

if [ -z "$1" ] ; then

echo "You must supply a symbol"

else

myfile="emg.sym"

if [ -f "$myfile" ] ; then

cat "$myfile" | tr -d "'\t\`" | grep -n "$1"

else

echo "No $myfile"

fi

fi

exit 0

The key is the cat-through-grep sequence of commands. The result shows me the g++ function, with all the noise characters removed. For example:

MacBook.local:~/source/emgdir dickguertin$ xsym DoSVC

1649: _Z5DoSVCi, function, 0x151dd

MacBook.local:~/source/emgdir dickguertin$ gdb -q -se emg

Reading symbols for shared libraries .... done

(gdb) (gdb) break _Z5DoSVCi

Breakpoint 1 at 0x151ef: file emsvc.c, line 4930.

(gdb) list _Z5DoSVCi

4925 /*- PANIC ----- 252 -*/

4926 /*- M1EXIT ---- 253 -*/

4927 /*- COMMAND --- 254 -*/

4928 /*- PAUSE ----- 255 -*/

4929

4930 global int DoSVC (int code) /*+proc+*/

4931 /*- Supervisor call code number -*/

4932 { byte *reg0, *reg1, *reg4, *reg5;

4933 char charbuf[260], cmd[12];

4934 INTERRUPT_PARMS *int_addr;

Now, as you can see, both setting breakpoints, and listing source code seem to work. But what happens if I don't use the g++ function name?

(gdb) break dbugtrap

Function "dbugtrap" not defined.

Make breakpoint pending on future shared library load? (y or [n]) n

Doesn't work. That's why I created the "xsym" scrip. In another Terminal window, I can do this:

MacBook.local:~/source/emgdir dickguertin$ xsym dbugtrap

1739: _ZL8dbugtrapv, function, 0x9ec7

Now, I can copy the g++ function name, and paste it into the "gdb" session in the other window:

(gdb) break _ZL8dbugtrapv

Breakpoint 2 at 0x9ecd: file emsvc.c, line 3426.

(gdb) list _ZL8dbugtrapv

3415 return;

3416 }

3417 if (clr_Trap(--tnum) == 0) putLine("No such trap.\n");

3418 } /*- proc-end: clrTraps -*/

3419

3420 static void dbugtrap (NoParm) /*+proc+*/

3421 { /*- For GBD or DBX -*/

3422 #ifdef _MACWORLD_

3423 Debugger();

3424 #endif

(gdb) list

3425 return;

3426 } /*- proc-end: dbugtrap -*/

3427

3428 static void GetCmds (char* flag) /*+proc+*/

3429 { /*- Logic to handle Trap Commands -*/

3430 char *charloc;

3431 char charbuf[260], cmd[6];

3432 int len;

3433

3434 while (1) /*- Loop until user exits -*/

It isn't easy to work back and forth between two windows, but it does succeed in allowing me to debug.

CONTRAST WITH TIGER:

This is what the symbol table entries look like on Tiger:

Mac-Mini.local:~/source dickguertin$ xsym dbugtrap

3088: _Z8dbugtrapv dbugtrap(), function, 0xf6b6

Mac-Mini.local:~/source dickguertin$ xsym DoTRAP

2463: _Z6DoTRAPl DoTRAP(long), function, 0x2d308

The program is compiled directly in "source", not in a sub-directory like "emgdir", and "gdb" can create a symbol table file using the "maint print psymbols" command at any time, directly from "emg". The resulting file (emg.sym) isn't needed by you or "gdb". You can delete the OBJect files at any time, even before creating "emg.sym", and everything works.

Mac-Min.locali:~/source dickguertin$ gdb -q -se emg

Reading symbols for shared libraries ..... done

(gdb) break dbugtrap

Breakpoint 1 at 0xf6bc: file emsvc.c, line 3426.

(gdb) list dbugtrap

3415 return;

3416 }

3417 if (clr_Trap(--tnum) == 0) putLine("No such trap.\n");

3418 } /*- proc-end: clrTraps -*/

3419

3420 static void dbugtrap (NoParm) /*+proc+*/

3421 { /*- For GBD or DBX -*/

3422 #ifdef _MACWORLD_

3423 Debugger();

3424 #endif

(gdb) list

3425 return;

3426 } /*- proc-end: dbugtrap -*/

3427

3428 static void GetCmds (char* flag) /*+proc+*/

3429 { /*- Logic to handle Trap Commands -*/

3430 char *charloc;

3431 char charbuf[260], cmd[6];

3432 int len;

3433

3434 while (1) /*- Loop until user exits -*/

As you can see, SRC function names are known and recognized, and there are no OBJect files. Everything needed for debugging is in the program "emg".

I created the "emg.sym" file just to show that the symbol table entries contain the SRC function names AND signature. Both are needed for uniqueness.

Contact Dick Guertin

Dick Guertin's Google Home Page