What to Look for when Porting the KGDB Interface
===============================================
Try to avoid calling any routine from the rest of the kernel.
(It's OK to call these routines during initialization).
You wouldn't be able to set breakpoints within these routines
during debugging, since this would hang the debugging interface.
Interface between KGDB and Ethernet Board (sys/dev/yy/if_xx.c)
--------------------------------------------------------------
General Considerations
There is a problem when the debugger uses the same ethernet board as
does the rest of the kernel. For one thing there might arrive packets
destined for the kernel during debugging sessions. Since the debugger
receives all available packets for the time being it has to deliver
back to the driver those packets it has no use for. This implies that
the debugging driver must leave the interrupt pending conditions alone
so that the kernel driver gets the interrupt at the next time its
interrupt is enabled (whether this is when the debugger is left or
later with an spl*()). The same holds for the transmit interrupt
pending, at least when kgdbinit determines that there is some packet
on its way out.
Configuration Files
The interface that is used for debugging has to have a unique
attribute with the option "disable", and must allow the attachment
of a kgdbif. The relevant part of the "files" file for interface
"xx" would look like this:
define kgdbxx { [ disable = 0 ] }
device xx: ether, ifnet, kgdbxx
attach xx at yy
file dev/zz/if_xx.c xx | kgdb_xx needs-flag
attach kgdbif at kgdbxx with kgdb_xx
with proper values for yy and zz. The file dev/zz/if_xx.c contains
both the code of the kernel driver and the KGDB driver for this
interface. You might want to #include "xx.h" in there and
conditionalize the compilation of the KGDB driver with
#if NKGDB_XX > 0.
The appropriate part of the machine configuration would read like
this:
xx* at yy
kgdbif0 at xx?
Note that the unit for kgdbif in the configuration file must be
given explicitly! It's used to distinguish the interface used
for debugging from the one you want to debug a new interface
driver for (see below).
Driver Code
The interface is "probed" by calling the parent probe routine with
a first argument of NULL. The last argument to the probe routine
is a struct kgdb_if pointer that needs to be (partly) initialized by
the probe code. Fields to be set by the probe routine are:
myenetaddr fill this with the own ethernet address of
the device/machine.
flags mark at least KGDB_MYHW here.
name Name of the device, only used for a message.
port Port number, only used for a message by
machine/device independent code.
start routine called everytime KGDB is entered.
leave routine called everytime KGDB is left.
receive routine called to receive a packet.
send routine called to send a packet.
Additional fields that may be set are:
myinetaddr fill this with the own internet address,
and mark KGDB_MYIP in flags.
unit These remaining fields are solely for
speed use by the driver.
fill
drvflags
The routine should check for existance of the ethernet board.
This routine should also try to find the system driver for the
same board and note its unit and device structure for later use.
The routine should return 0 on success and -1 on failure.
The remainder of the routines are called via function pointers
in the kgdb_if structure. The probe routine needs to fill in
these function pointers with proper values.
void start(struct kgdb_if *kip)
This routine gets called every time the debugger is entered.
kip is a pointer to the kgdb_if structure used for debugging.
It should initialize the hardware and software interface.
This routine should also note the current state of the ethernet board
(as far as it can) so a later call to leave can reinstantiate this
state.
void leave(struct kgdb_if *kip)
This routine is called whenever the debugger is left. It should
restore the ethernet hardware to the state prior to the last call to
start.
int receive(struct kgdb_if *kip, u_char *buf, int poll)
This routine should return an ethernet packet to the buffer pointed to
by buf and return its length. The packet should be complete with the
ethernet header, i.e. it starts with the recipient address, but does not
contain the ethernet checksum.
If poll is set, it should return immediately, if no packet is available.
Otherwise it should wait for the next packet.
This routine should return the number of bytes transferred to buf.
void send(struct kgdb_if *kip, u_char *buf, int l)
This routine should send an ethernet packet out of the debugging
interface. The packet is already complete with the ethernet header,
but does not contain the ethernet checksum.
Debugging
If you have a working KGDB, you can test new interface code for a
different interface by supplying "option KGDBTEST" and attaching
a kgdbif1 to the new interface in your configuration file. When
you boot the resulting kernel with the "-d" option, this will
initialize the new interface right after starting KGDB on the
working one. Thereafter, the code will continue to send and
receive packets on the new interface until you set the variable
"kgdb_test" to 0.
Note that during debugging interface code this way you are using
most of the code that comprises the debugger code itself. So you
have to be extremely careful with setting breakpoints and the like.
Interface between KGDB and Machine (sys/arch/xxx/xxx/kgdb_glue.c)
-----------------------------------------------------------------
void kgdbcopy(s,d,n) void *s, *d; int n;
void kgdbzero(d,n) void *d; int n;
void kgdbcmp(s,d,n) char *s, *d; int n;
These routines are the same as bcopy, bzero and bcmp resp. They are
here with other names to allow setting breakpoints into the normal
routines during debugging. This implies that you shouldn't use
things like structure assignement in the code that gets used by
the debugger.
void kgdbinit(void)
This routine gets called when the debugger should be entered for the
first time.
int kgdb_poll(void)
This routine gets called after a panic to check for a keypress by the user.
If implemented it allows the user to press any key on the console to do
the automatic reboot after a panic. Otherwise the debugging interface
will wait forever for some remote debugger to attach in case of a panic.
int kgdbcmds(void)
There should be call to this routine from somewhere in locore when the
trap mechanism determines that the debugger should be entered, i.e. on
a single step or breakpoint interrupt from kernel code. The trapping
mechanism should already have stored the registers into the global area
kgdbregs. The layout of this area must be the same as that expected
by GDB. The return value of this routine is 0, if the user wants to
continue, 1 if the user wants to do single stepping, and 2 if the user
has detached from debugging.
int kgdbfbyte(u_char *p)
This routine should fetch a byte from address p. It must not enter any
trap handling code, but instead return -1 on inability to access the data.
void kgdbsbyte(u_char *p,u_char c)
This routine should set the byte pointed to by p to the value given as c.
The routine must not enter any trap handling code. Furthermore it should
reset the modification bit in the relevant page table entry to the value
before the store.
sys/arch/xxx/include/kgdb.h
Machine dependent definitions and protoypes should be in
sys/arch/xxx/include/kgdb.h, i.e. in <machine/kgdb.h>. This includes
the size of the array kgdbregs, that holds the contents of the registers
of the debuggee at the time KGDB is entered.