208 lines
7.5 KiB
Plaintext
208 lines
7.5 KiB
Plaintext
|
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.
|