bitkeeper revision 1.698.1.1 (4022a73eOGiwh6ZU9-EU4LZoLcVnuQ)

pervasive debugger
This commit is contained in:
ach61@labyrinth.cl.cam.ac.uk committed 2004-02-05 20:27:42 +00:00
1 parent f21e4de207
commit 5a84d1bfb7
16 files changed
+2274 -26

No files matched your search

+7
View File
@@ -12,6 +12,7 @@
3f9e7d60PWZJeVh5xdnk0nLUdxlqEA docs/eps/xenlogo.eps
3f9e7d63lTwQbp2fnx7yY93epWS-eQ docs/figs/dummy
3f9e7d564bWFB-Czjv1qdmE6o0GqNg docs/interface.tex
4022a73cgxX1ryj1HgS-IwwB6NUi2A docs/pdb.txt
3f9e7d58t7N6hjjBMxSn-NMxBphchA docs/style.tex
3f9e7d5bz8BwYkNuwyiPVu7JJG441A docs/xenstyle.cls
3f815144d1vI2777JI-dO4wk49Iw7g extras/mini-os/Makefile
@@ -73,6 +74,8 @@
3f13d81e6Z6806ihYYUw8GVKNkYnuw tools/misc/xen_nat_enable.README
3f1668d4F29Jsw0aC0bJEIkOBiagiQ tools/misc/xen_read_console.c
3f87ba90EUVPQLVOlFG0sW89BCwouQ tools/misc/xen_refresh_dev.c
4022a73cEKvrYe_DVZW2JlAxobg9wg tools/nsplitd/Makefile
4022a73cKms4Oq030x2JBzUB426lAQ tools/nsplitd/nsplitd.c
3fbca441SjQr8vJwTQIgH1laysaWog tools/xc/Makefile
3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/xc/lib/Makefile
3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/xc/lib/rpm.spec
@@ -118,6 +121,7 @@
3ddb79bdIKgipvGoqExEQ7jawfVowA xen/arch/i386/pci-i386.h
3ddb79bdHe6_Uij4-glW91vInNtBYQ xen/arch/i386/pci-irq.c
3ddb79bcZ_2FxINljqNSkqa17ISyJw xen/arch/i386/pci-pc.c
4022a73czgX7d-2zfF_cb33oVemApQ xen/arch/i386/pdb-stub.c
3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/i386/process.c
3ddb79bc7KxGCEJsgBnkDX7XjD_ZEQ xen/arch/i386/rwlock.c
3ddb79bcrD6Z_rUvSDgrvjyb4846Eg xen/arch/i386/setup.c
@@ -133,6 +137,8 @@
3ddb79bddEYJbcURvqqcx99Yl2iAhQ xen/common/block.c
3ddb79bdrqnW93GR9gZk1OJe1qK-iQ xen/common/brlock.c
3fb10d07GscSWPKxBqpvNfU-dYfa0g xen/common/console.c
4022a73c_BbDFd2YJ_NQYVvKX5Oz7w xen/common/debug-linux.c
4022a73c_KPZ1VEbYOrpAhQffd01kA xen/common/debug-linux.h
3fa152581E5KhrAtqZef2Sr5NKTz4w xen/common/debug.c
3ddb79bdLX_P6iB7ILiblRLWvebapg xen/common/dom0_ops.c
3e6377e4i0c9GtKN65e99OtRbw3AZw xen/common/dom_mem_ops.c
@@ -394,6 +400,7 @@
3ddb79c3xjYnrv5t3VqYlR4tNEOl4Q xen/include/asm-i386/page.h
3e450943kzme29HPCtq5HNOVQkddfw xen/include/asm-i386/param.h
3ddb79c3ysKUbxZuwKBRK3WXU2TlEg xen/include/asm-i386/pci.h
4022a73diKn2Ax4-R4gzk59lm1YdDg xen/include/asm-i386/pdb.h
3ddb79c3nm2zdzeO6Mj8g7ex3txgGw xen/include/asm-i386/pgalloc.h
3ddb79c2QF5-pZGzuX4QukPCDAl59A xen/include/asm-i386/processor.h
3ddb79c3mbqEM7QQr3zVq7NiBNhouA xen/include/asm-i386/ptrace.h
+8 -2
View File
@@ -240,10 +240,16 @@ that may be able to help diagnose problems:
ifname=dummy Don't use any network interface.
ser_baud=xxx Enable serial I/O and set the baud rate.
ser_baud=xxx Enable serial I/O and set the baud rate (COM1)
dom0_mem=xxx Set the initial amount of memory for domain0.
pdb=xxx Enable the pervasive debugger. See docs/pdb.txt
xxx defines how the gdb stub will communicate:
com1 use com1
com1H use com1 (with high bit set)
com2 use on com2
com2H use com2 (with high bit set)
It's probably a good idea to join the Xen developer's mailing list on
Sourceforge: http://lists.sourceforge.net/lists/listinfo/xen-devel
+215
View File
@@ -0,0 +1,215 @@
Pervasive Debugging
===================
040205 Alex Ho (alex.ho@cl.cam.ac.uk)
Introduction
------------
The pervasive debugging project is leveraging Xen to
debug distributed systems. We have added a gdb stub
to Xen to allow for remote debugging of both Xen and
guest operating systems. More information about the
pervasive debugger is available at: http://www.cl.cam.ac.uk/netos/pdb
Implementation
--------------
The gdb stub communicates with gdb running over a serial line.
The main entry point is pdb_handle_exception() which is invoked
from: pdb_key_pressed() ('D' on the console)
do_int3_exception() (interrupt 3: breakpoint exception)
do_debug() (interrupt 1: debug exception)
This accepts characters from the serial port and passes gdb
commands to pdb_process_command() which implements the gdb stub
interface. This file draws heavily from the kgdb project and
sample gdbstub provided with gdb.
The stub can examine registers, single step and continue, and
read and write memory (in Xen, a domain, or a Linux process'
address space). The debugger does not currently trace the
current process, so all bets are off if context switch occurs
in the domain.
Setup
-----
+-------+ telnet +-----------+ serial +-------+
| GDB |--------| nsplitd |--------| Xen |
+-------+ +-----------+ +-------+
To run pdb, Xen must be appropriately configured and
a suitable serial interface attached to the target machine.
GDB and nsplitd can run on the same machine.
Xen Configuration
Add the "pdb=xxx" option to your Xen boot command line
where xxx is one of the following values:
com1 gdb stub should communicate on com1
com1H gdb stub should communicate on com1 (with high bit set)
com2 gdb stub should communicate on com2
com2H gdb stub should communicate on com2 (with high bit set)
Symbolic debugging infomration is quite helpful too:
xeno.bk/xen/arch/i386/Rules.mk
add -g to CFLAGS to compile Xen with symbols
xeno.bk/xenolinux-2.4.24-sparse/arch/xeno/Makefile
add -g to CFLAGS to compile XenoLinux with symbols
You may also want to consider dedicating a register to the
frame pointer (disable the -fomit-frame-pointer compile flag).
When booting Xen and domain 0, look for the console text
"Initializing pervasive debugger (PDB)" just before DOM0 starts up.
Serial Port Configuration
pdb expects to communicate with gdb using the serial port. Since
this port is often shared with the machine's console output, pdb can
discriminate its communication by setting the high bit of each char.
A new tool has been added to the source tree which splits
the serial output from a remote machine into two streams:
one stream (without the high bit) is the console and
one stream (with the high bit stripped) is the pdb communication.
See: xeno.bk/tools/nsplitd
Note: nsplitd was originally written for the Nemesis project
at Cambridge.
Usage:
%telnet <hostname> <port>
This is the console of the remote machine. You will probably
want to set telnet in char mode (or create a .telnetrc file).
<hostname> and <port> are for your instance of nsplitd.
You should be able to press 'h' to display a list of keyboard
handlers. In particular, you should see:
key 'D' (ascii '44') => enter pervasive debugger
After nsplitd accepts a connection on <port>, it starts listening
on port <port + 1>. Characters sent to the <port + 1> will have the
high bit set and vice versa for characters received.
Note: if you are not using a serial console and can dedicate your
serial line to pdb messages, then edit pdb_put_char and pdb_get_char
in pdb-stub.c to remove the high bit tests.
GDB 6.0
pdb has been tested with gdb 6.0. It should also work with
earlier versions.
Usage
-----
1. Boot Xen and XenoLinux
2. Interrupt Xen by pressing 'D' at the console
You should see the console message:
pdb_handle_exception [0x88][0xfc5c9d88]
At this point Xen is waiting for gdb commands on the serial line.
3. Attach with gdb
(gdb) file xeno.bk/xen/xen
Reading symbols from xeno.bk/xen/xen...done.
(gdb) target remote <hostname>:<port + 1> /* contact nsplitd */
Remote debugging using serial.srg:12131
continue_cpu_idle_loop () at current.h:10
warning: shared library handler failed to enable breakpoint
(gdb) break __enter_scheduler
Breakpoint 1 at 0xfc510a94: file schedule.c, line 330.
(gdb) cont
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
__enter_scheduler () at schedule.c:330
(gdb) step
(gdb) step
(gdb) print next /* the variable prev has been optimized away! */
$1 = (struct task_struct *) 0x0
(gdb) delete
Delete all breakpoints? (y or n) y
4. You can add additional symbols to gdb
(gdb) add-sym xenolinux-2.4.24/vmlinux
add symbol table from file "xenolinux-2.4.24/vmlinux" at
(y or n) y
Reading symbols from xenolinux-2.4.24/vmlinux...done.
(gdb) x/s cpu_vendor_names[0]
0xc01530d2 <cpdext+62898>: "Intel"
(gdb) break free_uid
Breakpoint 2 at 0xc0012250
(gdb) cont
Continuing. /* run a command in domain 0 */
Program received signal SIGTRAP, Trace/breakpoint trap.
free_uid (up=0xbffff738) at user.c:77
(gdb) print *up
$2 = {__count = {counter = 0}, processes = {counter = 135190120}, files = {
counter = 0}, next = 0x395, pprev = 0xbffff878, uid = 134701041}
(gdb) finish
Run till exit from #0 free_uid (up=0xbffff738) at user.c:77
Program received signal SIGTRAP, Trace/breakpoint trap.
release_task (p=0xc2da0000) at exit.c:51
(gdb) print *p
$3 = {state = 4, flags = 4, sigpending = 0, addr_limit = {seg = 3221225472},
exec_domain = 0xc016a040, need_resched = 0, ptrace = 0, lock_depth = -1,
counter = 1, nice = 0, policy = 0, mm = 0x0, processor = 0,
cpus_runnable = 1, cpus_allowed = 4294967295, run_list = {next = 0x0,
prev = 0x0}, sleep_time = 18995, next_task = 0xc017c000,
prev_task = 0xc2f94000, active_mm = 0x0, local_pages = {next = 0xc2da0054,
prev = 0xc2da0054}, allocation_order = 0, nr_local_pages = 0,
binfmt = 0xc016c6a0, exit_code = 0, exit_signal = 17, pdeath_signal = 0,
personality = 0, did_exec = -1, task_dumpable = 1, pid = 917, pgrp = 914,
tty_old_pgrp = 0, session = 914, tgid = 917, leader = 0,
p_opptr = 0xc2f94000, p_pptr = 0xc2f94000, p_cptr = 0x0, p_ysptr = 0x0,
p_osptr = 0x0, thread_group = {next = 0xc2da00a8, prev = 0xc2da00a8},
pidhash_next = 0x0, pidhash_pprev = 0xc01900b8, wait_chldexit = {
lock = <incomplete type>, task_list = {next = 0xc2da00b8,
prev = 0xc2da00b8}}, vfork_done = 0x0, rt_priority = 0,
it_real_value = 0, it_prof_value = 0, it_virt_value = 0, it_real_incr = 0,
it_prof_incr = 0, it_virt_incr = 0, real_timer = {list = {next = 0x0,
prev = 0x0}, expires = 18950, data = 3269066752,
function = 0xc000ce30 <it_real_fn>}, times = {tms_utime = 0,
tms_stime = 0, tms_cutime = 0, tms_cstime = 0}, start_time = 18989,
per_cpu_utime = {1}, per_cpu_stime = {310}, min_flt = 13, maj_flt = 104,
nswap = 0, cmin_flt = 0, cmaj_flt = 0, cnswap = 0, swappable = -1, uid = 0,
euid = 0, suid = 0, fsuid = 0, gid = 0, egid = 0, sgid = 0, fsgid = 0,
ngroups = 7, groups = {0, 1, 2, 3, 4, 6, 10, 0 <repeats 25 times>},
cap_effective = 4294967039, cap_inheritable = 0, cap_permitted = 4294967039,
keep_capabilities = 0, user = 0xc016b18c, rlim = {{rlim_cur = 4294967295,
rlim_max = 4294967295}, {rlim_cur = 4294967295, rlim_max = 4294967295}, {
rlim_cur = 4294967295, rlim_max = 4294967295}, {rlim_cur = 8388608,
rlim_max = 4294967295}, {rlim_cur = 0, rlim_max = 4294967295}, {
rlim_cur = 4294967295, rlim_max = 4294967295}, {rlim_cur = 512,
rlim_max = 512}, {rlim_cur = 1024, rlim_max = 1024}, {
rlim_cur = 4294967295, rlim_max = 4294967295}, {rlim_cur = 4294967295,
rlim_max = 4294967295}, {rlim_cur = 4294967295, rlim_max = 4294967295}},
used_math = 0, comm = "id\000h\000og\000\000\000\000\000\000\000\000",
link_count = 0, total_link_count = 1, tty = 0xc3ed1000, locks = 0,
semundo = 0x0, semsleeping = 0x0, thread = {esp0 = 3269074944,
eip = 3221249046, esp = 3269074792, fs = 0, gs = 0, io_pl = 3, debugreg = {
0, 0, 0, 0, 0, 0, 0, 0}, cr2 = 0, trap_no = 0, error_code = 0, i387 = {
fsave = {cwd = 2098047, swd = 125632512, twd = 1073944696, fip = 2091,
fcs = -1073745032, foo = 2099, fos = 8064, st_space = {
0 <repeats 20 times>}, status = 0}, fxsave = {cwd = 895, swd = 32,
twd = 0, fop = 1917, fip = 1073944696, fcs = 2091, foo = -1073745032,
fos = 2099, mxcsr = 8064, reserved = 0, st_space = {
0 <repeats 24 times>, 1449431204, -1774489361, 16383, 0, 1,
-1891252224, 16404, 0}, xmm_space = {0 <repeats 32 times>},
padding = {0 <repeats 56 times>}}, soft = {cwd = 2098047,
swd = 125632512, twd = 1073944696, fip = 2091, fcs = -1073745032,
foo = 2099, fos = 8064, st_space = {0 <repeats 20 times>},
ftop = 0 '\0', changed = 0 '\0', lookahead = 0 '\0',
no_update = 0 '\0', rm = 0 '\0', alimit = 0 '\0', info = 0x0,
entry_eip = 0}}, vm86_info = 0x0, screen_bitmap = 0, v86flags = 0,
v86mask = 0, saved_esp0 = 0}, fs = 0x0, files = 0x0, namespace = 0x0,
sigmask_lock = <incomplete type>, sig = 0x0, blocked = {sig = {0, 0}},
pending = {head = 0x0, tail = 0xc2da04f8, signal = {sig = {0, 0}}},
sas_ss_sp = 0, sas_ss_size = 0, notifier = 0, notifier_data = 0x0,
notifier_mask = 0x0, parent_exec_id = 7, self_exec_id = 8,
alloc_lock = <incomplete type>, journal_info = 0x0}
+11
View File
@@ -0,0 +1,11 @@
ROOT = ..
CFILES = $(wildcard *.c)
INSTALL_BINS := nsplitd
include $(ROOT)/mk/rules.mk
nsplitd: $(OBJS)
$(CC) $(CFLAGS) -o nsplitd $(OBJS)
+686
View File
@@ -0,0 +1,686 @@
/*
* nsplitd.c
* ---------
*
* $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $
*
* Copyright (c) 1995, University of Cambridge Computer Laboratory,
* Copyright (c) 1995, Richard Black, All Rights Reserved.
*
*
* A complete re-implementation of DME's nsplitd for use from inetd
*
*/
/* The basic stream comes in (via inetd) and we then conenct to
* somewhere else providing a loop-through service, except we offer
* two other ports for connection - one of which gets a second channel
* using the top bit to distinguish, and the other is a master control
* port (normally used for gdb) which gets complete exclusive access
* for its duration.
*
* Originally designed for multiplexing a xwcons/telnet with a gdb
* post-mortem debugging session.
*
* Here is a picture:
*
* port0 (from inetd)
* 8-bit connection /
* made by us <----> nsplitd <-----gdbport (default port0+2)
* to host:port/tcp |\
* | port1 (default port0+1)
* \
* control (default port0+3)
*
* If port1 is explicitly disabled (through a command-line option) then
* port0 becomes 8-bit clean.
*/
/*
* N.B.: We do NOT support 8 bit stdin/stdout usage on a
* /dev/... because to do that right involves much messing with ioctl
* and TIOC... etc. If you want to do that sort of thing then the
* right way to do it is to chain this onto wconsd (which does know
* about and understand all the ioctl and TIOC grief).
*/
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <netdb.h>
#include <string.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <syslog.h>
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef LOG_DAEMON
#define LOG_DAEMON 0
#endif
#define DB(x) /* ((x), fflush(stderr)) */
extern char *optarg;
extern int optind, opterr, optopt;
static char *prog_name;
static void usage(void)
{
fprintf(stderr, "This program (%s) should be run via inetd (tcp)\n\n",
prog_name);
fprintf(stderr, "usage: %s [-h<highport>][-g<gdbport>]"
"[-c<ctlport>][-8] host:service\n",
prog_name);
exit(1);
}
static void fault(char *format, ...)
{
va_list ap;
char logbuf[1024];
va_start(ap, format);
fprintf(stderr, "%s: ", prog_name);
vfprintf(stderr, format, ap);
fflush(stderr);
va_end(ap);
/* XXX This is a bit dubious, but there is no vsyslog */
va_start(ap, format);
vsprintf(logbuf, format, ap);
syslog(LOG_ERR, logbuf);
va_end(ap);
exit(1);
}
static int getservice(char *name, unsigned short *port)
{
struct servent *se;
if (!name) return -1;
if (isdigit(name[0]))
*port = atoi(name);
else
{
if (!(se = getservbyname(name, "tcp")))
return -1;
*port = ntohs(se->s_port);
}
return 0;
}
/*
* connect_host: connect to ("name", "port")
*/
static int connect_host (char *name, unsigned int port)
{
int fd;
struct hostent *hostent;
struct sockaddr_in sin;
int on;
if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
fault("socket");
if (!(hostent = gethostbyname(name)))
fault("gethostbyname: %s: %s\n", name, strerror(errno));
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons (port);
memcpy(&sin.sin_addr.s_addr, hostent->h_addr, sizeof(struct in_addr));
if (connect(fd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
fault("connect: %s:%u: %s\n", name, port, strerror(errno));
on = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
return fd;
}
/*
* open a tcp socket and start listening for connections on it
*/
static int startlistening(unsigned short port)
{
int fd, on;
struct sockaddr_in sin;
if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
fault("socket");
on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_REUSEADDR): %m");
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons (port);
sin.sin_addr.s_addr = INADDR_ANY;
if (bind(fd, &sin, sizeof(sin)) < 0)
fault("bind: %u: %s\n", port, strerror(errno));
if (listen(fd, 1) < 0)
fault("listen: %s\n", strerror(errno));
return fd;
}
static void noblock(int fd)
{
int on=1;
if (ioctl(fd, FIONBIO, &on) < 0)
fault("ioctl: FIONBIO: %s\n", strerror(errno));
}
/* You might not believe this, but fd_sets don't have to be a 32-bit
* integer. In particular, in glibc2 it is an array of unsigned
* longs. Hence, this hacked up FD_SET_rjb() that works out if it
* would have been a nop. */
#define FD_SET_rjb(fd, setp) \
do { \
if ((fd) != 32) \
FD_SET((fd), (setp)); \
} while(0)
#define FD_ISSET_rjb(fd, setp) (((fd) != 32)? FD_ISSET((fd), (setp)) : 0)
#define MAXSIZE 256
/* -----------------------------------------------------------------
* The main bit of the algorithm. Note we use 32 to mean not connected
* because this gives us 1<<32 == 0. We could have done this one
* character at a time, but that would have been very inefficient and
* not the unix way. */
static int debug;
static void doit(int actl, int acto, int lish, int lisg, int lisc)
{
int acth, actg, actc;
int gdbmode = FALSE;
char gibuf[MAXSIZE], oibuf[MAXSIZE];
char libuf[MAXSIZE], lobuf[MAXSIZE];
char hibuf[MAXSIZE], hobuf[MAXSIZE];
char ctlbuf[MAXSIZE];
fd_set rdfs, wrfs, exfs;
int gicc, oicc, licc, locc, hicc, hocc, ctlcc;
char *giptr, *oiptr, *liptr, *loptr, *hiptr, *hoptr;
int rc, fromlen;
struct sockaddr_in from;
gicc = oicc = licc = locc = hicc = hocc = ctlcc = 0;
acth = actg = actc = 32; /* XXX yummy */
noblock(actl);
noblock(acto);
for(;;)
{
FD_ZERO(&rdfs);
FD_ZERO(&wrfs);
FD_ZERO(&exfs);
/* always take input from the control port (if it's connected) */
FD_SET_rjb(actc, &rdfs);
if (gdbmode)
{
if (oicc)
FD_SET_rjb(actg, &wrfs);
else
FD_SET_rjb(acto, &rdfs);
if (gicc)
FD_SET_rjb(acto, &wrfs);
else
FD_SET_rjb(actg, &rdfs);
}
else
{
/* There is no such thing as oibuf because its been split into
* lobuf and hobuf
*/
if (locc || hocc)
{
if (locc)
FD_SET_rjb(actl, &wrfs);
if (hocc)
FD_SET_rjb(acth, &wrfs);
}
else
FD_SET_rjb(acto, &rdfs);
if (licc)
FD_SET_rjb(acto, &wrfs);
else
FD_SET_rjb(actl, &rdfs);
if (hicc)
FD_SET_rjb(acto, &wrfs);
else
FD_SET_rjb(acth, &rdfs);
}
if (acth == 32 && lish>=0) FD_SET_rjb(lish, &rdfs);
if (actg == 32) FD_SET_rjb(lisg, &rdfs);
if (actc == 32) FD_SET_rjb(lisc, &rdfs);
/* now make exfs the union of the read and write fd sets, plus
* "actl" */
{
int i;
exfs = rdfs;
for(i=0; i<32; i++) /* XXX we only copy fd numbers up to 31 */
if (FD_ISSET(i, &wrfs))
FD_SET_rjb(i, &exfs);
FD_SET_rjb(actl, &exfs);
}
/* XXX AND: can't print something of type fd_set as %x - it
* might be an array */
DB(fprintf(stderr, "%s: before select: %08x %08x %08x\n",
prog_name, rdfs, wrfs, exfs));
if (select(32, &rdfs, &wrfs, &exfs, NULL) < 0)
fault("select: %s\n", strerror(errno));
DB(fprintf(stderr, "%s: after select: %08x %08x %08x\n",
prog_name, rdfs, wrfs, exfs));
/* XXX it appears that a non-blocking socket may not show up
* correctly in exfs but instead goes readable with no data in
* it. Thus we check for zero and goto the appropriate close
* method. */
/* Deal with exceptions */
if (FD_ISSET_rjb(actg, &exfs))
{
exfs_actg:
close(actg);
gdbmode = FALSE;
oicc = 0;
oiptr = oibuf;
actg = 32;
continue; /* because assumptions changed */
}
if (FD_ISSET_rjb(acth, &exfs))
{
exfs_acth:
close(acth);
hicc = hocc = 0;
hiptr = hibuf;
hoptr = hibuf;
acth = 32;
continue; /* because assumptions changed */
}
if (FD_ISSET_rjb(actl, &exfs) ||
FD_ISSET_rjb(acto, &exfs))
{
exfs_actl:
exfs_acto:
/* Thats all folks ... */
break;
}
if (FD_ISSET_rjb(actc, &exfs))
{
exfs_ctl:
close(actc);
actc = 32;
ctlcc = 0;
continue;
}
/* Deal with reading */
if (FD_ISSET_rjb(acto, &rdfs))
{
if ((oicc = read(acto, oiptr = oibuf, MAXSIZE)) < 0)
fault("read acto: %d: %s\n", oicc, strerror(errno));
if (!oicc) goto exfs_acto;
if (!gdbmode)
{
int t;
assert((locc == 0) && (hocc == 0));
loptr = lobuf;
hoptr = hobuf;
if (lish>=0) {
for(t=0; t<oicc; t++)
if (oibuf[t] & 0x80)
hobuf[hocc++] = oibuf[t] & 0x7f;
else
lobuf[locc++] = oibuf[t];
} else {
for (t=0; t<oicc; t++)
lobuf[locc++] = oibuf[t];
}
/* If no high connection scratch that */
if (acth == 32)
hocc=0;
}
}
if (FD_ISSET_rjb(actl, &rdfs))
{
if ((licc = read(actl, liptr = libuf, MAXSIZE)) < 0)
fault("read actl: %d: %s\n", licc, strerror(errno));
if (!licc) goto exfs_actl;
}
if (FD_ISSET_rjb(acth, &rdfs))
{
int t;
if ((hicc = read(acth, hiptr = hibuf, MAXSIZE)) < 0)
fault("read acth: %d: %s\n", hicc, strerror(errno));
if (!hicc) goto exfs_acth;
for(t=0; t<hicc; t++)
hibuf[t] |= 0x80;
}
if (FD_ISSET_rjb(actg, &rdfs))
{
if ((gicc = read(actg, giptr = gibuf, MAXSIZE)) < 0)
fault("read actg: %d: %s\n", gicc, strerror(errno));
if (debug) write(1, giptr, gicc); /* XXX */
if (!gicc) goto exfs_actg;
}
if (FD_ISSET_rjb(actc, &rdfs))
{
if ((ctlcc = read(actc, ctlbuf, MAXSIZE)) < 0)
fault("read actc: %d: %s\n", ctlcc, strerror(errno));
if (debug) write(1, ctlbuf, gicc);
if (!ctlcc) goto exfs_ctl;
if (ctlbuf[0] == 'r') /* reset command */
{
syslog(LOG_INFO, "reset command read, exiting");
if (debug) write(1, "reseting\n", sizeof("reseting\n"));
break;
}
}
/* Deal with writing */
if (FD_ISSET_rjb(actg, &wrfs))
{
/* We must be in gdb mode so send oi buffer data */
assert(gdbmode);
if (debug) write(2, oiptr, oicc); /* XXX */
if ((rc = write(actg, oiptr, oicc)) <= 0)
fault("write actg: %d: %s\n", rc, strerror(errno));
oiptr += rc;
oicc -= rc;
}
if (FD_ISSET_rjb(actl, &wrfs))
{
if ((rc = write(actl, loptr, locc)) <= 0)
fault("write actl: %d: %s\n", rc, strerror(errno));
loptr += rc;
locc -= rc;
}
if (FD_ISSET_rjb(acth, &wrfs))
{
if ((rc = write(acth, hoptr, hocc)) <= 0)
fault("write acth: %d: %s\n", rc, strerror(errno));
hoptr += rc;
hocc -= rc;
}
if (FD_ISSET_rjb(acto, &wrfs))
{
/* If in gdb mode send gdb input, otherwise send low data
preferentially */
if (gdbmode)
{
assert(gicc);
if ((rc = write(acto, giptr, gicc)) <= 0)
fault("write acto: %d: %s\n", rc, strerror(errno));
giptr += rc;
gicc -= rc;
}
else
{
if (licc)
{
if ((rc = write(acto, liptr, licc)) <= 0)
fault("write acto: %d: %s\n", rc, strerror(errno));
liptr += rc;
licc -= rc;
}
else
{
assert(hicc);
if ((rc = write(acto, hiptr, hicc)) <= 0)
fault("write acto: %d: %s\n", rc, strerror(errno));
hiptr += rc;
hicc -= rc;
}
}
}
/* Deals with new connections */
if ((acth == 32) && lish>=0 && (FD_ISSET_rjb(lish, &rdfs)))
{
fromlen = sizeof(from);
if ((acth = accept(lish, &from, &fromlen)) < 0)
{
syslog(LOG_WARNING, "accept: %m");
acth = 32;
}
else
{
noblock(acth);
hicc = hocc = 0;
syslog(LOG_INFO, "highbit client peer is %s:%u\n",
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
}
}
if ((actg == 32) && (FD_ISSET_rjb(lisg, &rdfs)))
{
fromlen = sizeof(from);
if ((actg = accept(lisg, &from, &fromlen)) < 0)
{
syslog(LOG_WARNING, "accept: %m");
actg = 32;
}
else
{
noblock(actg);
gicc = 0;
gdbmode = TRUE;
syslog(LOG_INFO, "gdb client peer is %s:%u\n",
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
}
}
if ((actc == 32) && (FD_ISSET_rjb(lisc, &rdfs)))
{
fromlen = sizeof(from);
if ((actc = accept(lisc, &from, &fromlen)) < 0)
{
syslog(LOG_WARNING, "accept (ctl): %m");
actc = 32;
}
else
{
noblock(actc);
syslog(LOG_INFO, "ctl client peer is %s:%u\n",
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
}
}
/* Back to top of loop */
}
/* We are bailing because one of the primary connections has gone
* away. We close these all explicitly here because that way the
* timeout on reusing the port numbers is smnaller. */
close(acth);
close(actg);
/* XXX AND: why are we closing all these "character counts" ?? */
close(gicc);
close(oicc);
close(licc);
close(locc);
close(hicc);
close(hocc);
}
/*
* ------------------------------------------------------------
*/
int main(int argc, char **argv)
{
/* In general, suffix "l" is low channel, "h" is high channel, "g"
* is gdb channel, "c" is control channel and "o" is output channel.
*/
struct sockaddr_in from;
int infd = 0, outfd;
unsigned short portl, porth, portg, portc, porto;
int on = 1, c;
char *outname, *outservice;
int fromlen;
int lish, lisg, lisc;
#if 0
FILE *newerr;
#endif /* 0 */
prog_name = argv[0];
if (isatty(infd))
usage();
/* Here, then not just a simple idiot. */
signal(SIGPIPE, SIG_IGN);
openlog(prog_name, LOG_PID, LOG_DAEMON);
fromlen = sizeof(from);
if (getsockname(infd, &from, &fromlen) < 0)
fault("getsockname: %s", strerror(errno));
if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET))
fault("not an inet socket (family=%d)\n", from.sin_family);
portl = ntohs(from.sin_port);
porth = portl+1;
portg = porth+1;
portc = portg+1;
fromlen = sizeof(from);
if (getpeername(infd, &from, &fromlen) < 0)
fault("getpeername: %s", strerror(errno));
if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET))
fault("not an inet socket (family=%d)\n", from.sin_family);
syslog(LOG_INFO, "on port %u peer is %s:%u\n", portl,
inet_ntoa(from.sin_addr), ntohs(from.sin_port));
if (setsockopt(infd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
/* from here on, we map stderr to output on the connection so we can
* report errors to the remote user.
*/
#if 0
if (!(newerr = fdopen(infd, "w")))
syslog(LOG_WARNING, "fdopen: %m");
else
*stderr = *newerr;
#endif
while((c = getopt(argc, argv, "d8h:g:c:")) != EOF)
{
switch(c)
{
case 'd':
debug++;
break;
case 'h':
/* high bit port */
if (getservice(optarg, &porth) < 0)
fault("getservice failed (high port '%s')\n", optarg);
break;
case 'g':
/* gdb port */
if (getservice(optarg, &portg) < 0)
fault("getservice failed (gdb port '%s')\n", optarg);
break;
case 'c':
/* control port */
if (getservice(optarg, &portc) < 0)
fault("getservice failed (control port '%s')\n", optarg);
break;
case '8':
/* 8-bit clean; no high port */
porth=0;
break;
default:
fault("bad argument list!\n");
}
}
if (argc != optind + 1)
fault("unparsed arguments (%d!=%d)\n", argc, optind+1);
outname = argv[optind];
if (!(outservice = strchr(outname, ':')))
fault("output arg '%s' doesn't contain ':'\n", outname);
*outservice++ = 0;
if (getservice(outservice, &porto) < 0)
fault("getservice failed (output port '%s')\n", outservice);
/* Time to start the sockets */
if (porth) {
lish = startlistening(porth);
} else {
lish = -1;
}
lisg = startlistening(portg);
lisc = startlistening(portc);
outfd = connect_host(outname, porto);
doit(infd, outfd, lish, lisg, lisc);
syslog(LOG_INFO, "terminating normally\n");
fclose(stderr);
closelog();
exit(0);
}
/* End $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $ */
+831
View File
@@ -0,0 +1,831 @@
#include <xeno/lib.h>
#include <xeno/sched.h>
#include <asm-i386/ptrace.h>
#include <xeno/keyhandler.h>
#include <asm/pdb.h>
#include <xeno/list.h>
#undef DEBUG_TRACE
#ifdef DEBUG_TRACE
#define TRC(_x) _x
#else
#define TRC(_x)
#endif
#define BUFMAX 400
#define PDB_DOMAIN_OFFSET 2 /* all domains are positive numbers */
static const char hexchars[]="0123456789abcdef";
int remote_debug;
int pdb_foobar = 0x123456; /* testing */
char *pdb_foobaz = "cambridge"; /* testing */
#define PDB_BUFMAX 1024
static char pdb_in_buffer[PDB_BUFMAX];
static char pdb_out_buffer[PDB_BUFMAX];
static char pdb_buffer[PDB_BUFMAX];
static int pdb_in_buffer_ptr;
static unsigned char pdb_in_checksum;
static unsigned char pdb_xmit_checksum;
int pdb_ctrl_thread = -1;
int pdb_info_thread = -1;
int pdb_stepping = 0;
int hex (char);
char *mem2hex (char *, char *, int);
char *hex2mem (char *, char *, int);
int hexToInt (char **ptr, int *intValue);
void pdb_put_packet (unsigned char *buffer, int ack);
void pdb_put_char (u_char c);
u_char pdb_get_char ();
static volatile int mem_err = 0;
void set_mem_err (void) /* NOT USED YET... */
{
mem_err = 1;
}
/* These are separate functions so that they are so short and sweet
that the compiler won't save any registers (if there is a fault
to mem_fault, they won't get restored, so there better not be any
saved). */
int
get_char (char *addr)
{
return *addr;
}
void
set_char (char *addr, int val)
{
*addr = val;
}
void
pdb_process_query (char *ptr)
{
if (strcmp(ptr, "C") == 0)
{
/* empty string */
}
else if (strcmp(ptr, "fThreadInfo") == 0)
{
struct task_struct *p = &idle0_task;
u_long flags;
int count = 0, buf_idx = 0;
read_lock_irqsave (&tasklist_lock, flags);
pdb_out_buffer[buf_idx++] = 'm';
while ( (p = p->next_task) != &idle0_task )
{
int domain = p->domain + PDB_DOMAIN_OFFSET;
if (count > 0)
pdb_out_buffer[buf_idx++] = ',';
/*
if (domain < 0)
{ pdb_out_buffer[buf_idx++] = '-'; domain = domain * -1; }
*/
if (domain > 15)
{
pdb_out_buffer[buf_idx++] = hexchars[domain >> 4];
}
pdb_out_buffer[buf_idx++] = hexchars[domain % 16];
count++;
}
pdb_out_buffer[buf_idx++] = 'l';
pdb_out_buffer[buf_idx++] = 0;
read_unlock_irqrestore(&tasklist_lock, flags);
}
else if (strcmp(ptr, "sThreadInfo") == 0)
{
}
else if (strncmp(ptr, "ThreadExtraInfo,", 16) == 0)
{
int thread = 0;
char *message = "whatever!";
ptr += 16;
if (hexToInt (&ptr, &thread))
{
mem2hex ((char *)message, pdb_out_buffer, strlen(message) + 1);
}
}
else if (strcmp(ptr, "Offsets") == 0)
{
/* empty string */
}
else if (strncmp(ptr, "Symbol", 6) == 0)
{
strcpy (pdb_out_buffer, "OK");
}
else
{
printk("pdb_process_query: unknown query [%s]\n", ptr);
}
}
int
pdb_process_command (char *ptr, struct pt_regs *regs)
{
int sigval = 10;
int length;
unsigned long addr;
int ack = 1; /* wait for ack in pdb_put_packet */
int go = 0;
TRC(printk("pdb: [%s]\n", ptr));
{
pdb_out_buffer[0] = 0;
switch (*ptr++)
{
case '?':
pdb_out_buffer[0] = 'S';
pdb_out_buffer[1] = hexchars[sigval >> 4];
pdb_out_buffer[2] = hexchars[sigval % 16];
pdb_out_buffer[3] = 0;
break;
case 'S': /* step with signal */
case 's': /* step */
regs->eflags |= 0x100;
pdb_stepping = 1;
return 1;
/* not reached */
case 'C': /* continue with signal */
case 'c': /* continue */
regs->eflags &= ~0x100;
/* jump out before replying to gdb */
return 1;
/* not reached */
case 'd':
remote_debug = !(remote_debug); /* toggle debug flag */
break;
case 'D': /* detach */
return go;
/* not reached */
case 'g': /* return the value of the CPU registers */
{
int idx = 0;
mem2hex ((char *)&regs->eax, &pdb_out_buffer[idx], sizeof(regs->eax));
idx += sizeof(regs->eax) * 2;
mem2hex ((char *)&regs->ecx, &pdb_out_buffer[idx], sizeof(regs->ecx));
idx += sizeof(regs->ecx) * 2;
mem2hex ((char *)&regs->edx, &pdb_out_buffer[idx], sizeof(regs->edx));
idx += sizeof(regs->edx) * 2;
mem2hex ((char *)&regs->ebx, &pdb_out_buffer[idx], sizeof(regs->ebx));
idx += sizeof(regs->ebx) * 2;
mem2hex ((char *)&regs->esp, &pdb_out_buffer[idx], sizeof(regs->esp));
idx += sizeof(regs->esp) * 2;
mem2hex ((char *)&regs->ebp, &pdb_out_buffer[idx], sizeof(regs->ebp));
idx += sizeof(regs->ebp) * 2;
mem2hex ((char *)&regs->esi, &pdb_out_buffer[idx], sizeof(regs->esi));
idx += sizeof(regs->esi) * 2;
mem2hex ((char *)&regs->edi, &pdb_out_buffer[idx], sizeof(regs->edi));
idx += sizeof(regs->edi) * 2;
mem2hex ((char *)&regs->eip, &pdb_out_buffer[idx], sizeof(regs->eip));
idx += sizeof(regs->eip) * 2;
mem2hex ((char *)&regs->eflags, &pdb_out_buffer[idx], sizeof(regs->eflags));
idx += sizeof(regs->eflags) * 2;
mem2hex ((char *)&regs->xcs, &pdb_out_buffer[idx], sizeof(regs->xcs));
idx += sizeof(regs->xcs) * 2;
mem2hex ((char *)&regs->xss, &pdb_out_buffer[idx], sizeof(regs->xss));
idx += sizeof(regs->xss) * 2;
mem2hex ((char *)&regs->xds, &pdb_out_buffer[idx], sizeof(regs->xds));
idx += sizeof(regs->xds) * 2;
mem2hex ((char *)&regs->xes, &pdb_out_buffer[idx], sizeof(regs->xes));
idx += sizeof(regs->xes) * 2;
mem2hex ((char *)&regs->xfs, &pdb_out_buffer[idx], sizeof(regs->xfs));
idx += sizeof(regs->xfs) * 2;
mem2hex ((char *)&regs->xgs, &pdb_out_buffer[idx], sizeof(regs->xgs));
/*
TRC(printk (" reg: %s \n", pdb_out_buffer));
TRC(printk (" ebx: 0x%08lx\n", regs->ebx));
TRC(printk (" ecx: 0x%08lx\n", regs->ecx));
TRC(printk (" edx: 0x%08lx\n", regs->edx));
TRC(printk (" esi: 0x%08lx\n", regs->esi));
TRC(printk (" edi: 0x%08lx\n", regs->edi));
TRC(printk (" ebp: 0x%08lx\n", regs->ebp));
TRC(printk (" eax: 0x%08lx\n", regs->eax));
TRC(printk (" xds: 0x%08x\n", regs->xds));
TRC(printk (" xes: 0x%08x\n", regs->xes));
TRC(printk (" xfs: 0x%08x\n", regs->xfs));
TRC(printk (" xgs: 0x%08x\n", regs->xgs));
TRC(printk (" eip: 0x%08lx\n", regs->eip));
TRC(printk (" xcs: 0x%08x\n", regs->xcs));
TRC(printk (" efl: 0x%08lx\n", regs->eflags));
TRC(printk (" esp: 0x%08lx\n", regs->esp));
TRC(printk (" xss: 0x%08x\n", regs->xss));
*/
break;
}
case 'G': /* set the value of the CPU registers - return OK */
break;
case 'H':
{
int thread;
char *next = &ptr[1];
if (hexToInt (&next, &thread))
{
if (thread > 0)
{
thread = thread - PDB_DOMAIN_OFFSET;
}
if (*ptr == 'c')
{
pdb_ctrl_thread = thread;
}
else if (*ptr == 'g')
{
pdb_info_thread = thread;
}
else
{
printk ("ack, unknown command %c (thread: %d)\n",
*ptr, thread);
}
}
strcpy (pdb_out_buffer, "OK");
break;
}
case 'k': /* kill request */
{
strcpy (pdb_out_buffer, "OK"); /* ack for fun */
printk ("don't kill bill...\n");
ack = 0;
break;
}
case 'q':
{
pdb_process_query(ptr);
break;
}
/* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
case 'm':
{
/* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
if (hexToInt (&ptr, (int *)&addr))
if (*(ptr++) == ',')
if (hexToInt (&ptr, &length))
{
ptr = 0;
mem_err = 0;
if (pdb_info_thread >= 0)
{
pdb_get_values(pdb_info_thread, pdb_buffer, addr, length);
mem2hex (pdb_buffer, pdb_out_buffer, length);
}
else
mem2hex ((char *) addr, pdb_out_buffer, length);
if (mem_err)
{
strcpy (pdb_out_buffer, "E03");
}
}
if (ptr)
{
strcpy (pdb_out_buffer, "E01");
}
break;
}
/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
case 'M':
{
/* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
if (hexToInt (&ptr, (int *)&addr))
if (*(ptr++) == ',')
if (hexToInt (&ptr, &length))
if (*(ptr++) == ':')
{
mem_err = 0;
pdb_set_values(pdb_info_thread,
ptr, addr, length);
if (mem_err)
{
strcpy (pdb_out_buffer, "E03");
}
else
{
strcpy (pdb_out_buffer, "OK");
}
ptr = 0;
}
if (ptr)
{
strcpy (pdb_out_buffer, "E02");
}
break;
}
case 'T':
{
int thread;
if (hexToInt (&ptr, &thread))
{
thread -= PDB_DOMAIN_OFFSET;
struct task_struct *p = find_domain_by_id(thread);
if (p == NULL)
{
strcpy (pdb_out_buffer, "E00");
}
else
{
strcpy (pdb_out_buffer, "OK");
}
put_task_struct(p);
}
break;
}
} /* switch */
/* reply to the request */
pdb_put_packet (pdb_out_buffer, ack);
}
return go;
}
/*
* process an input character from the serial line.
*
* return "1" if the character is a gdb debug string
* (and hence shouldn't be further processed).
*/
int pdb_debug_state = 0; /* small parser state machine */
int pdb_serial_input(u_char c, struct pt_regs *regs)
{
int out = 1;
int loop, count;
switch (pdb_debug_state)
{
case 0: /* not currently processing debug string */
if ( c == '$' ) /* start token */
{
pdb_debug_state = 1;
pdb_in_buffer_ptr = 0;
pdb_in_checksum = 0;
pdb_xmit_checksum = 0;
}
else
{
out = 0;
}
break;
case 1: /* saw '$' */
if ( c == '#' ) /* checksum token */
{
pdb_debug_state = 2;
pdb_in_buffer[pdb_in_buffer_ptr] = 0;
}
else
{
pdb_in_checksum += c;
pdb_in_buffer[pdb_in_buffer_ptr++] = c;
}
break;
case 2: /* 1st checksum digit */
pdb_xmit_checksum = hex(c) << 4;
pdb_debug_state = 3;
break;
case 3: /* 2nd checksum digit */
pdb_xmit_checksum += hex(c);
if (pdb_in_checksum != pdb_xmit_checksum)
{
pdb_put_char('-'); /* checksum failure */
printk ("checksum failure [%s.%02x.%02x]\n", pdb_in_buffer,
pdb_in_checksum, pdb_xmit_checksum);
}
else
{
pdb_put_char('+'); /* checksum okay */
if ( pdb_in_buffer_ptr > 1 && pdb_in_buffer[2] == ':' )
{
pdb_put_char(pdb_in_buffer[0]);
pdb_put_char(pdb_in_buffer[1]);
/* remove sequence chars from buffer */
count = strlen(pdb_in_buffer);
for (loop = 3; loop < count; loop++)
pdb_in_buffer[loop - 3] = pdb_in_buffer[loop];
}
pdb_process_command (pdb_in_buffer, regs);
}
pdb_debug_state = 0;
break;
}
return out;
}
int hex(char ch)
{
if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
if ((ch >= '0') && (ch <= '9')) return (ch-'0');
if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
return (-1);
}
/* convert the memory pointed to by mem into hex, placing result in buf */
/* return a pointer to the last char put in buf (null) */
char *
mem2hex (mem, buf, count)
char *mem;
char *buf;
int count;
{
int i;
unsigned char ch;
for (i = 0; i < count; i++)
{
ch = get_char (mem++);
*buf++ = hexchars[ch >> 4];
*buf++ = hexchars[ch % 16];
}
*buf = 0;
return (buf);
}
/* convert the hex array pointed to by buf into binary to be placed in mem */
/* return a pointer to the character AFTER the last byte written */
char *
hex2mem (buf, mem, count)
char *buf;
char *mem;
int count;
{
int i;
unsigned char ch;
for (i = 0; i < count; i++)
{
ch = hex (*buf++) << 4;
ch = ch + hex (*buf++);
set_char (mem++, ch);
}
return (mem);
}
int
hexToInt (char **ptr, int *intValue)
{
int numChars = 0;
int hexValue;
int negative = 0;
*intValue = 0;
if (**ptr == '-')
{
negative = 1;
numChars++;
(*ptr)++;
}
while (**ptr)
{
hexValue = hex (**ptr);
if (hexValue >= 0)
{
*intValue = (*intValue << 4) | hexValue;
numChars++;
}
else
break;
(*ptr)++;
}
if (negative)
{
*intValue *= -1;
}
return (numChars);
}
/***********************************************************************/
/***********************************************************************/
/*
* Add a breakpoint to the list of known breakpoints.
* For now there should only be two or three breakpoints so
* we use a simple linked list. In the future, maybe a red-black tree?
*/
struct pdb_breakpoint breakpoints;
void pdb_bkpt_add (unsigned long address)
{
struct pdb_breakpoint *bkpt;
bkpt = kmalloc(sizeof(struct pdb_breakpoint), GFP_KERNEL);
INIT_LIST_HEAD(&bkpt->list);
bkpt->address = address;
list_add(&bkpt->list, &breakpoints.list);
return;
}
/*
* Check to see of the breakpoint is in the list of known breakpoints
*
* return 1 if it has been set, 0 otherwise
*/
struct pdb_breakpoint* pdb_bkpt_search (unsigned long address)
{
struct pdb_breakpoint *found = NULL;
struct list_head *list_entry;
struct pdb_breakpoint *bkpt;
list_for_each(list_entry, &breakpoints.list)
{
bkpt = list_entry(list_entry, struct pdb_breakpoint, list);
if (bkpt->address == address)
{
found = bkpt;
break;
}
}
return found;
}
/*
* Remove a breakpoint to the list of known breakpoints.
*
* Return 1 if the element was not found, otherwise 0.
*/
void pdb_bkpt_remove_ptr (struct pdb_breakpoint *bkpt)
{
struct list_head *list_entry = &bkpt->list;
list_del(list_entry);
kfree(bkpt);
}
int pdb_bkpt_remove (unsigned long address)
{
struct list_head *list_entry;
struct pdb_breakpoint *bkpt;
int found = 1;
list_for_each(list_entry, &breakpoints.list)
{
bkpt = list_entry(list_entry, struct pdb_breakpoint, list);
if (bkpt->address == address)
{
pdb_bkpt_remove_ptr (bkpt);
found = 0;
break;
}
}
return found;
}
/***********************************************************************/
void breakpoint(void);
int pdb_initialized = 0;
int pdb_high_bit = 1;
void pdb_put_char (u_char c)
{
extern void debug_putchar(u_char);
u_char cc = pdb_high_bit ? c | 0x80 : c;
debug_putchar(cc);
}
u_char pdb_get_char ()
{
extern u_char debug_getchar();
u_char cc = debug_getchar();
return cc & 0x7f;
}
/* send the packet in buffer. */
void pdb_put_packet (unsigned char *buffer, int ack)
{
unsigned char checksum;
int count;
char ch;
/* $<packet info>#<checksum> */
/* do */
{
pdb_put_char ('$');
checksum = 0;
count = 0;
while ((ch = buffer[count]))
{
pdb_put_char (ch);
checksum += ch;
count += 1;
}
pdb_put_char('#');
pdb_put_char(hexchars[checksum >> 4]);
pdb_put_char(hexchars[checksum % 16]);
}
if (ack)
{
if ((ch = pdb_get_char()) != '+')
{
printk(" pdb return error: %c 0x%x [%s]\n", ch, ch, buffer);
}
}
}
void pdb_get_packet(char *buffer)
{
int count;
char ch;
unsigned char checksum = 0;
unsigned char xmitcsum = 0;
do
{
while ((ch = pdb_get_char()) != '$');
count = 0;
checksum = 0;
while (count < BUFMAX)
{
ch = pdb_get_char();
if (ch == '#') break;
checksum += ch;
buffer[count] = ch;
count++;
}
buffer[count] = 0;
if (ch == '#')
{
xmitcsum = hex(pdb_get_char()) << 4;
xmitcsum += hex(pdb_get_char());
if (xmitcsum == checksum)
{
pdb_put_char('+');
if (buffer[2] == ':')
{
printk ("gdb packet found with sequence ID\n");
}
}
else
{
pdb_put_char('-');
}
}
} while (checksum != xmitcsum);
return;
}
/*
* process a machine interrupt or exception
* return 1 if pdb is not interested in the exception; it should
* be propagated to the guest os.
*/
int pdb_handle_exception(int exceptionVector,
struct pt_regs *xen_regs)
{
int signal = 0;
printk ("pdb_handle_exception [0x%x][0x%lx]\n",
exceptionVector, xen_regs->eip);
/* if pdb didn't set the breakpoint, and
pdb is not single stepping, and
the user didn't press the magic debug key on the console,
then pass the exception up to the guest os */
if (pdb_bkpt_search(xen_regs->eip - 1) == NULL &&
pdb_stepping == 0 &&
exceptionVector != 0x88)
{
TRC(printk("pdb: external breakpoint at 0x%lx\n", xen_regs->eip));
return 1;
}
if (pdb_stepping == 1)
{
xen_regs->eflags &= ~0x100;
pdb_stepping = 0;
}
if (exceptionVector == 0x03)
{
xen_regs->eip --;
}
/* generate a signal for gdb */
switch (exceptionVector)
{
case 136 : signal = 2; break; /* SIGINT */
case 1 : signal = 5; break; /* SIGTRAP */
case 3 : signal = 5; break; /* SIGTRAP */
default :
printk ("can't generate signal for unknown exception vector %d\n",
exceptionVector);
break;
}
pdb_out_buffer[0] = 'S';
pdb_out_buffer[1] = hexchars[signal >> 4];
pdb_out_buffer[2] = hexchars[signal % 16];
pdb_out_buffer[3] = 0;
pdb_put_packet(pdb_out_buffer, 1);
while (1)
{
pdb_out_buffer[0] = 0;
pdb_get_packet(pdb_in_buffer);
if (pdb_process_command(pdb_in_buffer, xen_regs))
{
return 0;
}
}
return 0;
}
void pdb_key_pressed(u_char key, void *dev_id, struct pt_regs *regs)
{
pdb_handle_exception(136, regs);
return;
}
void initialize_pdb()
{
extern char opt_pdb[];
int pdb_com_port;
if (strncmp(opt_pdb, "com", 3) == 0)
{
extern void debug_set_com_port(int port);
pdb_com_port = opt_pdb[3] - '0'; /* error checking ? */
debug_set_com_port(pdb_com_port);
pdb_high_bit = opt_pdb[4] == 'H' ? 1 : 0;
}
else
{
if (strcmp(opt_pdb, "none") != 0)
{
printk ("pdb: unknown option\n");
}
return;
}
printk ("Initializing pervasive debugger (PDB) [%s] port %d, high %d\n",
opt_pdb, pdb_com_port, pdb_high_bit);
breakpoints.address = 0;
INIT_LIST_HEAD(&breakpoints.list);
pdb_stepping = 0;
/* ack any spurrious gdb packets */
pdb_put_char ('+');
/* serial console */
add_key_handler('D', pdb_key_pressed, "enter pervasive debugger");
pdb_initialized = 1;
}
void breakpoint(void)
{
if (pdb_initialized)
asm("int $3");
}
+2
View File
@@ -12,6 +12,7 @@
#include <asm/apic.h>
#include <asm/desc.h>
#include <asm/domain_page.h>
#include <asm/pdb.h>
struct cpuinfo_x86 boot_cpu_data = { 0 };
/* Lots of nice things, since we only target PPro+. */
@@ -428,6 +429,7 @@ void __init start_of_day(void)
do_initcalls();
initialize_serial(); /* setup serial 'driver' (for debugging) */
initialize_keyboard(); /* setup keyboard (also for debugging) */
initialize_pdb(); /* pervasive debugger */
if ( !setup_network_devices() )
panic("Must have a network device!\n");
+63 -2
View File
@@ -49,6 +49,7 @@
#include <asm/pgalloc.h>
#include <asm/uaccess.h>
#include <asm/i387.h>
#include <asm/pdb.h>
#define GTBF_TRAP 1
#define GTBF_TRAP_NOCODE 2
@@ -223,6 +224,30 @@ static inline void do_trap(int trapnr, char *str,
smp_processor_id(), trapnr, str, error_code);
}
static inline void do_int3_exception(int trapnr,
struct pt_regs *regs,
long error_code)
{
struct task_struct *p = current;
struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
trap_info_t *ti;
if ((regs->xcs & 3) != 3)
{
pdb_handle_exception(trapnr, regs);
return;
}
ti = current->thread.traps + trapnr;
gtb->flags = GTBF_TRAP_NOCODE;
gtb->error_code = error_code;
gtb->cs = ti->cs;
gtb->eip = ti->address;
if ( TI_GET_IF(ti) )
clear_bit(EVENTS_MASTER_ENABLE_BIT, &p->shared_info->events_mask);
return;
}
#define DO_ERROR_NOCODE(trapnr, str, name) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
@@ -236,7 +261,6 @@ do_trap(trapnr, str, regs, error_code, 1); \
}
DO_ERROR_NOCODE( 0, "divide error", divide_error)
DO_ERROR_NOCODE( 3, "int3", int3)
DO_ERROR_NOCODE( 4, "overflow", overflow)
DO_ERROR_NOCODE( 5, "bounds", bounds)
DO_ERROR_NOCODE( 6, "invalid operand", invalid_op)
@@ -251,6 +275,12 @@ DO_ERROR(17, "alignment check", alignment_check)
DO_ERROR_NOCODE(18, "machine check", machine_check)
DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error)
asmlinkage void do_int3(struct pt_regs * regs, long error_code)
{
if (pdb_initialized) do_int3_exception(3, regs, error_code);
else do_trap(3, "int3", regs, error_code, 0);
}
asmlinkage void do_double_fault(void)
{
extern spinlock_t console_lock;
@@ -489,13 +519,44 @@ asmlinkage void math_state_restore(struct pt_regs *regs, long error_code)
}
}
asmlinkage void do_debug(struct pt_regs * regs, long error_code)
{
unsigned int condition;
struct task_struct *tsk = current;
struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
/*
printk("do_debug_exceptionn [%lx][%lx][%x]\n",
error_code, regs->eip, regs->xcs);
*/
__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
if ((condition & (1 << 14)) != (1 << 14))
{
printk ("\nwarning: debug trap w/o BS bit [0x%x]\n\n", condition);
}
__asm__("movl %0,%%db6" : : "r" (0));
if (pdb_handle_exception(1, regs)) /* propagate to domain */
{
tsk->thread.debugreg[6] = condition;
gtb->flags = GTBF_TRAP_NOCODE;
gtb->cs = tsk->thread.traps[1].cs;
gtb->eip = tsk->thread.traps[1].address;
}
return;
}
asmlinkage void do_debug_orig(struct pt_regs * regs, long error_code)
{
unsigned int condition;
struct task_struct *tsk = current;
struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
/* Mask out spurious debug traps due to lazy DR7 setting */
+82
View File
@@ -0,0 +1,82 @@
#include <xeno/config.h>
#include <xeno/types.h>
#include <xeno/lib.h>
#include <hypervisor-ifs/dom0_ops.h>
#include "debug-linux.h"
/*
* linux specific pdb stuff
*/
/*
static inline struct task_struct *find_task_by_pid(int pid)
{
struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];
for(p = *htable; p && p->pid != pid; p = p->pidhash_next) ;
return p;
}
*/
/* read a byte from a process */
u_char pdb_linux_get_value (int domain, int pid, unsigned long addr)
{
u_char result = 0;
unsigned long task_struct_p, mm_p, pgd, task_struct_pid;
unsigned long l2tab, page;
/* find the task_struct of the given process */
pdb_get_values(domain, (u_char *) &task_struct_p,
pidhash_addr + pid_hashfn(pid) * 4,
sizeof(task_struct_p));
/* find the correct task struct */
while (task_struct_p != (unsigned long)NULL)
{
pdb_get_values(domain, (u_char *) &task_struct_pid,
task_struct_p + task_struct_pid_offset,
sizeof(task_struct_pid));
if (task_struct_pid == pid)
{
break;
}
pdb_get_values(domain, (u_char *) &task_struct_p,
task_struct_p + task_struct_pidhash_next_offset,
sizeof(task_struct_p));
}
if (task_struct_p == (unsigned long)NULL)
{
/* oops */
printk ("error: couldn't find process 0x%x in domain %d\n", pid, domain);
return 0;
}
/* get the mm_struct within the task_struct */
pdb_get_values(domain, (u_char *) &mm_p,
task_struct_p + task_struct_mm_offset,
sizeof(mm_p));
/* get the page global directory (cr3) within the mm_struct */
pdb_get_values(domain, (u_char *) &pgd,
mm_p + mm_struct_pgd_offset,
sizeof(pgd));
/* get the l2 table entry */
pdb_get_values(domain, (u_char *) &l2tab,
pgd + (addr >> PGDIR_SHIFT) * 4,
sizeof(l2tab));
l2tab = (unsigned long)__va(machine_to_phys(domain, l2tab) & PAGE_MASK);
/* get the page table entry */
pdb_get_values(domain, (u_char *) &page,
l2tab + ((addr & L1_PAGE_BITS) >> PAGE_SHIFT) * 4,
sizeof(page));
page = (unsigned long)__va(machine_to_phys(domain, page) & PAGE_MASK);
/* get the byte */
pdb_get_values(domain, (u_char *) &result, page + (addr & ~PAGE_MASK),
sizeof(result));
return result;
}
+45
View File
@@ -0,0 +1,45 @@
#include <asm/pdb.h>
/* from linux/sched.h */
#define PIDHASH_SZ (4096 >> 2)
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
/* from asm-xeno/pgtable-2level.h */
#define PGDIR_SHIFT 22
#define PTRS_PER_PGD 1024
/* from asm-xeno/page.h */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define __PAGE_OFFSET (0xC0000000)
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
/* from debug.h */
#define ENTRIES_PER_L1_PAGETABLE 1024
#define L1_PAGE_BITS ( (ENTRIES_PER_L1_PAGETABLE - 1) << PAGE_SHIFT )
/* adapted from asm-xeno/page.h */
static inline unsigned long machine_to_phys(int domain, unsigned long machine)
{
unsigned long phys;
pdb_get_values(domain, (u_char *) &phys,
(unsigned long) machine_to_phys_mapping + (machine >> PAGE_SHIFT) * 4,
sizeof(phys));
phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
return phys;
}
#define pidhash_addr 0xc018f260UL
#define task_struct_mm_offset 0x2c
#define task_struct_pid_offset 0x7c
#define task_struct_pidhash_next_offset 0xb0
#define mm_struct_pgd_offset 0x0c
extern u_char pdb_linux_get_value (int domain, int pid, unsigned long addr);
+177 -6
View File
@@ -10,33 +10,182 @@
#include <hypervisor-ifs/dom0_ops.h>
#include <xeno/sched.h>
#include <xeno/event.h>
#include <asm/page.h>
#include <asm/domain_page.h> /* [un]map_domain_mem */
#include <asm/pdb.h>
#define DEBUG_TRACE
#undef DEBUG_TRACE
#ifdef DEBUG_TRACE
#define TRC(_x) _x
#else
#define TRC(_x)
#endif
/****************************************************************************/
int pdb_change_values (int domain, u_char *buffer, unsigned long addr,
int length, int rw);
/*
* Set memory in a domain's address space
* Set "length" bytes at "address" from "domain" to the values in "buffer".
* Return the number of bytes set, 0 if there was a problem.
*
* THIS WILL BECOME A MACRO
*/
int pdb_set_values (int domain, u_char *buffer, unsigned long addr, int length)
{
int count;
void *bkpt;
count = pdb_change_values(domain, buffer, addr, length, 2);
/* this is a bit x86 specific at the moment... */
if (length == 1 && buffer[0] == 'c' && buffer[1] == 'c')
{
/* inserting a new breakpoint */
pdb_bkpt_add (addr);
TRC(printk("pdb breakpoint detected at 0x%lx\n", addr));
}
else if ((bkpt = pdb_bkpt_search(addr)))
{
/* removing a breakpoint */
TRC(printk("pdb breakpoint cleared at 0x%lx\n", addr));
pdb_bkpt_remove_ptr(bkpt);
}
return count;
}
/*
* Read memory from a domain's address space.
* Fetch "length" bytes at "address" from "domain" into "buffer".
* Return the number of bytes read, 0 if there was a problem.
*
* THIS WILL BECOME A MACRO
*/
int pdb_get_values (int domain, u_char *buffer, unsigned long addr, int length)
{
return pdb_change_values(domain, buffer, addr, length, 1);
}
/*
* Change memory in a domain's address space.
* Read or write "length" bytes at "address" from "domain" into/from "buffer".
* Return the number of bytes read, 0 if there was a problem.
* RW: 1 = read, 2 = write
*/
int pdb_change_values (int domain, u_char *buffer, unsigned long addr,
int length, int rw)
{
struct task_struct *p;
l2_pgentry_t* l2_table = NULL;
l1_pgentry_t* l1_table = NULL;
u_char *page;
int bytes = 0;
extern char *hex2mem (char *, char *, int);
p = find_domain_by_id(domain);
if ((addr >> PAGE_SHIFT) == ((addr + length - 1) >> PAGE_SHIFT))
{
l2_table = map_domain_mem(pagetable_val(p->mm.pagetable));
l2_table += l2_table_offset(addr);
if (!(l2_pgentry_val(*l2_table) & _PAGE_PRESENT))
{
printk ("L2:0x%p (0x%lx) \n", l2_table, l2_pgentry_val(*l2_table));
goto exit2;
}
if (l2_pgentry_val(*l2_table) & _PAGE_PSE)
{
#define PSE_PAGE_SHIFT L2_PAGETABLE_SHIFT
#define PSE_PAGE_SIZE (1UL << PSE_PAGE_SHIFT)
#define PSE_PAGE_MASK (~(PSE_PAGE_SIZE-1))
#define L1_PAGE_BITS ( (ENTRIES_PER_L1_PAGETABLE - 1) << L1_PAGETABLE_SHIFT )
#define pse_pgentry_to_phys(_x) (l2_pgentry_val(_x) & PSE_PAGE_MASK)
page = map_domain_mem(pse_pgentry_to_phys(*l2_table) +/* 10 bits */
(addr & L1_PAGE_BITS)); /* 10 bits */
page += addr & (PAGE_SIZE - 1); /* 12 bits */
}
else
{
l1_table = map_domain_mem(l2_pgentry_to_phys(*l2_table));
l1_table += l1_table_offset(addr);
if (!(l1_pgentry_val(*l1_table) & _PAGE_PRESENT))
{
printk ("L2:0x%p (0x%lx) L1:0x%p (0x%lx)\n",
l2_table, l2_pgentry_val(*l2_table),
l1_table, l1_pgentry_val(*l1_table));
goto exit1;
}
page = map_domain_mem(l1_pgentry_to_phys(*l1_table));
page += addr & (PAGE_SIZE - 1);
}
switch (rw)
{
case 1: /* read */
memcpy (buffer, page, length);
bytes = length;
break;
case 2: /* write */
hex2mem (buffer, page, length);
bytes = length;
break;
default: /* unknown */
printk ("error: unknown RW flag: %d\n", rw);
return 0;
}
unmap_domain_mem((void *)page);
exit1:
if (l1_table != NULL)
unmap_domain_mem((void *)l1_table);
exit2:
unmap_domain_mem((void *)l2_table);
}
else
{
/* read spans pages. need to recurse */
printk ("pdb memory SPAN! addr:0x%lx l: %x\n", addr, length);
}
put_task_struct(p);
return bytes;
}
/*
* interactively call pervasive debugger from a privileged domain
*/
void pdb_do_debug (dom0_op_t *op)
{
op->u.debug.status = 0;
op->u.debug.out1 = op->u.debug.in2 + 10;
op->u.debug.out2 = op->u.debug.in1 + 100;
TRC(printk("PDB: op:%c, dom:%x, in1:%x, in2:%x\n",
TRC(printk("PDB: op:%c, dom:%x, in1:%x, in2:%x, in3:%x, in4:%x\n",
op->u.debug.opcode, op->u.debug.domain,
op->u.debug.in1, op->u.debug.in2));
op->u.debug.in1, op->u.debug.in2,
op->u.debug.in3, op->u.debug.in4));
/* NOT NOW
if (op->u.debug.domain == 0)
{
op->u.debug.status = 1;
return;
}
*/
switch (op->u.debug.opcode)
{
case 'r' :
case 'c' :
{
struct task_struct * p = find_domain_by_id(op->u.debug.domain);
if ( p != NULL )
@@ -54,6 +203,28 @@ void pdb_do_debug (dom0_op_t *op)
}
break;
}
case 'r' :
{
int loop;
u_char x;
for (loop = 0; loop < op->u.debug.in2; loop++) /* length */
{
extern u_char pdb_linux_get_value (int domain, int pid, unsigned long addr);
if (loop % 8 == 0)
{
printk ("\n%08x ", op->u.debug.in1 + loop);
}
x = pdb_linux_get_value(op->u.debug.domain, /* domain */
op->u.debug.in3, /* pid */
op->u.debug.in1 + loop); /* addr */
printk (" %02x", x);
}
printk ("\n");
break;
}
case 's' :
{
unsigned long cpu_mask;
+3
View File
@@ -69,6 +69,8 @@ int opt_noreboot=0;
int opt_ignorebiostables=0;
/* opt_watchdog: If true, run a watchdog NMI on each processor. */
int opt_watchdog=0;
/* opt_pdb: Name of serial port for Xen pervasive debugger (and enable pdb) */
unsigned char opt_pdb[10] = "none";
static struct {
unsigned char *name;
@@ -85,6 +87,7 @@ static struct {
{ "noreboot", OPT_BOOL, &opt_noreboot },
{ "ignorebiostables", OPT_BOOL, &opt_ignorebiostables },
{ "watchdog", OPT_BOOL, &opt_watchdog },
{ "pdb", OPT_STR, &opt_pdb },
{ NULL, 0, NULL }
};
+97 -12
View File
@@ -41,31 +41,114 @@
#define NS16550_MCR_OUT2 0x08 /* OUT2: interrupt mask */
#define NS16550_MCR_LOOP 0x10 /* Loop */
#define SERIAL_BASE 0x3f8 /* XXX SMH: horrible hardwired COM1 */
#define LSR_DR 0x01 /* Data ready */
#define LSR_OE 0x02 /* Overrun */
#define LSR_PE 0x04 /* Parity error */
#define LSR_FE 0x08 /* Framing error */
#define LSR_BI 0x10 /* Break */
#define LSR_THRE 0x20 /* Xmit holding register empty */
#define LSR_TEMT 0x40 /* Xmitter empty */
#define LSR_ERR 0x80 /* Error */
static int serial_echo = 0; /* default is not to echo; change with 'e' */
#define SERIAL_COM1 0x3f8
#define SERIAL_COM2 0x2f8
int serial_com_base = SERIAL_COM1;
int debug_com_base = SERIAL_COM1;
static int serial_echo = 0; /* default is not to echo; change with '~' */
void toggle_echo(u_char key, void *dev_id, struct pt_regs *regs)
{
serial_echo = !serial_echo;
}
void debug_set_com_port(int port)
{
debug_com_base = port == 1 ? SERIAL_COM1 : SERIAL_COM2;
}
int debug_testchar() /* character available? */
{
return (inb(debug_com_base + NS16550_LSR) & LSR_DR);
}
u_char debug_getchar()
{
while (! (inb(debug_com_base + NS16550_LSR) & LSR_DR));/* wait for char */
return inb(debug_com_base + NS16550_RBR);
}
void debug_putch(u_char c)
{
while (! (inb(debug_com_base + NS16550_LSR) & LSR_THRE));
/* wait for idle */
outb(c, debug_com_base + NS16550_RBR);
}
void debug_putchar(u_char c)
{
debug_putch(c);
if (c == '\n') debug_putch('\r');
}
int serial_testchar() /* character available? */
{
return (inb(serial_com_base + NS16550_LSR) & LSR_DR);
}
u_char serial_getchar()
{
while (! (inb(serial_com_base + NS16550_LSR) & LSR_DR));/* wait for char */
return inb(serial_com_base + NS16550_RBR);
}
void serial_putch(u_char c)
{
while (! (inb(serial_com_base + NS16550_LSR) & LSR_THRE));
/* wait for idle */
outb(c, serial_com_base + NS16550_RBR);
}
void serial_putchar(u_char c)
{
serial_putch(c);
if (c == '\n') serial_putch('\r');
}
static spinlock_t serial_lock;
static void serial_rx_int(int irq, void *dev_id, struct pt_regs *regs)
{
u_char c;
key_handler *handler;
unsigned long flags;
while ( (inb(SERIAL_BASE + NS16550_LSR) & 1) == 1 )
spin_lock_irqsave(&serial_lock, flags);
while (serial_testchar())
{
c = inb(SERIAL_BASE + NS16550_RBR);
c = serial_getchar();
if( (handler = get_key_handler(c)) != NULL )
(*handler)(c, dev_id, regs);
if (c & 0x80)
{
extern int pdb_serial_input(u_char, struct pt_regs *);
pdb_serial_input(c & 0x7f, regs);
}
else
{
if ( (handler = get_key_handler(c)) != NULL )
(*handler)(c, dev_id, regs);
if ( serial_echo )
printk("%c", c);
}
if ( serial_echo )
serial_putch(c);
}
}
spin_unlock_irqrestore(&serial_lock, flags);
}
void initialize_serial()
@@ -74,6 +157,8 @@ void initialize_serial()
if ( !SERIAL_ENABLED )
return;
spin_lock_init(&serial_lock);
/* setup key handler */
add_key_handler('~', toggle_echo, "toggle serial echo");
@@ -82,13 +167,13 @@ void initialize_serial()
/* Clear FIFOs, enable, trigger at 1 byte */
outb(NS16550_FCR_TRG1 | NS16550_FCR_ENABLE |
NS16550_FCR_CLRX | NS16550_FCR_CLTX,
SERIAL_BASE+NS16550_FCR);
serial_com_base + NS16550_FCR);
/* Enable receive interrupts. Also remember to keep DTR/RTS asserted. */
outb(NS16550_MCR_OUT2|NS16550_MCR_DTR|NS16550_MCR_RTS,
SERIAL_BASE + NS16550_MCR);
serial_com_base + NS16550_MCR);
outb(NS16550_IER_ERDAI,
SERIAL_BASE + NS16550_IER );
serial_com_base + NS16550_IER );
if( (rc = request_irq(4, serial_rx_int, SA_NOPROFILE, "serial", 0)) )
printk("initialize_serial: failed to get IRQ4, rc=%d\n", rc);
+41
View File
@@ -0,0 +1,41 @@
/*
* pervasive debugger
*
* alex ho
* 2004
* university of cambridge computer laboratory
*/
#ifndef __PDB_H__
#define __PDB_H__
#include <asm/ptrace.h>
#include <xeno/list.h>
extern int pdb_initialized;
extern int pdb_com_port;
extern int pdb_high_bit;
extern void initialize_pdb(void);
extern int pdb_set_values (int domain, u_char *buffer,
unsigned long addr, int length);
extern int pdb_get_values (int domain, u_char *buffer,
unsigned long addr, int length);
extern int pdb_handle_exception(int exceptionVector,
struct pt_regs *xen_regs);
struct pdb_breakpoint
{
struct list_head list;
unsigned long address;
};
extern void pdb_bkpt_add (unsigned long address);
extern struct pdb_breakpoint* pdb_bkpt_search (unsigned long address);
extern void pdb_bkpt_remove_ptr (struct pdb_breakpoint *bkpt);
extern int pdb_bkpt_remove (unsigned long address);
#endif /* __PDB_H__ */
+5 -3
View File
@@ -17,7 +17,7 @@
* This makes sure that old versions of dom0 tools will stop working in a
* well-defined way (rather than crashing the machine, for instance).
*/
#define DOM0_INTERFACE_VERSION 0xAAAA0003
#define DOM0_INTERFACE_VERSION 0xAAAA0004
/*
@@ -168,9 +168,11 @@ typedef struct dom0_debug_st
{
/* IN variables. */
char opcode;
int domain, in1, in2;
unsigned int domain;
int in1, in2, in3, in4;
/* OUT variables. */
int status, out1, out2;
unsigned int status;
int out1, out2;
} dom0_debug_t;
/*
+1 -1
View File
@@ -159,7 +159,7 @@ struct task_struct
* or expiring timer
* TASK_UNINTERRUPTIBLE: Domain is blocked but may not be woken up by an
* arbitrary event or timer.
* TASK_STOPPED: Domain is sopped.
* TASK_STOPPED: Domain is stopped.
* TASK_DYING: Domain is about to cross over to the land of the dead.
*/
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.