EFI68k and the GNU debugger (*LONG*)

John S Gwynne jsg
Fri Nov 11 03:53:12 GMT 1994


--------

Last weekend I took the time to install the GNU debugger (gdb) and
configure it to work remotely with EFI68k (that's a 68HC000 single
board computer for the newcomers). I am now happy to say my efforts
were successful. Those familiar with gdb may not wish to read on as
gdb running remotely is identical to its normal use. Those who wish to
know more will find an example "mock" debugging session below.  In the
following, I've tried to show what I consider to be four strong-points
of this software (1) the ability to evaluate at the command line any
valid C expression that may even include function calls and variables
located on the remote machine (this is an example for the C-language
only, but gdb has full support for C++ and other languages too), (2)
stepping through C code line-by-line, (3) stepping through code one
machine instruction at a time, and (4) stepping through source
code/assembly code that has been optimized. I will not take the time
to show the use of breakpoints, but gdb has extensive facilities for
this that permit definitions in a variety of manners and under a
number of conditions.

As an example of gdb use, I have chosen the following do-nothing
program which simple adds two numbers through the use of a function.
This is intended to be just an example of gdb!

the program:
=================== cut here =========================
/* external hooks into the debugger stub */
extern void set_debug(void);
extern void breakpoint(void);

/* an example function that adds its arguments */
int add_func( int a, int b)
{
  return (a+b);
}

/* This is an example of a simple program that
   adds two integers, i and j. */
mymain() 
{ 
  int i, j; 

  set_debug_traps();		/* initialize the debugger stub */
  breakpoint();			/* a "pre-programmed"  breakpoint where the
				   debugger gains control */

  j=16;				/* load j with 16 */
  i=2;				/* load i with 2 */

  i=add_func(i, j);		/* add i and j; put the result in i */
}
=================== cut here =========================

The follow is the gdb session with my comments.

=================== cut here =========================
GDB is free software and you are welcome to 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.
GDB 4.13 (mips-sgi-irix4.0.5F --target m68k-sun-sunos4),
Copyright 1994 Free Software Foundation, Inc...

[switch the debugger over to remote mode on EFI68k]

(gdb) target remote /dev/ttyd2
Remote debugging using /dev/ttyd2
breakpoint () at m68k-stub.c:843
843     }

[the debugger has stopped at the breakpoint compiled into the
  program; a ``trap #1'' exception in the debugger stub.]

(gdb) n
mymain () at t3.c:21
21        j=16;                         /* load j with 16 */

[n (next line) has returned us from the function ``breakpoint()'' (line 843
of the debuging stub) to line 21 of ``mymain()'' in file "t3.c".]

(gdb) l
16
17        set_debug_traps();            /* initialize the debugger stub */
18        breakpoint();                 /* out first breakpoint where the
19                                         debugger gains control */
20
21        j=16;                         /* load j with 16 */
22        i=2;                          /* load i with 2 */
23
24        i=add_func(i, j);             /* add i and j; put result in i */
25      }

[l (list) list the program lines surrounding the current line: 21]

(gdb) p add_func(2, 4)
$1 = 6

[p (print) the result of add_func(2,4). Did you catch that? Print the
results of the expression ``add_func(2,4)''. This is ``so cool'' when
one considers that this expression (i.e., the evaluation of the
function add_func()) was preformed on the remote board and brought
back to the host via the debugger... this is not part of the original
program... ok, I thought it was cool... :).]

(gdb) n
22        i=2;                          /* load i with 2 */

(gdb) n
24        i=add_func(i, j);             /* add i and j; put result in i */

(gdb) p i
$2 = 2

(gdb) p j
$3 = 16

[we have now executed the lines 21-24 and have verified that i and j
are indeed 2 and 16. The next n-command will execute the function call
and return. A s-command (step) would go to the first line of the
function add_func and stop.]

(gdb) n
25      }

(gdb) p i
$4 = 18

[and we have the result... 18. Now, one more time but in
assembly from non-optimized-C code.]

(gdb) info line 21
Line 21 of "t3.c" starts at address 0x200736 <mymain+16>
   and ends at 0x20073c <mymain+22>.

(gdb) set $pc=0x200736

[info allowed us to find the memory location of line 21. Then the set
command moves the program counter for us.]

(gdb) x/10i $pc
0x200736 <mymain+16>:   moveq #16,d1
0x200738 <mymain+18>:   movel d1,fp@(-8)
0x20073c <mymain+22>:   moveq #2,d1
0x20073e <mymain+24>:   movel d1,fp@(-4)
0x200742 <mymain+28>:   movel fp@(-8),sp at -
0x200746 <mymain+32>:   movel fp@(-4),sp at -
0x20074a <mymain+36>:   bsrs 0x200710 <add_func>
0x20074c <mymain+38>:   addqw #8,sp
0x20074e <mymain+40>:   movel d0,fp@(-4)
0x200752 <mymain+44>:   unlk fp

[the x-command (examine) with the /i parameter disassembles memory for
us and displays the result. Note that all labels are maintained.]

(gdb) si
si
0x200738        21        j=16;                         /* load j with 16 */

[si (step-instruction) moves us through the program...]

(gdb) si
22        i=2;                          /* load i with 2 */

(gdb) si
0x20073e        22        i=2;                          /* load i with 2 */

(gdb) si
24        i=add_func(i, j);             /* add i and j; put result in i */

(gdb) si
0x200746        24        i=add_func(i, j);             /* add i and j; put result in i */

(gdb) si
0x20074a        24        i=add_func(i, j);             /* add i and j; put result in i */

(gdb) si
add_func (a=2113508, b=3896) at t3.c:7
7       {

[we are about to enter add_func(), but the values of a and b will not
be correct until the next frame is created by the following link instruction.]

(gdb) x/10i $pc-4
0x200710 <add_func>:    linkw fp,#0
0x200714 <add_func+4>:  movel fp@(8),d1
0x200718 <add_func+8>:  addl fp@(12),d1
0x20071c <add_func+12>: movel d1,d0
0x20071e <add_func+14>: bra 0x200722 <add_func+18>
0x200722 <add_func+18>: unlk fp
0x200724 <add_func+20>: rts
0x200726 <mymain>:      linkw fp,#-8
0x20072a <mymain+4>:    jsr @#0x2013fe <set_debug_traps>
0x200730 <mymain+10>:   jsr @#0x2014b2 <breakpoint>

(gdb) si
add_func (a=2, b=16) at t3.c:8
8         return (a+b);

[note a and b have the correct values now.]

(gdb) si
0x200718        8         return (a+b);

(gdb)
0x20071e        8         return (a+b);

(gdb)
9       }

(gdb) si
0x200724 in add_func (a=2113508, b=3896) at t3.c:9
9       }

[the add_func frame was deleted...]

(gdb) si
0x20074c in mymain () at t3.c:24
24        i=add_func(i, j);             /* add i and j; put result in i */

(gdb) si
0x20074e        24        i=add_func(i, j);             /* add i and j; put result in i */

(gdb) si
25      }

(gdb) p i
$4 = 18

[and again, we have the result: 18. Lastly, the following is the same
thing but this time compiled using the optimizer. This time the
variables i and j do not exist in memory but are rather in the cpu
registers (actually in this example, since i and j don't really do
anything, they only exist on the stack for a few instructions).]

breakpoint () at m68k-stub.c:843
843     }

[the stop at the pre-programmed breakpoint as above]

(gdb) n
mymain () at t3.c:24
24        i=add_func(i, j);             /* add i and j; put result in i */

[line 24 is the first line to generate an instruction after the
"breakpoint()" call with optimization.]

(gdb) x/10i $pc-16
0x200720 <mymain>:      linkw fp,#0
0x200724 <mymain+4>:    jsr @#0x2013e6 <set_debug_traps>
0x20072a <mymain+10>:   jsr @#0x20149a <breakpoint>
0x200730 <mymain+16>:   pea @#0x10
0x200734 <mymain+20>:   pea @#0x2
0x200738 <mymain+24>:   bsrs 0x200710 <add_func>
0x20073a <mymain+26>:   unlk fp
0x20073c <mymain+28>:   rts
0x20073e <mymain+30>:   orb #86,d0
0x200742 <putDebugChar+2>:      0177774

[as you see, ``i'' and ``j'' are pushed right onto the
stack... pea=>push_effective_address]

(gdb) si
0x200734        24        i=add_func(i, j);             /* add i and j; put result in i */

(gdb) si
0x200738        24        i=add_func(i, j);             /* add i and j; put result in i */

(gdb) si
add_func (a=2113508, b=3896) at t3.c:7
7       {

(gdb) x/10i $pc
0x200710 <add_func>:    linkw fp,#0
0x200714 <add_func+4>:  movel fp@(8),d0
0x200718 <add_func+8>:  addl fp@(12),d0
0x20071c <add_func+12>: unlk fp
0x20071e <add_func+14>: rts
0x200720 <mymain>:      linkw fp,#0
0x200724 <mymain+4>:    jsr @#0x2013e6 <set_debug_traps>
0x20072a <mymain+10>:   jsr @#0x20149a <breakpoint>
0x200730 <mymain+16>:   pea @#0x10
0x200734 <mymain+20>:   pea @#0x2

(gdb) si
add_func (a=2, b=16) at t3.c:8
8         return (a+b);

(gdb) si
0x200718        8         return (a+b);

(gdb) si
9       }

(gdb) si
0x20071e in add_func (a=2113508, b=3896) at t3.c:9
9       }

(gdb) si
mymain () at t3.c:25
25      }

(gdb) p i
No symbol "i" in current context.

[oops... the result returned in the register $do, but mymain() never
really does anything with it... you get the idea...]
=================== cut here =============

Well, those are the basics.... There are a lot more command such as
backtrace that retraces the the function calls (from the stack frames)
to see who called what... etc.... etc...

My apologies for the length of this post, but it represents a major
mile stone in the development of this single-board-computer. Software
development is becoming more and more traditional in the UNIX sense
with, again, most of the GNU tools avaliable. The bottom line is that
with the software developed in C around *FREE* GNU tools,
upgrading to the next "faster" controllers/CPU's (like the MIPS R4200
or R4600 (?) RISC variant for Chrysler) will require only minor
software changes in several stubs... 

                                       John S Gwynne
                                          Gwynne.1 at osu.edu
_______________________________________________________________________________
               T h e   O h i o - S t a t e   U n i v e r s i t y
    ElectroScience Laboratory, 1320 Kinnear Road, Columbus, Ohio 43212, USA
                Telephone: (614) 292-7981 * Fax: (614) 292-7292
-------------------------------------------------------------------------------





More information about the Diy_efi mailing list