summaryrefslogtreecommitdiff
path: root/sys/ddb
diff options
context:
space:
mode:
Diffstat (limited to 'sys/ddb')
-rw-r--r--sys/ddb/db_access.c97
-rw-r--r--sys/ddb/db_access.h39
-rw-r--r--sys/ddb/db_aout.c350
-rw-r--r--sys/ddb/db_break.c348
-rw-r--r--sys/ddb/db_break.h64
-rw-r--r--sys/ddb/db_command.c507
-rw-r--r--sys/ddb/db_command.h59
-rw-r--r--sys/ddb/db_examine.c327
-rw-r--r--sys/ddb/db_expr.c226
-rw-r--r--sys/ddb/db_input.c246
-rw-r--r--sys/ddb/db_lex.c276
-rw-r--r--sys/ddb/db_lex.h72
-rw-r--r--sys/ddb/db_output.c423
-rw-r--r--sys/ddb/db_output.h38
-rw-r--r--sys/ddb/db_print.c67
-rw-r--r--sys/ddb/db_run.c381
-rw-r--r--sys/ddb/db_run.h51
-rw-r--r--sys/ddb/db_sym.c381
-rw-r--r--sys/ddb/db_sym.h99
-rw-r--r--sys/ddb/db_trap.c71
-rw-r--r--sys/ddb/db_variables.c164
-rw-r--r--sys/ddb/db_variables.h53
-rw-r--r--sys/ddb/db_watch.c264
-rw-r--r--sys/ddb/db_watch.h53
-rw-r--r--sys/ddb/db_write_cmd.c99
25 files changed, 4755 insertions, 0 deletions
diff --git a/sys/ddb/db_access.c b/sys/ddb/db_access.c
new file mode 100644
index 00000000000..4914f1e02fd
--- /dev/null
+++ b/sys/ddb/db_access.c
@@ -0,0 +1,97 @@
+/* $NetBSD: db_access.c,v 1.8 1994/10/09 08:37:35 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h> /* type definitions */
+#include <machine/endian.h>
+
+#include <ddb/db_access.h>
+
+/*
+ * Access unaligned data items on aligned (longword)
+ * boundaries.
+ */
+
+int db_extend[] = { /* table for sign-extending */
+ 0,
+ 0xFFFFFF80,
+ 0xFFFF8000,
+ 0xFF800000
+};
+
+db_expr_t
+db_get_value(addr, size, is_signed)
+ db_addr_t addr;
+ register size_t size;
+ boolean_t is_signed;
+{
+ char data[sizeof(int)];
+ register db_expr_t value;
+ register int i;
+
+ db_read_bytes(addr, size, data);
+
+ value = 0;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ for (i = size - 1; i >= 0; i--)
+#else /* BYTE_ORDER == BIG_ENDIAN */
+ for (i = 0; i < size; i++)
+#endif /* BYTE_ORDER */
+ value = (value << 8) + (data[i] & 0xFF);
+
+ if (size < 4 && is_signed && (value & db_extend[size]) != 0)
+ value |= db_extend[size];
+ return (value);
+}
+
+void
+db_put_value(addr, size, value)
+ db_addr_t addr;
+ register size_t size;
+ register db_expr_t value;
+{
+ char data[sizeof(int)];
+ register int i;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ for (i = 0; i < size; i++)
+#else /* BYTE_ORDER == BIG_ENDIAN */
+ for (i = size - 1; i >= 0; i--)
+#endif /* BYTE_ORDER */
+ {
+ data[i] = value & 0xFF;
+ value >>= 8;
+ }
+
+ db_write_bytes(addr, size, data);
+}
diff --git a/sys/ddb/db_access.h b/sys/ddb/db_access.h
new file mode 100644
index 00000000000..21f0a3b76e2
--- /dev/null
+++ b/sys/ddb/db_access.h
@@ -0,0 +1,39 @@
+/* $NetBSD: db_access.h,v 1.6 1994/10/09 08:29:57 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Data access functions for debugger.
+ */
+db_expr_t db_get_value __P((db_addr_t, size_t, boolean_t));
+void db_put_value __P((db_addr_t, size_t, db_expr_t));
+
+void db_read_bytes __P((db_addr_t, size_t, char *));
+void db_write_bytes __P((db_addr_t, size_t, char *));
diff --git a/sys/ddb/db_aout.c b/sys/ddb/db_aout.c
new file mode 100644
index 00000000000..453423d7b7c
--- /dev/null
+++ b/sys/ddb/db_aout.c
@@ -0,0 +1,350 @@
+/* $NetBSD: db_aout.c,v 1.12 1994/10/09 08:19:31 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h> /* data types */
+
+#include <ddb/db_sym.h>
+
+#ifndef DB_NO_AOUT
+
+#define _AOUT_INCLUDE_
+#include <nlist.h>
+#include <stab.h>
+
+/*
+ * An a.out symbol table as loaded into the kernel debugger:
+ *
+ * symtab -> size of symbol entries, in bytes
+ * sp -> first symbol entry
+ * ...
+ * ep -> last symbol entry + 1
+ * strtab == start of string table
+ * size of string table in bytes,
+ * including this word
+ * -> strings
+ */
+
+#ifdef SYMTAB_SPACE
+int db_symtabsize = SYMTAB_SPACE;
+int db_symtab[SYMTAB_SPACE/sizeof(int)] = { 0, 1 };
+#endif
+
+/*
+ * Find the symbol table and strings; tell ddb about them.
+ */
+X_db_sym_init(symtab, esymtab, name)
+ int * symtab; /* pointer to start of symbol table */
+ char * esymtab; /* pointer to end of string table,
+ for checking - rounded up to integer
+ boundary */
+ char * name;
+{
+ register struct nlist *sym_start, *sym_end;
+ register struct nlist *sp;
+ register char * strtab;
+ register int strlen;
+ char * estrtab;
+
+#ifdef SYMTAB_SPACE
+ if (*symtab < sizeof(int)) {
+ printf ("DDB: no symbols\n");
+ return;
+ }
+#endif
+
+ /*
+ * Find pointers to the start and end of the symbol entries,
+ * given a pointer to the start of the symbol table.
+ */
+ sym_start = (struct nlist *)(symtab + 1);
+ sym_end = (struct nlist *)((char *)sym_start + *symtab);
+
+ strtab = (char *)sym_end;
+ strlen = *(int *)strtab;
+
+#ifdef SYMTAB_SPACE
+ printf("DDB: found symbols [%d + %d bytes]\n",
+ *symtab, strlen);
+ if ((*symtab + strlen) > db_symtabsize) {
+ printf("DDB: symbols larger than SYMTAB_SPACE?\n");
+ return;
+ }
+#else
+ estrtab = strtab + strlen;
+
+#define round_to_size(x) \
+ (((vm_offset_t)(x) + sizeof(vm_size_t) - 1) & ~(sizeof(vm_size_t) - 1))
+
+ if (round_to_size(estrtab) != round_to_size(esymtab)) {
+ db_printf("[ %s symbol table not valid ]\n", name);
+ return;
+ }
+#undef round_to_size
+
+#endif
+
+ for (sp = sym_start; sp < sym_end; sp++) {
+ register int strx;
+ strx = sp->n_un.n_strx;
+ if (strx != 0) {
+ if (strx > strlen) {
+ db_printf("Bad string table index (%#x)\n", strx);
+ sp->n_un.n_name = 0;
+ continue;
+ }
+ sp->n_un.n_name = strtab + strx;
+ }
+ }
+
+ if (db_add_symbol_table((char *)sym_start, (char *)sym_end, name,
+ (char *)symtab) != -1) {
+#ifndef SYMTAB_SPACE
+ db_printf("[ preserving %d bytes of %s symbol table ]\n",
+ esymtab - (char *)symtab, name);
+#endif
+ }
+}
+
+db_sym_t
+X_db_lookup(stab, symstr)
+ db_symtab_t *stab;
+ char * symstr;
+{
+ register struct nlist *sp, *ep;
+
+ sp = (struct nlist *)stab->start;
+ ep = (struct nlist *)stab->end;
+
+ for (; sp < ep; sp++) {
+ if (sp->n_un.n_name == 0)
+ continue;
+ if ((sp->n_type & N_STAB) == 0 &&
+ sp->n_un.n_name != 0 &&
+ db_eqname(sp->n_un.n_name, symstr, '_'))
+ {
+ return ((db_sym_t)sp);
+ }
+ }
+ return ((db_sym_t)0);
+}
+
+db_sym_t
+X_db_search_symbol(symtab, off, strategy, diffp)
+ db_symtab_t * symtab;
+ register
+ db_addr_t off;
+ db_strategy_t strategy;
+ db_expr_t *diffp; /* in/out */
+{
+ register unsigned int diff = *diffp;
+ register struct nlist *symp = 0;
+ register struct nlist *sp, *ep;
+
+ sp = (struct nlist *)symtab->start;
+ ep = (struct nlist *)symtab->end;
+
+ for (; sp < ep; sp++) {
+ if (sp->n_un.n_name == 0)
+ continue;
+ if ((sp->n_type & N_STAB) != 0 || (sp->n_type & N_TYPE) == N_FN)
+ continue;
+ if (off >= sp->n_value) {
+ if (off - sp->n_value < diff) {
+ diff = off - sp->n_value;
+ symp = sp;
+ if (diff == 0 &&
+ (strategy == DB_STGY_PROC &&
+ sp->n_type == (N_TEXT|N_EXT) ||
+ strategy == DB_STGY_ANY &&
+ (sp->n_type & N_EXT)))
+ break;
+ }
+ else if (off - sp->n_value == diff) {
+ if (symp == 0)
+ symp = sp;
+ else if ((symp->n_type & N_EXT) == 0 &&
+ (sp->n_type & N_EXT) != 0)
+ symp = sp; /* pick the external symbol */
+ }
+ }
+ }
+ if (symp == 0) {
+ *diffp = off;
+ }
+ else {
+ *diffp = diff;
+ }
+ return ((db_sym_t)symp);
+}
+
+/*
+ * Return the name and value for a symbol.
+ */
+void
+X_db_symbol_values(sym, namep, valuep)
+ db_sym_t sym;
+ char **namep;
+ db_expr_t *valuep;
+{
+ register struct nlist *sp;
+
+ sp = (struct nlist *)sym;
+ if (namep)
+ *namep = sp->n_un.n_name;
+ if (valuep)
+ *valuep = sp->n_value;
+}
+
+
+boolean_t
+X_db_line_at_pc(symtab, cursym, filename, linenum, off)
+ db_symtab_t * symtab;
+ db_sym_t cursym;
+ char **filename;
+ int *linenum;
+ db_expr_t off;
+{
+ register struct nlist *sp, *ep;
+ register struct nlist *sym = (struct nlist *)cursym;
+ unsigned long sodiff = -1UL, lndiff = -1UL, ln = 0;
+ char *fname = NULL;
+
+ sp = (struct nlist *)symtab->start;
+ ep = (struct nlist *)symtab->end;
+
+/* XXX - gcc specific */
+#define NEWSRC(str) ((str) != NULL && \
+ (str)[0] == 'g' && strcmp((str), "gcc_compiled.") == 0)
+
+ for (; sp < ep; sp++) {
+
+ /*
+ * Prevent bogus linenumbers in case module not compiled
+ * with debugging options
+ */
+#if 0
+ if (sp->n_value <= off && (off - sp->n_value) <= sodiff &&
+ NEWSRC(sp->n_un.n_name)) {
+#endif
+ if ((sp->n_type & N_TYPE) == N_FN || NEWSRC(sp->n_un.n_name)) {
+ sodiff = lndiff = -1UL;
+ ln = 0;
+ fname = NULL;
+ }
+
+ if (sp->n_type == N_SO) {
+ if (sp->n_value <= off && (off - sp->n_value) < sodiff) {
+ sodiff = off - sp->n_value;
+ fname = sp->n_un.n_name;
+ }
+ continue;
+ }
+
+ if (sp->n_type != N_SLINE)
+ continue;
+
+ if (sp->n_value > off)
+ break;
+
+ if (off - sp->n_value < lndiff) {
+ lndiff = off - sp->n_value;
+ ln = sp->n_desc;
+ }
+ }
+
+ if (fname != NULL && ln != 0) {
+ *filename = fname;
+ *linenum = ln;
+ return TRUE;
+ }
+
+ return (FALSE);
+}
+
+boolean_t
+X_db_sym_numargs(symtab, cursym, nargp, argnamep)
+ db_symtab_t * symtab;
+ db_sym_t cursym;
+ int *nargp;
+ char **argnamep;
+{
+ register struct nlist *sp, *ep;
+ u_long addr;
+ int maxnarg = *nargp, nargs = 0;
+
+ if (cursym == NULL)
+ return FALSE;
+
+ addr = ((struct nlist *)cursym)->n_value;
+ sp = (struct nlist *)symtab->start;
+ ep = (struct nlist *)symtab->end;
+
+ for (; sp < ep; sp++) {
+ if (sp->n_type == N_FUN && sp->n_value == addr) {
+ while (++sp < ep && sp->n_type == N_PSYM) {
+ if (nargs >= maxnarg)
+ break;
+ nargs++;
+ *argnamep++ = sp->n_un.n_name?sp->n_un.n_name:"???";
+ {
+ /* XXX - remove trailers */
+ char *cp = *(argnamep-1);
+ while (*cp != '\0' && *cp != ':') cp++;
+ if (*cp == ':') *cp = '\0';
+ }
+ }
+ *nargp = nargs;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Initialization routine for a.out files.
+ */
+ddb_init()
+{
+#ifndef SYMTAB_SPACE
+ extern char *esym;
+ extern int end;
+
+ if (esym > (char *)&end) {
+ X_db_sym_init((int *)&end, esym, "netbsd");
+ }
+#else
+ X_db_sym_init (db_symtab, 0, "netbsd");
+#endif
+}
+
+#endif /* DB_NO_AOUT */
diff --git a/sys/ddb/db_break.c b/sys/ddb/db_break.c
new file mode 100644
index 00000000000..e85c52f4102
--- /dev/null
+++ b/sys/ddb/db_break.c
@@ -0,0 +1,348 @@
+/* $NetBSD: db_break.c,v 1.5 1994/10/09 08:19:32 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Breakpoints.
+ */
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h> /* type definitions */
+
+#include <ddb/db_lex.h>
+#include <ddb/db_break.h>
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_break.h>
+
+#define NBREAKPOINTS 100
+struct db_breakpoint db_break_table[NBREAKPOINTS];
+db_breakpoint_t db_next_free_breakpoint = &db_break_table[0];
+db_breakpoint_t db_free_breakpoints = 0;
+db_breakpoint_t db_breakpoint_list = 0;
+
+db_breakpoint_t
+db_breakpoint_alloc()
+{
+ register db_breakpoint_t bkpt;
+
+ if ((bkpt = db_free_breakpoints) != 0) {
+ db_free_breakpoints = bkpt->link;
+ return (bkpt);
+ }
+ if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
+ db_printf("All breakpoints used.\n");
+ return (0);
+ }
+ bkpt = db_next_free_breakpoint;
+ db_next_free_breakpoint++;
+
+ return (bkpt);
+}
+
+void
+db_breakpoint_free(bkpt)
+ register db_breakpoint_t bkpt;
+{
+ bkpt->link = db_free_breakpoints;
+ db_free_breakpoints = bkpt;
+}
+
+void
+db_set_breakpoint(map, addr, count)
+ vm_map_t map;
+ db_addr_t addr;
+ int count;
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_find_breakpoint(map, addr)) {
+ db_printf("Already set.\n");
+ return;
+ }
+
+ bkpt = db_breakpoint_alloc();
+ if (bkpt == 0) {
+ db_printf("Too many breakpoints.\n");
+ return;
+ }
+
+ bkpt->map = map;
+ bkpt->address = addr;
+ bkpt->flags = 0;
+ bkpt->init_count = count;
+ bkpt->count = count;
+
+ bkpt->link = db_breakpoint_list;
+ db_breakpoint_list = bkpt;
+}
+
+void
+db_delete_breakpoint(map, addr)
+ vm_map_t map;
+ db_addr_t addr;
+{
+ register db_breakpoint_t bkpt;
+ register db_breakpoint_t *prev;
+
+ for (prev = &db_breakpoint_list;
+ (bkpt = *prev) != 0;
+ prev = &bkpt->link) {
+ if (db_map_equal(bkpt->map, map) &&
+ (bkpt->address == addr)) {
+ *prev = bkpt->link;
+ break;
+ }
+ }
+ if (bkpt == 0) {
+ db_printf("Not set.\n");
+ return;
+ }
+
+ db_breakpoint_free(bkpt);
+}
+
+db_breakpoint_t
+db_find_breakpoint(map, addr)
+ vm_map_t map;
+ db_addr_t addr;
+{
+ register db_breakpoint_t bkpt;
+
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ {
+ if (db_map_equal(bkpt->map, map) &&
+ (bkpt->address == addr))
+ return (bkpt);
+ }
+ return (0);
+}
+
+db_breakpoint_t
+db_find_breakpoint_here(addr)
+ db_addr_t addr;
+{
+ return db_find_breakpoint(db_map_addr(addr), addr);
+}
+
+boolean_t db_breakpoints_inserted = TRUE;
+
+void
+db_set_breakpoints()
+{
+ register db_breakpoint_t bkpt;
+
+ if (!db_breakpoints_inserted) {
+
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ if (db_map_current(bkpt->map)) {
+ bkpt->bkpt_inst = db_get_value(bkpt->address,
+ BKPT_SIZE,
+ FALSE);
+ db_put_value(bkpt->address,
+ BKPT_SIZE,
+ BKPT_SET(bkpt->bkpt_inst));
+ }
+ db_breakpoints_inserted = TRUE;
+ }
+}
+
+void
+db_clear_breakpoints()
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_breakpoints_inserted) {
+
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ if (db_map_current(bkpt->map)) {
+ db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
+ }
+ db_breakpoints_inserted = FALSE;
+ }
+}
+
+/*
+ * Set a temporary breakpoint.
+ * The instruction is changed immediately,
+ * so the breakpoint does not have to be on the breakpoint list.
+ */
+db_breakpoint_t
+db_set_temp_breakpoint(addr)
+ db_addr_t addr;
+{
+ register db_breakpoint_t bkpt;
+
+ bkpt = db_breakpoint_alloc();
+ if (bkpt == 0) {
+ db_printf("Too many breakpoints.\n");
+ return 0;
+ }
+
+ bkpt->map = NULL;
+ bkpt->address = addr;
+ bkpt->flags = BKPT_TEMP;
+ bkpt->init_count = 1;
+ bkpt->count = 1;
+
+ bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
+ db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
+ return bkpt;
+}
+
+void
+db_delete_temp_breakpoint(bkpt)
+ db_breakpoint_t bkpt;
+{
+ db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
+ db_breakpoint_free(bkpt);
+}
+
+/*
+ * List breakpoints.
+ */
+void
+db_list_breakpoints()
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_breakpoint_list == 0) {
+ db_printf("No breakpoints set\n");
+ return;
+ }
+
+ db_printf(" Map Count Address\n");
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ {
+ db_printf("%s%8x %5d ",
+ db_map_current(bkpt->map) ? "*" : " ",
+ bkpt->map, bkpt->init_count);
+ db_printsym(bkpt->address, DB_STGY_PROC);
+ db_printf("\n");
+ }
+}
+
+/* Delete breakpoint */
+/*ARGSUSED*/
+void
+db_delete_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
+}
+
+/* Set breakpoint with skip count */
+/*ARGSUSED*/
+void
+db_breakpoint_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ if (count == -1)
+ count = 1;
+
+ db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
+}
+
+/* list breakpoints */
+void
+db_listbreak_cmd()
+{
+ db_list_breakpoints();
+}
+
+#include <vm/vm_kern.h>
+
+/*
+ * We want ddb to be usable before most of the kernel has been
+ * initialized. In particular, current_thread() or kernel_map
+ * (or both) may be null.
+ */
+
+boolean_t
+db_map_equal(map1, map2)
+ vm_map_t map1, map2;
+{
+ return ((map1 == map2) ||
+ ((map1 == NULL) && (map2 == kernel_map)) ||
+ ((map1 == kernel_map) && (map2 == NULL)));
+}
+
+boolean_t
+db_map_current(map)
+ vm_map_t map;
+{
+#if 0
+ thread_t thread;
+
+ return ((map == NULL) ||
+ (map == kernel_map) ||
+ (((thread = current_thread()) != NULL) &&
+ (map == thread->task->map)));
+#else
+ return (1);
+#endif
+}
+
+vm_map_t
+db_map_addr(addr)
+ vm_offset_t addr;
+{
+#if 0
+ thread_t thread;
+
+ /*
+ * We want to return kernel_map for all
+ * non-user addresses, even when debugging
+ * kernel tasks with their own maps.
+ */
+
+ if ((VM_MIN_ADDRESS <= addr) &&
+ (addr < VM_MAX_ADDRESS) &&
+ ((thread = current_thread()) != NULL))
+ return thread->task->map;
+ else
+#endif
+ return kernel_map;
+}
diff --git a/sys/ddb/db_break.h b/sys/ddb/db_break.h
new file mode 100644
index 00000000000..007b87d4540
--- /dev/null
+++ b/sys/ddb/db_break.h
@@ -0,0 +1,64 @@
+/* $NetBSD: db_break.h,v 1.7 1994/10/09 08:29:58 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#ifndef _DDB_DB_BREAK_H_
+#define _DDB_DB_BREAK_H_
+
+#include <vm/vm.h>
+
+/*
+ * Breakpoints.
+ */
+typedef struct db_breakpoint {
+ vm_map_t map; /* in this map */
+ db_addr_t address; /* set here */
+ int init_count; /* number of times to skip bkpt */
+ int count; /* current count */
+ int flags; /* flags: */
+#define BKPT_SINGLE_STEP 0x2 /* to simulate single step */
+#define BKPT_TEMP 0x4 /* temporary */
+ int bkpt_inst; /* saved instruction at bkpt */
+ struct db_breakpoint *link; /* link in in-use or free chain */
+} *db_breakpoint_t;
+
+db_breakpoint_t db_find_breakpoint __P((vm_map_t, db_addr_t));
+db_breakpoint_t db_find_breakpoint_here __P((db_addr_t));
+void db_set_breakpoints __P((void));
+void db_clear_breakpoints __P((void));
+
+db_breakpoint_t db_set_temp_breakpoint __P((db_addr_t));
+void db_delete_temp_breakpoint __P((db_breakpoint_t));
+
+boolean_t db_map_equal __P((vm_map_t, vm_map_t));
+boolean_t db_map_current __P((vm_map_t));
+vm_map_t db_map_addr __P((vm_offset_t));
+
+#endif _DDB_DB_BREAK_H_
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c
new file mode 100644
index 00000000000..7b6a14cb7fc
--- /dev/null
+++ b/sys/ddb/db_command.c
@@ -0,0 +1,507 @@
+/* $NetBSD: db_command.c,v 1.13 1994/10/09 08:29:59 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Command dispatcher.
+ */
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h> /* type definitions */
+
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+#include <ddb/db_command.h>
+
+#include <setjmp.h>
+
+/*
+ * Exported global variables
+ */
+boolean_t db_cmd_loop_done;
+jmp_buf *db_recover;
+
+/*
+ * if 'ed' style: 'dot' is set at start of last item printed,
+ * and '+' points to next line.
+ * Otherwise: 'dot' points to next item, '..' points to last.
+ */
+boolean_t db_ed_style = TRUE;
+
+/*
+ * Utility routine - discard tokens through end-of-line.
+ */
+void
+db_skip_to_eol()
+{
+ int t;
+ do {
+ t = db_read_token();
+ } while (t != tEOL);
+}
+
+/*
+ * Results of command search.
+ */
+#define CMD_UNIQUE 0
+#define CMD_FOUND 1
+#define CMD_NONE 2
+#define CMD_AMBIGUOUS 3
+#define CMD_HELP 4
+
+/*
+ * Search for command prefix.
+ */
+int
+db_cmd_search(name, table, cmdp)
+ char *name;
+ struct db_command *table;
+ struct db_command **cmdp; /* out */
+{
+ struct db_command *cmd;
+ int result = CMD_NONE;
+
+ for (cmd = table; cmd->name != 0; cmd++) {
+ register char *lp;
+ register char *rp;
+ register int c;
+
+ lp = name;
+ rp = cmd->name;
+ while ((c = *lp) == *rp) {
+ if (c == 0) {
+ /* complete match */
+ *cmdp = cmd;
+ return (CMD_UNIQUE);
+ }
+ lp++;
+ rp++;
+ }
+ if (c == 0) {
+ /* end of name, not end of command -
+ partial match */
+ if (result == CMD_FOUND) {
+ result = CMD_AMBIGUOUS;
+ /* but keep looking for a full match -
+ this lets us match single letters */
+ }
+ else {
+ *cmdp = cmd;
+ result = CMD_FOUND;
+ }
+ }
+ }
+ if (result == CMD_NONE) {
+ /* check for 'help' */
+ if (name[0] == 'h' && name[1] == 'e'
+ && name[2] == 'l' && name[3] == 'p')
+ result = CMD_HELP;
+ }
+ return (result);
+}
+
+void
+db_cmd_list(table)
+ struct db_command *table;
+{
+ register struct db_command *cmd;
+
+ for (cmd = table; cmd->name != 0; cmd++) {
+ db_printf("%-12s", cmd->name);
+ db_end_line();
+ }
+}
+
+void
+db_command(last_cmdp, cmd_table)
+ struct db_command **last_cmdp; /* IN_OUT */
+ struct db_command *cmd_table;
+{
+ struct db_command *cmd;
+ int t;
+ char modif[TOK_STRING_SIZE];
+ db_expr_t addr, count;
+ boolean_t have_addr;
+ int result;
+
+ t = db_read_token();
+ if (t == tEOL) {
+ /* empty line repeats last command, at 'next' */
+ cmd = *last_cmdp;
+ addr = (db_expr_t)db_next;
+ have_addr = FALSE;
+ count = 1;
+ modif[0] = '\0';
+ }
+ else if (t == tEXCL) {
+ void db_fncall();
+ db_fncall();
+ return;
+ }
+ else if (t != tIDENT) {
+ db_printf("?\n");
+ db_flush_lex();
+ return;
+ }
+ else {
+ /*
+ * Search for command
+ */
+ while (cmd_table) {
+ result = db_cmd_search(db_tok_string,
+ cmd_table,
+ &cmd);
+ switch (result) {
+ case CMD_NONE:
+ db_printf("No such command\n");
+ db_flush_lex();
+ return;
+ case CMD_AMBIGUOUS:
+ db_printf("Ambiguous\n");
+ db_flush_lex();
+ return;
+ case CMD_HELP:
+ db_cmd_list(cmd_table);
+ db_flush_lex();
+ return;
+ default:
+ break;
+ }
+ if ((cmd_table = cmd->more) != 0) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ db_cmd_list(cmd_table);
+ db_flush_lex();
+ return;
+ }
+ }
+ }
+
+ if ((cmd->flag & CS_OWN) == 0) {
+ /*
+ * Standard syntax:
+ * command [/modifier] [addr] [,count]
+ */
+ t = db_read_token();
+ if (t == tSLASH) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ db_printf("Bad modifier\n");
+ db_flush_lex();
+ return;
+ }
+ db_strcpy(modif, db_tok_string);
+ }
+ else {
+ db_unread_token(t);
+ modif[0] = '\0';
+ }
+
+ if (db_expression(&addr)) {
+ db_dot = (db_addr_t) addr;
+ db_last_addr = db_dot;
+ have_addr = TRUE;
+ }
+ else {
+ addr = (db_expr_t) db_dot;
+ have_addr = FALSE;
+ }
+ t = db_read_token();
+ if (t == tCOMMA) {
+ if (!db_expression(&count)) {
+ db_printf("Count missing\n");
+ db_flush_lex();
+ return;
+ }
+ }
+ else {
+ db_unread_token(t);
+ count = -1;
+ }
+ if ((cmd->flag & CS_MORE) == 0) {
+ db_skip_to_eol();
+ }
+ }
+ }
+ *last_cmdp = cmd;
+ if (cmd != 0) {
+ /*
+ * Execute the command.
+ */
+ (*cmd->fcn)(addr, have_addr, count, modif);
+
+ if (cmd->flag & CS_SET_DOT) {
+ /*
+ * If command changes dot, set dot to
+ * previous address displayed (if 'ed' style).
+ */
+ if (db_ed_style) {
+ db_dot = db_prev;
+ }
+ else {
+ db_dot = db_next;
+ }
+ }
+ else {
+ /*
+ * If command does not change dot,
+ * set 'next' location to be the same.
+ */
+ db_next = db_dot;
+ }
+ }
+}
+
+/*ARGSUSED*/
+void
+db_map_print_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ extern void _vm_map_print();
+ boolean_t full = FALSE;
+
+ if (modif[0] == 'f')
+ full = TRUE;
+
+ _vm_map_print(addr, full, db_printf);
+}
+
+/*ARGSUSED*/
+void
+db_object_print_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ extern void _vm_object_print();
+ boolean_t full = FALSE;
+
+ if (modif[0] == 'f')
+ full = TRUE;
+
+ _vm_object_print(addr, full, db_printf);
+}
+
+/*
+ * 'show' commands
+ */
+extern void db_show_all_procs();
+extern void db_show_callout();
+extern void db_listbreak_cmd();
+extern void db_listwatch_cmd();
+extern void db_show_regs();
+void db_show_help();
+
+struct db_command db_show_all_cmds[] = {
+ { "procs", db_show_all_procs,0, 0 },
+ { "callout", db_show_callout,0, 0 },
+ { (char *)0 }
+};
+
+struct db_command db_show_cmds[] = {
+ { "all", 0, 0, db_show_all_cmds },
+ { "registers", db_show_regs, 0, 0 },
+ { "breaks", db_listbreak_cmd, 0, 0 },
+ { "watches", db_listwatch_cmd, 0, 0 },
+ { "map", db_map_print_cmd, 0, 0 },
+ { "object", db_object_print_cmd, 0, 0 },
+ { (char *)0, }
+};
+
+extern void db_print_cmd(), db_examine_cmd(), db_set_cmd();
+extern void db_search_cmd();
+extern void db_write_cmd();
+extern void db_delete_cmd(), db_breakpoint_cmd();
+extern void db_deletewatch_cmd(), db_watchpoint_cmd();
+extern void db_single_step_cmd(), db_trace_until_call_cmd(),
+ db_trace_until_matching_cmd(), db_continue_cmd();
+extern void db_stack_trace_cmd();
+void db_help_cmd();
+void db_fncall();
+
+struct db_command db_command_table[] = {
+#ifdef DB_MACHINE_COMMANDS
+ /* this must be the first entry, if it exists */
+ { "machine", 0, 0, 0},
+#endif
+ { "print", db_print_cmd, 0, 0 },
+ { "examine", db_examine_cmd, CS_SET_DOT, 0 },
+ { "x", db_examine_cmd, CS_SET_DOT, 0 },
+ { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 },
+ { "set", db_set_cmd, CS_OWN, 0 },
+ { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 },
+ { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 },
+ { "delete", db_delete_cmd, 0, 0 },
+ { "d", db_delete_cmd, 0, 0 },
+ { "break", db_breakpoint_cmd, 0, 0 },
+ { "dwatch", db_deletewatch_cmd, 0, 0 },
+ { "watch", db_watchpoint_cmd, CS_MORE, 0 },
+ { "step", db_single_step_cmd, 0, 0 },
+ { "s", db_single_step_cmd, 0, 0 },
+ { "continue", db_continue_cmd, 0, 0 },
+ { "c", db_continue_cmd, 0, 0 },
+ { "until", db_trace_until_call_cmd,0, 0 },
+ { "next", db_trace_until_matching_cmd,0, 0 },
+ { "match", db_trace_until_matching_cmd,0, 0 },
+ { "trace", db_stack_trace_cmd, 0, 0 },
+ { "call", db_fncall, CS_OWN, 0 },
+ { "ps", db_show_all_procs, 0, 0 },
+ { "callout", db_show_callout, 0, 0 },
+ { "show", 0, 0, db_show_cmds },
+ { (char *)0, }
+};
+
+#ifdef DB_MACHINE_COMMANDS
+
+/* this function should be called to install the machine dependent
+ commands. It should be called before the debugger is enabled */
+void db_machine_commands_install(ptr)
+struct db_command *ptr;
+{
+ db_command_table[0].more = ptr;
+ return;
+}
+
+#endif
+
+struct db_command *db_last_command = 0;
+
+void
+db_help_cmd()
+{
+ struct db_command *cmd = db_command_table;
+
+ while (cmd->name != 0) {
+ db_printf("%-12s", cmd->name);
+ db_end_line();
+ cmd++;
+ }
+}
+
+void
+db_command_loop()
+{
+ jmp_buf db_jmpbuf;
+ jmp_buf *savejmp = db_recover;
+ extern int db_output_line;
+
+ /*
+ * Initialize 'prev' and 'next' to dot.
+ */
+ db_prev = db_dot;
+ db_next = db_dot;
+
+ db_cmd_loop_done = 0;
+ (void) setjmp(*(db_recover = &db_jmpbuf));
+
+ while (!db_cmd_loop_done) {
+ if (db_print_position() != 0)
+ db_printf("\n");
+ db_output_line = 0;
+
+ db_printf("db> ");
+ (void) db_read_line();
+
+ db_command(&db_last_command, db_command_table);
+ }
+
+ db_recover = savejmp;
+}
+
+void
+db_error(s)
+ char *s;
+{
+ if (s)
+ db_printf(s);
+ db_flush_lex();
+ longjmp(*db_recover, 1);
+}
+
+
+/*
+ * Call random function:
+ * !expr(arg,arg,arg)
+ */
+void
+db_fncall()
+{
+ db_expr_t fn_addr;
+#define MAXARGS 11
+ db_expr_t args[MAXARGS];
+ int nargs = 0;
+ db_expr_t retval;
+ db_expr_t (*func)();
+ int t;
+
+ if (!db_expression(&fn_addr)) {
+ db_printf("Bad function\n");
+ db_flush_lex();
+ return;
+ }
+ func = (db_expr_t (*) ()) fn_addr;
+
+ t = db_read_token();
+ if (t == tLPAREN) {
+ if (db_expression(&args[0])) {
+ nargs++;
+ while ((t = db_read_token()) == tCOMMA) {
+ if (nargs == MAXARGS) {
+ db_printf("Too many arguments\n");
+ db_flush_lex();
+ return;
+ }
+ if (!db_expression(&args[nargs])) {
+ db_printf("Argument missing\n");
+ db_flush_lex();
+ return;
+ }
+ nargs++;
+ }
+ db_unread_token(t);
+ }
+ if (db_read_token() != tRPAREN) {
+ db_printf("?\n");
+ db_flush_lex();
+ return;
+ }
+ }
+ db_skip_to_eol();
+
+ while (nargs < MAXARGS) {
+ args[nargs++] = 0;
+ }
+
+ retval = (*func)(args[0], args[1], args[2], args[3], args[4],
+ args[5], args[6], args[7], args[8], args[9] );
+ db_printf("%#n\n", retval);
+}
diff --git a/sys/ddb/db_command.h b/sys/ddb/db_command.h
new file mode 100644
index 00000000000..47cdf5db01f
--- /dev/null
+++ b/sys/ddb/db_command.h
@@ -0,0 +1,59 @@
+/* $NetBSD: db_command.h,v 1.7 1994/10/09 08:30:00 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Command loop declarations.
+ */
+void db_command_loop __P((void));
+void db_skip_to_eol __P((void));
+
+void db_error __P((char *)); /* report error */
+
+db_addr_t db_dot; /* current location */
+db_addr_t db_last_addr; /* last explicit address typed */
+db_addr_t db_prev; /* last address examined
+ or written */
+db_addr_t db_next; /* next address to be examined
+ or written */
+
+/*
+ * Command table
+ */
+struct db_command {
+ char *name; /* command name */
+ void (*fcn)(); /* function to call */
+ int flag; /* extra info: */
+#define CS_OWN 0x1 /* non-standard syntax */
+#define CS_MORE 0x2 /* standard syntax, but may have other
+ words at end */
+#define CS_SET_DOT 0x100 /* set dot after command */
+ struct db_command *more; /* another level of command */
+};
diff --git a/sys/ddb/db_examine.c b/sys/ddb/db_examine.c
new file mode 100644
index 00000000000..07a7c691fc3
--- /dev/null
+++ b/sys/ddb/db_examine.c
@@ -0,0 +1,327 @@
+/* $NetBSD: db_examine.c,v 1.9 1994/11/17 04:51:50 gwr Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h> /* type definitions */
+
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
+
+char db_examine_format[TOK_STRING_SIZE] = "x";
+
+extern db_addr_t db_disasm(/* db_addr_t, boolean_t */);
+ /* instruction disassembler */
+
+/*
+ * Examine (print) data. Syntax is:
+ * x/[bhl][cdiorsuxz]*
+ * For example, the command:
+ * x/bxxxx
+ * should print:
+ * address: 01 23 45 67
+ */
+/*ARGSUSED*/
+void
+db_examine_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ if (modif[0] != '\0')
+ db_strcpy(db_examine_format, modif);
+
+ if (count == -1)
+ count = 1;
+
+ db_examine((db_addr_t) addr, db_examine_format, count);
+}
+
+db_examine(addr, fmt, count)
+ register
+ db_addr_t addr;
+ char * fmt; /* format string */
+ int count; /* repeat count */
+{
+ int c;
+ db_expr_t value;
+ int size;
+ int width;
+ char * fp;
+
+ while (--count >= 0) {
+ fp = fmt;
+ size = 4;
+ width = 12;
+ while ((c = *fp++) != 0) {
+ if (db_print_position() == 0) {
+ /* Always print the address. */
+ db_printsym(addr, DB_STGY_ANY);
+ db_printf(":\t");
+ db_prev = addr;
+ }
+ switch (c) {
+ case 'b': /* byte */
+ size = 1;
+ width = 4;
+ break;
+ case 'h': /* half-word */
+ size = 2;
+ width = 8;
+ break;
+ case 'l': /* long-word */
+ size = 4;
+ width = 12;
+ break;
+ case 'a': /* address */
+ db_printf("= 0x%x\n", addr);
+ break;
+ case 'r': /* signed, current radix */
+ value = db_get_value(addr, size, TRUE);
+ addr += size;
+ db_printf("%-*r", width, value);
+ break;
+ case 'x': /* unsigned hex */
+ value = db_get_value(addr, size, FALSE);
+ addr += size;
+ db_printf("%-*x", width, value);
+ break;
+ case 'z': /* signed hex */
+ value = db_get_value(addr, size, TRUE);
+ addr += size;
+ db_printf("%-*z", width, value);
+ break;
+ case 'd': /* signed decimal */
+ value = db_get_value(addr, size, TRUE);
+ addr += size;
+ db_printf("%-*d", width, value);
+ break;
+ case 'u': /* unsigned decimal */
+ value = db_get_value(addr, size, FALSE);
+ addr += size;
+ db_printf("%-*u", width, value);
+ break;
+ case 'o': /* unsigned octal */
+ value = db_get_value(addr, size, FALSE);
+ addr += size;
+ db_printf("%-*o", width, value);
+ break;
+ case 'c': /* character */
+ value = db_get_value(addr, 1, FALSE);
+ addr += 1;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ break;
+ case 's': /* null-terminated string */
+ for (;;) {
+ value = db_get_value(addr, 1, FALSE);
+ addr += 1;
+ if (value == 0)
+ break;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ }
+ break;
+ case 'i': /* instruction */
+ addr = db_disasm(addr, FALSE);
+ break;
+ case 'I': /* instruction, alternate form */
+ addr = db_disasm(addr, TRUE);
+ break;
+ default:
+ break;
+ }
+ if (db_print_position() != 0)
+ db_end_line();
+ }
+ }
+ db_next = addr;
+}
+
+/*
+ * Print value.
+ */
+char db_print_format = 'x';
+
+/*ARGSUSED*/
+void
+db_print_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ db_expr_t value;
+
+ if (modif[0] != '\0')
+ db_print_format = modif[0];
+
+ switch (db_print_format) {
+ case 'a':
+ db_printsym((db_addr_t)addr, DB_STGY_ANY);
+ break;
+ case 'r':
+ db_printf("%11r", addr);
+ break;
+ case 'x':
+ db_printf("%8x", addr);
+ break;
+ case 'z':
+ db_printf("%8z", addr);
+ break;
+ case 'd':
+ db_printf("%11d", addr);
+ break;
+ case 'u':
+ db_printf("%11u", addr);
+ break;
+ case 'o':
+ db_printf("%16o", addr);
+ break;
+ case 'c':
+ value = addr & 0xFF;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ break;
+ }
+ db_printf("\n");
+}
+
+db_print_loc_and_inst(loc)
+ db_addr_t loc;
+{
+ db_printsym(loc, DB_STGY_PROC);
+ db_printf(":\t");
+ (void) db_disasm(loc, FALSE);
+}
+
+db_strcpy(dst, src)
+ register char *dst;
+ register char *src;
+{
+ while (*dst++ = *src++)
+ ;
+}
+
+/*
+ * Search for a value in memory.
+ * Syntax: search [/bhl] addr value [mask] [,count]
+ */
+void
+db_search_cmd()
+{
+ int t;
+ db_addr_t addr;
+ int size;
+ db_expr_t value;
+ db_expr_t mask;
+ unsigned int count;
+
+ t = db_read_token();
+ if (t == tSLASH) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ bad_modifier:
+ db_printf("Bad modifier\n");
+ db_flush_lex();
+ return;
+ }
+
+ if (!strcmp(db_tok_string, "b"))
+ size = 1;
+ else if (!strcmp(db_tok_string, "h"))
+ size = 2;
+ else if (!strcmp(db_tok_string, "l"))
+ size = 4;
+ else
+ goto bad_modifier;
+ } else {
+ db_unread_token(t);
+ size = 4;
+ }
+
+ if (!db_expression(&addr)) {
+ db_printf("Address missing\n");
+ db_flush_lex();
+ return;
+ }
+
+ if (!db_expression(&value)) {
+ db_printf("Value missing\n");
+ db_flush_lex();
+ return;
+ }
+
+ if (!db_expression(&mask))
+ mask = 0xffffffff;
+
+ t = db_read_token();
+ if (t == tCOMMA) {
+ if (!db_expression(&count)) {
+ db_printf("Count missing\n");
+ db_flush_lex();
+ return;
+ }
+ } else {
+ db_unread_token(t);
+ count = -1; /* effectively forever */
+ }
+ db_skip_to_eol();
+
+ db_search(addr, size, value, mask, count);
+}
+
+db_search(addr, size, value, mask, count)
+ register
+ db_addr_t addr;
+ int size;
+ db_expr_t value;
+ db_expr_t mask;
+ unsigned int count;
+{
+ while (count-- != 0) {
+ db_prev = addr;
+ if ((db_get_value(addr, size, FALSE) & mask) == value)
+ break;
+ addr += size;
+ }
+ db_next = addr;
+}
diff --git a/sys/ddb/db_expr.c b/sys/ddb/db_expr.c
new file mode 100644
index 00000000000..1182a1f9993
--- /dev/null
+++ b/sys/ddb/db_expr.c
@@ -0,0 +1,226 @@
+/* $NetBSD: db_expr.c,v 1.4 1994/06/29 06:31:06 cgd Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+
+boolean_t
+db_term(valuep)
+ db_expr_t *valuep;
+{
+ int t;
+
+ t = db_read_token();
+ if (t == tIDENT) {
+ if (!db_value_of_name(db_tok_string, valuep)) {
+ db_error("Symbol not found\n");
+ /*NOTREACHED*/
+ }
+ return (TRUE);
+ }
+ if (t == tNUMBER) {
+ *valuep = (db_expr_t)db_tok_number;
+ return (TRUE);
+ }
+ if (t == tDOT) {
+ *valuep = (db_expr_t)db_dot;
+ return (TRUE);
+ }
+ if (t == tDOTDOT) {
+ *valuep = (db_expr_t)db_prev;
+ return (TRUE);
+ }
+ if (t == tPLUS) {
+ *valuep = (db_expr_t) db_next;
+ return (TRUE);
+ }
+ if (t == tDITTO) {
+ *valuep = (db_expr_t)db_last_addr;
+ return (TRUE);
+ }
+ if (t == tDOLLAR) {
+ if (!db_get_variable(valuep))
+ return (FALSE);
+ return (TRUE);
+ }
+ if (t == tLPAREN) {
+ if (!db_expression(valuep)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ t = db_read_token();
+ if (t != tRPAREN) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ return (TRUE);
+ }
+ db_unread_token(t);
+ return (FALSE);
+}
+
+boolean_t
+db_unary(valuep)
+ db_expr_t *valuep;
+{
+ int t;
+
+ t = db_read_token();
+ if (t == tMINUS) {
+ if (!db_unary(valuep)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ *valuep = -*valuep;
+ return (TRUE);
+ }
+ if (t == tSTAR) {
+ /* indirection */
+ if (!db_unary(valuep)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ *valuep = db_get_value((db_addr_t)*valuep, sizeof(int), FALSE);
+ return (TRUE);
+ }
+ db_unread_token(t);
+ return (db_term(valuep));
+}
+
+boolean_t
+db_mult_expr(valuep)
+ db_expr_t *valuep;
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_unary(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tSTAR || t == tSLASH || t == tPCT || t == tHASH) {
+ if (!db_term(&rhs)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ if (t == tSTAR)
+ lhs *= rhs;
+ else {
+ if (rhs == 0) {
+ db_error("Divide by 0\n");
+ /*NOTREACHED*/
+ }
+ if (t == tSLASH)
+ lhs /= rhs;
+ else if (t == tPCT)
+ lhs %= rhs;
+ else
+ lhs = ((lhs+rhs-1)/rhs)*rhs;
+ }
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+boolean_t
+db_add_expr(valuep)
+ db_expr_t *valuep;
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_mult_expr(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tPLUS || t == tMINUS) {
+ if (!db_mult_expr(&rhs)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ if (t == tPLUS)
+ lhs += rhs;
+ else
+ lhs -= rhs;
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+boolean_t
+db_shift_expr(valuep)
+ db_expr_t *valuep;
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_add_expr(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tSHIFT_L || t == tSHIFT_R) {
+ if (!db_add_expr(&rhs)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ if (rhs < 0) {
+ db_error("Negative shift amount\n");
+ /*NOTREACHED*/
+ }
+ if (t == tSHIFT_L)
+ lhs <<= rhs;
+ else {
+ /* Shift right is unsigned */
+ lhs = (unsigned) lhs >> rhs;
+ }
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+int
+db_expression(valuep)
+ db_expr_t *valuep;
+{
+ return (db_shift_expr(valuep));
+}
diff --git a/sys/ddb/db_input.c b/sys/ddb/db_input.c
new file mode 100644
index 00000000000..dd8ef077b33
--- /dev/null
+++ b/sys/ddb/db_input.c
@@ -0,0 +1,246 @@
+/* $NetBSD: db_input.c,v 1.6 1994/10/26 17:57:50 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <ddb/db_output.h>
+
+/*
+ * Character input and editing.
+ */
+
+/*
+ * We don't track output position while editing input,
+ * since input always ends with a new-line. We just
+ * reset the line position at the end.
+ */
+char * db_lbuf_start; /* start of input line buffer */
+char * db_lbuf_end; /* end of input line buffer */
+char * db_lc; /* current character */
+char * db_le; /* one past last character */
+
+#define CTRL(c) ((c) & 0x1f)
+#define isspace(c) ((c) == ' ' || (c) == '\t')
+#define BLANK ' '
+#define BACKUP '\b'
+
+void
+db_putstring(s, count)
+ char *s;
+ int count;
+{
+ while (--count >= 0)
+ cnputc(*s++);
+}
+
+void
+db_putnchars(c, count)
+ int c;
+ int count;
+{
+ while (--count >= 0)
+ cnputc(c);
+}
+
+/*
+ * Delete N characters, forward or backward
+ */
+#define DEL_FWD 0
+#define DEL_BWD 1
+void
+db_delete(n, bwd)
+ int n;
+ int bwd;
+{
+ register char *p;
+
+ if (bwd) {
+ db_lc -= n;
+ db_putnchars(BACKUP, n);
+ }
+ for (p = db_lc; p < db_le-n; p++) {
+ *p = *(p+n);
+ cnputc(*p);
+ }
+ db_putnchars(BLANK, n);
+ db_putnchars(BACKUP, db_le - db_lc);
+ db_le -= n;
+}
+
+/* returns TRUE at end-of-line */
+int
+db_inputchar(c)
+ int c;
+{
+ switch (c) {
+ case CTRL('b'):
+ /* back up one character */
+ if (db_lc > db_lbuf_start) {
+ cnputc(BACKUP);
+ db_lc--;
+ }
+ break;
+ case CTRL('f'):
+ /* forward one character */
+ if (db_lc < db_le) {
+ cnputc(*db_lc);
+ db_lc++;
+ }
+ break;
+ case CTRL('a'):
+ /* beginning of line */
+ while (db_lc > db_lbuf_start) {
+ cnputc(BACKUP);
+ db_lc--;
+ }
+ break;
+ case CTRL('e'):
+ /* end of line */
+ while (db_lc < db_le) {
+ cnputc(*db_lc);
+ db_lc++;
+ }
+ break;
+ case CTRL('h'):
+ case 0177:
+ /* erase previous character */
+ if (db_lc > db_lbuf_start)
+ db_delete(1, DEL_BWD);
+ break;
+ case CTRL('d'):
+ /* erase next character */
+ if (db_lc < db_le)
+ db_delete(1, DEL_FWD);
+ break;
+ case CTRL('k'):
+ /* delete to end of line */
+ if (db_lc < db_le)
+ db_delete(db_le - db_lc, DEL_FWD);
+ break;
+ case CTRL('t'):
+ /* twiddle last 2 characters */
+ if (db_lc >= db_lbuf_start + 2) {
+ c = db_lc[-2];
+ db_lc[-2] = db_lc[-1];
+ db_lc[-1] = c;
+ cnputc(BACKUP);
+ cnputc(BACKUP);
+ cnputc(db_lc[-2]);
+ cnputc(db_lc[-1]);
+ }
+ break;
+ case CTRL('r'):
+ db_putstring("^R\n", 3);
+ if (db_le > db_lbuf_start) {
+ db_putstring(db_lbuf_start, db_le - db_lbuf_start);
+ db_putnchars(BACKUP, db_le - db_lc);
+ }
+ break;
+ case '\n':
+ case '\r':
+ *db_le++ = c;
+ return (1);
+ default:
+ if (db_le == db_lbuf_end) {
+ cnputc('\007');
+ }
+ else if (c >= ' ' && c <= '~') {
+ register char *p;
+
+ for (p = db_le; p > db_lc; p--)
+ *p = *(p-1);
+ *db_lc++ = c;
+ db_le++;
+ cnputc(c);
+ db_putstring(db_lc, db_le - db_lc);
+ db_putnchars(BACKUP, db_le - db_lc);
+ }
+ break;
+ }
+ return (0);
+}
+
+int
+db_readline(lstart, lsize)
+ char * lstart;
+ int lsize;
+{
+ db_force_whitespace(); /* synch output position */
+
+ db_lbuf_start = lstart;
+ db_lbuf_end = lstart + lsize;
+ db_lc = lstart;
+ db_le = lstart;
+
+ while (!db_inputchar(cngetc()))
+ continue;
+
+ db_putchar('\n'); /* synch output position */
+
+ *db_le = 0;
+ return (db_le - db_lbuf_start);
+}
+
+void
+db_check_interrupt()
+{
+ register int c;
+
+ c = cnmaygetc();
+ switch (c) {
+ case -1: /* no character */
+ return;
+
+ case CTRL('c'):
+ db_error((char *)0);
+ /*NOTREACHED*/
+
+ case CTRL('s'):
+ do {
+ c = cnmaygetc();
+ if (c == CTRL('c')) {
+ db_error((char *)0);
+ /*NOTREACHED*/
+ }
+ } while (c != CTRL('q'));
+ break;
+
+ default:
+ /* drop on floor */
+ break;
+ }
+}
+
+cnmaygetc ()
+{
+ return (-1);
+}
diff --git a/sys/ddb/db_lex.c b/sys/ddb/db_lex.c
new file mode 100644
index 00000000000..c4fec55bebd
--- /dev/null
+++ b/sys/ddb/db_lex.c
@@ -0,0 +1,276 @@
+/* $NetBSD: db_lex.c,v 1.7 1994/10/09 08:56:25 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Lexical analyzer.
+ */
+#include <sys/param.h>
+
+#include <ddb/db_lex.h>
+
+char db_line[120];
+char * db_lp, *db_endlp;
+
+int
+db_read_line()
+{
+ int i;
+
+ i = db_readline(db_line, sizeof(db_line));
+ if (i == 0)
+ return (0); /* EOI */
+ db_lp = db_line;
+ db_endlp = db_lp + i;
+ return (i);
+}
+
+void
+db_flush_line()
+{
+ db_lp = db_line;
+ db_endlp = db_line;
+}
+
+int db_look_char = 0;
+
+int
+db_read_char()
+{
+ int c;
+
+ if (db_look_char != 0) {
+ c = db_look_char;
+ db_look_char = 0;
+ }
+ else if (db_lp >= db_endlp)
+ c = -1;
+ else
+ c = *db_lp++;
+ return (c);
+}
+
+void
+db_unread_char(c)
+ int c;
+{
+ db_look_char = c;
+}
+
+int db_look_token = 0;
+
+void
+db_unread_token(t)
+ int t;
+{
+ db_look_token = t;
+}
+
+int
+db_read_token()
+{
+ int t;
+
+ if (db_look_token) {
+ t = db_look_token;
+ db_look_token = 0;
+ }
+ else
+ t = db_lex();
+ return (t);
+}
+
+int db_radix = 16;
+
+void
+db_flush_lex()
+{
+ db_flush_line();
+ db_look_char = 0;
+ db_look_token = 0;
+}
+
+int
+db_lex()
+{
+ int c;
+
+ c = db_read_char();
+ while (c <= ' ' || c > '~') {
+ if (c == '\n' || c == -1)
+ return (tEOL);
+ c = db_read_char();
+ }
+
+ if (c >= '0' && c <= '9') {
+ /* number */
+ int r, digit;
+
+ if (c > '0')
+ r = db_radix;
+ else {
+ c = db_read_char();
+ if (c == 'O' || c == 'o')
+ r = 8;
+ else if (c == 'T' || c == 't')
+ r = 10;
+ else if (c == 'X' || c == 'x')
+ r = 16;
+ else {
+ r = db_radix;
+ db_unread_char(c);
+ }
+ c = db_read_char();
+ }
+ db_tok_number = 0;
+ for (;;) {
+ if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
+ digit = c - '0';
+ else if (r == 16 && ((c >= 'A' && c <= 'F') ||
+ (c >= 'a' && c <= 'f'))) {
+ if (c >= 'a')
+ digit = c - 'a' + 10;
+ else if (c >= 'A')
+ digit = c - 'A' + 10;
+ }
+ else
+ break;
+ db_tok_number = db_tok_number * r + digit;
+ c = db_read_char();
+ }
+ if ((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c == '_'))
+ {
+ db_error("Bad character in number\n");
+ /*NOTREACHED*/
+ }
+ db_unread_char(c);
+ return (tNUMBER);
+ }
+ if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ c == '_' || c == '\\')
+ {
+ /* string */
+ char *cp;
+
+ cp = db_tok_string;
+ if (c == '\\') {
+ c = db_read_char();
+ if (c == '\n' || c == -1) {
+ db_error("Bad escape\n");
+ /*NOTREACHED*/
+ }
+ }
+ *cp++ = c;
+ while (1) {
+ c = db_read_char();
+ if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_' || c == '\\' || c == ':')
+ {
+ if (c == '\\') {
+ c = db_read_char();
+ if (c == '\n' || c == -1) {
+ db_error("Bad escape\n");
+ /*NOTREACHED*/
+ }
+ }
+ *cp++ = c;
+ if (cp == db_tok_string+sizeof(db_tok_string)) {
+ db_error("String too long\n");
+ /*NOTREACHED*/
+ }
+ continue;
+ }
+ else {
+ *cp = '\0';
+ break;
+ }
+ }
+ db_unread_char(c);
+ return (tIDENT);
+ }
+
+ switch (c) {
+ case '+':
+ return (tPLUS);
+ case '-':
+ return (tMINUS);
+ case '.':
+ c = db_read_char();
+ if (c == '.')
+ return (tDOTDOT);
+ db_unread_char(c);
+ return (tDOT);
+ case '*':
+ return (tSTAR);
+ case '/':
+ return (tSLASH);
+ case '=':
+ return (tEQ);
+ case '%':
+ return (tPCT);
+ case '#':
+ return (tHASH);
+ case '(':
+ return (tLPAREN);
+ case ')':
+ return (tRPAREN);
+ case ',':
+ return (tCOMMA);
+ case '"':
+ return (tDITTO);
+ case '$':
+ return (tDOLLAR);
+ case '!':
+ return (tEXCL);
+ case '<':
+ c = db_read_char();
+ if (c == '<')
+ return (tSHIFT_L);
+ db_unread_char(c);
+ break;
+ case '>':
+ c = db_read_char();
+ if (c == '>')
+ return (tSHIFT_R);
+ db_unread_char(c);
+ break;
+ case -1:
+ return (tEOF);
+ }
+ db_printf("Bad character\n");
+ db_flush_lex();
+ return (tEOF);
+}
diff --git a/sys/ddb/db_lex.h b/sys/ddb/db_lex.h
new file mode 100644
index 00000000000..c49294d0332
--- /dev/null
+++ b/sys/ddb/db_lex.h
@@ -0,0 +1,72 @@
+/* $NetBSD: db_lex.h,v 1.6 1994/10/09 08:30:06 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Lexical analyzer.
+ */
+int db_read_line __P((void));
+void db_flush_line __P((void));
+int db_read_char __P((void));
+void db_unread_char __P((int));
+int db_read_token __P((void));
+void db_unread_token __P((int));
+void db_flush_lex __P((void));
+
+int db_tok_number;
+#define TOK_STRING_SIZE 120
+char db_tok_string[TOK_STRING_SIZE];
+int db_radix;
+
+#define tEOF (-1)
+#define tEOL 1
+#define tNUMBER 2
+#define tIDENT 3
+#define tPLUS 4
+#define tMINUS 5
+#define tDOT 6
+#define tSTAR 7
+#define tSLASH 8
+#define tEQ 9
+#define tLPAREN 10
+#define tRPAREN 11
+#define tPCT 12
+#define tHASH 13
+#define tCOMMA 14
+#define tDITTO 15
+#define tDOLLAR 16
+#define tEXCL 17
+#define tSHIFT_L 18
+#define tSHIFT_R 19
+#define tDOTDOT 20
+
+
+
+
diff --git a/sys/ddb/db_output.c b/sys/ddb/db_output.c
new file mode 100644
index 00000000000..eb6c46f5811
--- /dev/null
+++ b/sys/ddb/db_output.c
@@ -0,0 +1,423 @@
+/* $NetBSD: db_output.c,v 1.8 1994/06/29 22:41:41 deraadt Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Printf and character output for debugger.
+ */
+#include <sys/param.h>
+
+#include <machine/stdarg.h>
+
+/*
+ * Character output - tracks position in line.
+ * To do this correctly, we should know how wide
+ * the output device is - then we could zero
+ * the line position when the output device wraps
+ * around to the start of the next line.
+ *
+ * Instead, we count the number of spaces printed
+ * since the last printing character so that we
+ * don't print trailing spaces. This avoids most
+ * of the wraparounds.
+ */
+
+#ifndef DB_MAX_LINE
+#define DB_MAX_LINE 24 /* maximum line */
+#define DB_MAX_WIDTH 80 /* maximum width */
+#endif DB_MAX_LINE
+
+#define DB_MIN_MAX_WIDTH 20 /* minimum max width */
+#define DB_MIN_MAX_LINE 3 /* minimum max line */
+#define CTRL(c) ((c) & 0xff)
+
+int db_output_position = 0; /* output column */
+int db_output_line = 0; /* output line number */
+int db_last_non_space = 0; /* last non-space character */
+int db_tab_stop_width = 8; /* how wide are tab stops? */
+#define NEXT_TAB(i) \
+ ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
+int db_max_line = DB_MAX_LINE; /* output max lines */
+int db_max_width = DB_MAX_WIDTH; /* output line width */
+
+extern void db_check_interrupt();
+
+/*
+ * Force pending whitespace.
+ */
+void
+db_force_whitespace()
+{
+ register int last_print, next_tab;
+
+ last_print = db_last_non_space;
+ while (last_print < db_output_position) {
+ next_tab = NEXT_TAB(last_print);
+ if (next_tab <= db_output_position) {
+ while (last_print < next_tab) { /* DON'T send a tab!!! */
+ cnputc(' ');
+ last_print++;
+ }
+ }
+ else {
+ cnputc(' ');
+ last_print++;
+ }
+ }
+ db_last_non_space = db_output_position;
+}
+
+static void
+db_more()
+{
+ register char *p;
+ int quit_output = 0;
+
+ for (p = "--db_more--"; *p; p++)
+ cnputc(*p);
+ switch(cngetc()) {
+ case ' ':
+ db_output_line = 0;
+ break;
+ case 'q':
+ case CTRL('c'):
+ db_output_line = 0;
+ quit_output = 1;
+ break;
+ default:
+ db_output_line--;
+ break;
+ }
+ p = "\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b";
+ while (*p)
+ cnputc(*p++);
+ if (quit_output) {
+ db_error(0);
+ /* NOTREACHED */
+ }
+}
+
+/*
+ * Output character. Buffer whitespace.
+ */
+db_putchar(c)
+ int c; /* character to output */
+{
+ if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1)
+ db_more();
+ if (c > ' ' && c <= '~') {
+ /*
+ * Printing character.
+ * If we have spaces to print, print them first.
+ * Use tabs if possible.
+ */
+ db_force_whitespace();
+ cnputc(c);
+ db_output_position++;
+ if (db_max_width >= DB_MIN_MAX_WIDTH
+ && db_output_position >= db_max_width-1) {
+ /* auto new line */
+ cnputc('\n');
+ db_output_position = 0;
+ db_last_non_space = 0;
+ db_output_line++;
+ }
+ db_last_non_space = db_output_position;
+ }
+ else if (c == '\n') {
+ /* Return */
+ cnputc(c);
+ db_output_position = 0;
+ db_last_non_space = 0;
+ db_output_line++;
+ db_check_interrupt();
+ }
+ else if (c == '\t') {
+ /* assume tabs every 8 positions */
+ db_output_position = NEXT_TAB(db_output_position);
+ }
+ else if (c == ' ') {
+ /* space */
+ db_output_position++;
+ }
+ else if (c == '\007') {
+ /* bell */
+ cnputc(c);
+ }
+ /* other characters are assumed non-printing */
+}
+
+/*
+ * Return output position
+ */
+int
+db_print_position()
+{
+ return (db_output_position);
+}
+
+/*
+ * Printing
+ */
+extern int db_radix;
+
+/*VARARGS1*/
+#ifdef __STDC__
+db_printf(char *fmt, ...)
+#else
+db_printf(fmt, va_alist)
+ char *fmt;
+#endif
+{
+ va_list listp;
+ va_start(listp, fmt);
+ db_printf_guts (fmt, listp);
+ va_end(listp);
+}
+
+/* alternate name */
+
+/*VARARGS1*/
+#ifdef __STDC__
+kdbprintf(char *fmt, ...)
+#else
+kdbprintf(fmt, va_alist)
+ char *fmt;
+#endif
+{
+ va_list listp;
+ va_start(listp, fmt);
+ db_printf_guts (fmt, listp);
+ va_end(listp);
+}
+
+/*
+ * End line if too long.
+ */
+void
+db_end_line()
+{
+ if (db_output_position >= db_max_width)
+ db_printf("\n");
+}
+
+/*
+ * Put a number (base <= 16) in a buffer in reverse order; return an
+ * optional length and a pointer to the NULL terminated (preceded?)
+ * buffer.
+ */
+static char *
+db_ksprintn(ul, base, lenp)
+ register u_long ul;
+ register int base, *lenp;
+{ /* A long in base 8, plus NULL. */
+ static char buf[sizeof(long) * NBBY / 3 + 2];
+ register char *p;
+
+ p = buf;
+ do {
+ *++p = "0123456789abcdef"[ul % base];
+ } while (ul /= base);
+ if (lenp)
+ *lenp = p - buf;
+ return (p);
+}
+
+db_printf_guts(fmt, ap)
+ register const char *fmt;
+ va_list ap;
+{
+ register char *p;
+ register int ch, n;
+ u_long ul;
+ int base, lflag, tmp, width;
+ char padc;
+ int ladjust;
+ int sharpflag;
+ int neg;
+
+ for (;;) {
+ padc = ' ';
+ width = 0;
+ while ((ch = *(u_char *)fmt++) != '%') {
+ if (ch == '\0')
+ return;
+ db_putchar(ch);
+ }
+ lflag = 0;
+ ladjust = 0;
+ sharpflag = 0;
+ neg = 0;
+reswitch: switch (ch = *(u_char *)fmt++) {
+ case '0':
+ padc = '0';
+ goto reswitch;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ for (width = 0;; ++fmt) {
+ width = width * 10 + ch - '0';
+ ch = *fmt;
+ if (ch < '0' || ch > '9')
+ break;
+ }
+ goto reswitch;
+ case 'l':
+ lflag = 1;
+ goto reswitch;
+ case '-':
+ ladjust = 1;
+ goto reswitch;
+ case '#':
+ sharpflag = 1;
+ goto reswitch;
+ case 'b':
+ ul = va_arg(ap, int);
+ p = va_arg(ap, char *);
+ for (p = db_ksprintn(ul, *p++, NULL); ch = *p--;)
+ db_putchar(ch);
+
+ if (!ul)
+ break;
+
+ for (tmp = 0; n = *p++;) {
+ if (ul & (1 << (n - 1))) {
+ db_putchar(tmp ? ',' : '<');
+ for (; (n = *p) > ' '; ++p)
+ db_putchar(n);
+ tmp = 1;
+ } else
+ for (; *p > ' '; ++p);
+ }
+ if (tmp)
+ db_putchar('>');
+ break;
+ case '*':
+ width = va_arg (ap, int);
+ if (width < 0) {
+ ladjust = !ladjust;
+ width = -width;
+ }
+ goto reswitch;
+ case 'c':
+ db_putchar(va_arg(ap, int));
+ break;
+ case 's':
+ p = va_arg(ap, char *);
+ width -= strlen (p);
+ if (!ladjust && width > 0)
+ while (width--)
+ db_putchar (padc);
+ while (ch = *p++)
+ db_putchar(ch);
+ if (ladjust && width > 0)
+ while (width--)
+ db_putchar (padc);
+ break;
+ case 'r':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ if ((long)ul < 0) {
+ neg = 1;
+ ul = -(long)ul;
+ }
+ base = db_radix;
+ if (base < 8 || base > 16)
+ base = 10;
+ goto number;
+ case 'n':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = db_radix;
+ if (base < 8 || base > 16)
+ base = 10;
+ goto number;
+ case 'd':
+ ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
+ if ((long)ul < 0) {
+ neg = 1;
+ ul = -(long)ul;
+ }
+ base = 10;
+ goto number;
+ case 'o':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = 8;
+ goto number;
+ case 'u':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = 10;
+ goto number;
+ case 'z':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ if ((long)ul < 0) {
+ neg = 1;
+ ul = -(long)ul;
+ }
+ base = 16;
+ goto number;
+ case 'x':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = 16;
+number: p = (char *)db_ksprintn(ul, base, &tmp);
+ if (sharpflag && ul != 0) {
+ if (base == 8)
+ tmp++;
+ else if (base == 16)
+ tmp += 2;
+ }
+ if (neg)
+ tmp++;
+
+ if (!ladjust && width && (width -= tmp) > 0)
+ while (width--)
+ db_putchar(padc);
+ if (neg)
+ db_putchar ('-');
+ if (sharpflag && ul != 0) {
+ if (base == 8) {
+ db_putchar ('0');
+ } else if (base == 16) {
+ db_putchar ('0');
+ db_putchar ('x');
+ }
+ }
+ if (ladjust && width && (width -= tmp) > 0)
+ while (width--)
+ db_putchar(padc);
+
+ while (ch = *p--)
+ db_putchar(ch);
+ break;
+ default:
+ db_putchar('%');
+ if (lflag)
+ db_putchar('l');
+ /* FALLTHROUGH */
+ case '%':
+ db_putchar(ch);
+ }
+ }
+}
+
diff --git a/sys/ddb/db_output.h b/sys/ddb/db_output.h
new file mode 100644
index 00000000000..f378482ecbf
--- /dev/null
+++ b/sys/ddb/db_output.h
@@ -0,0 +1,38 @@
+/* $NetBSD: db_output.h,v 1.5 1994/10/09 08:19:36 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 8/90
+ */
+
+/*
+ * Printing routines for kernel debugger.
+ */
+void db_force_whitespace __P((void));
+int db_print_position __P((void));
+void db_end_line __P((void));
+int db_printf __P((char *, ...));
diff --git a/sys/ddb/db_print.c b/sys/ddb/db_print.c
new file mode 100644
index 00000000000..a584216c310
--- /dev/null
+++ b/sys/ddb/db_print.c
@@ -0,0 +1,67 @@
+/* $NetBSD: db_print.c,v 1.4 1994/06/29 06:31:15 cgd Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Miscellaneous printing.
+ */
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_sym.h>
+
+extern unsigned int db_maxoff;
+
+void
+db_show_regs()
+{
+ int (*func)();
+ register struct db_variable *regp;
+ db_expr_t value, offset;
+ char * name;
+
+ for (regp = db_regs; regp < db_eregs; regp++) {
+ db_read_variable(regp, &value);
+ db_printf("%-12s%#10n", regp->name, value);
+ db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset);
+ if (name != 0 && offset <= db_maxoff && offset != value) {
+ db_printf("\t%s", name);
+ if (offset != 0)
+ db_printf("+%#r", offset);
+ }
+ db_printf("\n");
+ }
+ db_print_loc_and_inst(PC_REGS(DDB_REGS));
+}
+
diff --git a/sys/ddb/db_run.c b/sys/ddb/db_run.c
new file mode 100644
index 00000000000..102cc3a4c63
--- /dev/null
+++ b/sys/ddb/db_run.c
@@ -0,0 +1,381 @@
+/* $NetBSD: db_run.c,v 1.7 1994/10/09 08:30:08 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Commands to run process.
+ */
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_run.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_break.h>
+#include <ddb/db_access.h>
+
+int db_run_mode;
+#define STEP_NONE 0
+#define STEP_ONCE 1
+#define STEP_RETURN 2
+#define STEP_CALLT 3
+#define STEP_CONTINUE 4
+#define STEP_INVISIBLE 5
+#define STEP_COUNT 6
+
+boolean_t db_sstep_print;
+int db_loop_count;
+int db_call_depth;
+
+boolean_t
+db_stop_at_pc(regs, is_breakpoint)
+ db_regs_t *regs;
+ boolean_t *is_breakpoint;
+{
+ register db_addr_t pc;
+ register db_breakpoint_t bkpt;
+
+ db_clear_single_step(regs);
+ db_clear_breakpoints();
+ db_clear_watchpoints();
+ pc = PC_REGS(regs);
+
+#ifdef FIXUP_PC_AFTER_BREAK
+ if (*is_breakpoint) {
+ /*
+ * Breakpoint trap. Fix up the PC if the
+ * machine requires it.
+ */
+ FIXUP_PC_AFTER_BREAK
+ pc = PC_REGS(regs);
+ }
+#endif
+
+ /*
+ * Now check for a breakpoint at this address.
+ */
+ bkpt = db_find_breakpoint_here(pc);
+ if (bkpt) {
+ if (--bkpt->count == 0) {
+ bkpt->count = bkpt->init_count;
+ *is_breakpoint = TRUE;
+ return (TRUE); /* stop here */
+ }
+ } else if (*is_breakpoint) {
+ PC_REGS(regs) += BKPT_SIZE;
+ }
+
+ *is_breakpoint = FALSE;
+
+ if (db_run_mode == STEP_INVISIBLE) {
+ db_run_mode = STEP_CONTINUE;
+ return (FALSE); /* continue */
+ }
+ if (db_run_mode == STEP_COUNT) {
+ return (FALSE); /* continue */
+ }
+ if (db_run_mode == STEP_ONCE) {
+ if (--db_loop_count > 0) {
+ if (db_sstep_print) {
+ db_printf("\t\t");
+ db_print_loc_and_inst(pc);
+ db_printf("\n");
+ }
+ return (FALSE); /* continue */
+ }
+ }
+ if (db_run_mode == STEP_RETURN) {
+ db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
+
+ /* continue until matching return */
+
+ if (!inst_trap_return(ins) &&
+ (!inst_return(ins) || --db_call_depth != 0)) {
+ if (db_sstep_print) {
+ if (inst_call(ins) || inst_return(ins)) {
+ register int i;
+
+ db_printf("[after %6d] ", db_inst_count);
+ for (i = db_call_depth; --i > 0; )
+ db_printf(" ");
+ db_print_loc_and_inst(pc);
+ db_printf("\n");
+ }
+ }
+ if (inst_call(ins))
+ db_call_depth++;
+ return (FALSE); /* continue */
+ }
+ }
+ if (db_run_mode == STEP_CALLT) {
+ db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
+
+ /* continue until call or return */
+
+ if (!inst_call(ins) &&
+ !inst_return(ins) &&
+ !inst_trap_return(ins)) {
+ return (FALSE); /* continue */
+ }
+ }
+ db_run_mode = STEP_NONE;
+ return (TRUE);
+}
+
+void
+db_restart_at_pc(regs, watchpt)
+ db_regs_t *regs;
+ boolean_t watchpt;
+{
+ register db_addr_t pc = PC_REGS(regs);
+
+ if ((db_run_mode == STEP_COUNT) ||
+ (db_run_mode == STEP_RETURN) ||
+ (db_run_mode == STEP_CALLT)) {
+ db_expr_t ins;
+
+ /*
+ * We are about to execute this instruction,
+ * so count it now.
+ */
+
+ ins = db_get_value(pc, sizeof(int), FALSE);
+ db_inst_count++;
+ db_load_count += inst_load(ins);
+ db_store_count += inst_store(ins);
+#ifdef SOFTWARE_SSTEP
+ /* XXX works on mips, but... */
+ if (inst_branch(ins) || inst_call(ins)) {
+ ins = db_get_value(next_instr_address(pc,1),
+ sizeof(int), FALSE);
+ db_inst_count++;
+ db_load_count += inst_load(ins);
+ db_store_count += inst_store(ins);
+ }
+#endif SOFTWARE_SSTEP
+ }
+
+ if (db_run_mode == STEP_CONTINUE) {
+ if (watchpt || db_find_breakpoint_here(pc)) {
+ /*
+ * Step over breakpoint/watchpoint.
+ */
+ db_run_mode = STEP_INVISIBLE;
+ db_set_single_step(regs);
+ } else {
+ db_set_breakpoints();
+ db_set_watchpoints();
+ }
+ } else {
+ db_set_single_step(regs);
+ }
+}
+
+void
+db_single_step(regs)
+ db_regs_t *regs;
+{
+ if (db_run_mode == STEP_CONTINUE) {
+ db_run_mode = STEP_INVISIBLE;
+ db_set_single_step(regs);
+ }
+}
+
+#ifdef SOFTWARE_SSTEP
+/*
+ * Software implementation of single-stepping.
+ * If your machine does not have a trace mode
+ * similar to the vax or sun ones you can use
+ * this implementation, done for the mips.
+ * Just define the above conditional and provide
+ * the functions/macros defined below.
+ *
+ * extern boolean_t
+ * inst_branch(), returns true if the instruction might branch
+ * extern unsigned
+ * branch_taken(), return the address the instruction might
+ * branch to
+ * db_getreg_val(); return the value of a user register,
+ * as indicated in the hardware instruction
+ * encoding, e.g. 8 for r8
+ *
+ * next_instr_address(pc,bd) returns the address of the first
+ * instruction following the one at "pc",
+ * which is either in the taken path of
+ * the branch (bd==1) or not. This is
+ * for machines (mips) with branch delays.
+ *
+ * A single-step may involve at most 2 breakpoints -
+ * one for branch-not-taken and one for branch taken.
+ * If one of these addresses does not already have a breakpoint,
+ * we allocate a breakpoint and save it here.
+ * These breakpoints are deleted on return.
+ */
+db_breakpoint_t db_not_taken_bkpt = 0;
+db_breakpoint_t db_taken_bkpt = 0;
+
+void
+db_set_single_step(regs)
+ register db_regs_t *regs;
+{
+ db_addr_t pc = PC_REGS(regs);
+ register unsigned inst, brpc;
+
+ /*
+ * User was stopped at pc, e.g. the instruction
+ * at pc was not executed.
+ */
+ inst = db_get_value(pc, sizeof(int), FALSE);
+ if (inst_branch(inst) || inst_call(inst)) {
+ extern unsigned getreg_val();
+
+ brpc = branch_taken(inst, pc, getreg_val, regs);
+ if (brpc != pc) { /* self-branches are hopeless */
+ db_taken_bkpt = db_set_temp_breakpoint(brpc);
+ }
+ pc = next_instr_address(pc,1);
+ }
+ pc = next_instr_address(pc,0);
+ db_not_taken_bkpt = db_set_temp_breakpoint(pc);
+}
+
+void
+db_clear_single_step(regs)
+ db_regs_t *regs;
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_taken_bkpt != 0) {
+ db_delete_temp_breakpoint(db_taken_bkpt);
+ db_taken_bkpt = 0;
+ }
+ if (db_not_taken_bkpt != 0) {
+ db_delete_temp_breakpoint(db_not_taken_bkpt);
+ db_not_taken_bkpt = 0;
+ }
+}
+
+#endif SOFTWARE_SSTEP
+
+extern int db_cmd_loop_done;
+
+/* single-step */
+/*ARGSUSED*/
+void
+db_single_step_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ boolean_t print = FALSE;
+
+ if (count == -1)
+ count = 1;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_ONCE;
+ db_loop_count = count;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/* trace and print until call/return */
+/*ARGSUSED*/
+void
+db_trace_until_call_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ boolean_t print = FALSE;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_CALLT;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/*ARGSUSED*/
+void
+db_trace_until_matching_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ boolean_t print = FALSE;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_RETURN;
+ db_call_depth = 1;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/* continue */
+/*ARGSUSED*/
+void
+db_continue_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ if (modif[0] == 'c')
+ db_run_mode = STEP_COUNT;
+ else
+ db_run_mode = STEP_CONTINUE;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
diff --git a/sys/ddb/db_run.h b/sys/ddb/db_run.h
new file mode 100644
index 00000000000..14a4dc96dd6
--- /dev/null
+++ b/sys/ddb/db_run.h
@@ -0,0 +1,51 @@
+/* $NetBSD: db_run.h,v 1.2 1994/10/09 08:30:12 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#ifndef _DDB_DB_RUN_
+#define _DDB_DB_RUN_
+
+/*
+ * Commands to run process.
+ */
+int db_inst_count;
+int db_load_count;
+int db_store_count;
+
+#ifndef db_set_single_step
+void db_set_single_step __P((db_regs_t *));
+#endif
+#ifndef db_clear_single_step
+void db_clear_single_step __P((db_regs_t *));
+#endif
+void db_restart_at_pc __P((db_regs_t *, boolean_t));
+boolean_t db_stop_at_pc __P((db_regs_t *, boolean_t *));
+
+#endif _DDB_DB_RUN_
diff --git a/sys/ddb/db_sym.c b/sys/ddb/db_sym.c
new file mode 100644
index 00000000000..0d929531cb2
--- /dev/null
+++ b/sys/ddb/db_sym.c
@@ -0,0 +1,381 @@
+/* $NetBSD: db_sym.c,v 1.9 1995/05/24 20:21:00 gwr Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_sym.h>
+
+/*
+ * We import from the symbol-table dependent routines:
+ */
+extern db_sym_t X_db_lookup();
+extern db_sym_t X_db_search_symbol();
+extern boolean_t X_db_line_at_pc();
+extern void X_db_symbol_values();
+
+/*
+ * Multiple symbol tables
+ */
+#ifndef MAXLKMS
+#define MAXLKMS 20
+#endif
+
+#ifndef MAXNOSYMTABS
+#define MAXNOSYMTABS MAXLKMS+1 /* Room for kernel + LKM's */
+#endif
+
+db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},};
+
+db_symtab_t *db_last_symtab;
+
+db_sym_t db_lookup(); /* forward */
+
+/*
+ * Add symbol table, with given name, to list of symbol tables.
+ */
+int
+db_add_symbol_table(start, end, name, ref)
+ char *start;
+ char *end;
+ char *name;
+ char *ref;
+{
+ int slot;
+
+ for (slot = 0; slot < MAXNOSYMTABS; slot++) {
+ if (db_symtabs[slot].name == NULL)
+ break;
+ }
+ if (slot >= MAXNOSYMTABS) {
+ printf ("No slots left for %s symbol table", name);
+ return(-1);
+ }
+
+ db_symtabs[slot].start = start;
+ db_symtabs[slot].end = end;
+ db_symtabs[slot].name = name;
+ db_symtabs[slot].private = ref;
+
+ return(slot);
+}
+
+/*
+ * Delete a symbol table. Caller is responsible for freeing storage.
+ */
+void
+db_del_symbol_table(name)
+ char *name;
+{
+ int slot;
+
+ for (slot = 0; slot < MAXNOSYMTABS; slot++) {
+ if (db_symtabs[slot].name &&
+ ! strcmp(db_symtabs[slot].name, name))
+ break;
+ }
+ if (slot >= MAXNOSYMTABS) {
+ printf ("Unable to find symbol table slot for %s.", name);
+ return;
+ }
+
+ db_symtabs[slot].start = 0;
+ db_symtabs[slot].end = 0;
+ db_symtabs[slot].name = 0;
+ db_symtabs[slot].private = 0;
+}
+
+/*
+ * db_qualify("vm_map", "netbsd") returns "netbsd:vm_map".
+ *
+ * Note: return value points to static data whose content is
+ * overwritten by each call... but in practice this seems okay.
+ */
+static char *
+db_qualify(sym, symtabname)
+ db_sym_t sym;
+ register char *symtabname;
+{
+ char *symname;
+ static char tmp[256];
+ register char *s;
+
+ db_symbol_values(sym, &symname, 0);
+ s = tmp;
+ while (*s++ = *symtabname++) {
+ }
+ s[-1] = ':';
+ while (*s++ = *symname++) {
+ }
+ return tmp;
+}
+
+
+boolean_t
+db_eqname(src, dst, c)
+ char *src;
+ char *dst;
+ char c;
+{
+ if (!strcmp(src, dst))
+ return (TRUE);
+ if (src[0] == c)
+ return (!strcmp(src+1,dst));
+ return (FALSE);
+}
+
+boolean_t
+db_value_of_name(name, valuep)
+ char *name;
+ db_expr_t *valuep;
+{
+ db_sym_t sym;
+
+ sym = db_lookup(name);
+ if (sym == DB_SYM_NULL)
+ return (FALSE);
+ db_symbol_values(sym, &name, valuep);
+ return (TRUE);
+}
+
+
+/*
+ * Lookup a symbol.
+ * If the symbol has a qualifier (e.g., ux:vm_map),
+ * then only the specified symbol table will be searched;
+ * otherwise, all symbol tables will be searched.
+ */
+db_sym_t
+db_lookup(symstr)
+ char *symstr;
+{
+ db_sym_t sp;
+ register int i;
+ int symtab_start = 0;
+ int symtab_end = MAXNOSYMTABS;
+ register char *cp;
+
+ /*
+ * Look for, remove, and remember any symbol table specifier.
+ */
+ for (cp = symstr; *cp; cp++) {
+ if (*cp == ':') {
+ *cp = '\0';
+ for (i = 0; i < MAXNOSYMTABS; i++) {
+ if (db_symtabs[i].name &&
+ ! strcmp(symstr, db_symtabs[i].name)) {
+ symtab_start = i;
+ symtab_end = i + 1;
+ break;
+ }
+ }
+ *cp = ':';
+ if (i == MAXNOSYMTABS) {
+ db_error("invalid symbol table name");
+ /*NOTREACHED*/
+ }
+ symstr = cp+1;
+ }
+ }
+
+ /*
+ * Look in the specified set of symbol tables.
+ * Return on first match.
+ */
+ for (i = symtab_start; i < symtab_end; i++) {
+ if (db_symtabs[i].name &&
+ (sp = X_db_lookup(&db_symtabs[i], symstr))) {
+ db_last_symtab = &db_symtabs[i];
+ return sp;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Does this symbol name appear in more than one symbol table?
+ * Used by db_symbol_values to decide whether to qualify a symbol.
+ */
+boolean_t db_qualify_ambiguous_names = FALSE;
+
+boolean_t
+db_symbol_is_ambiguous(sym)
+ db_sym_t sym;
+{
+ char *sym_name;
+ register int i;
+ register
+ boolean_t found_once = FALSE;
+
+ if (!db_qualify_ambiguous_names)
+ return FALSE;
+
+ db_symbol_values(sym, &sym_name, 0);
+ for (i = 0; i < MAXNOSYMTABS; i++) {
+ if (db_symtabs[i].name &&
+ X_db_lookup(&db_symtabs[i], sym_name)) {
+ if (found_once)
+ return TRUE;
+ found_once = TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Find the closest symbol to val, and return its name
+ * and the difference between val and the symbol found.
+ */
+db_sym_t
+db_search_symbol( val, strategy, offp)
+ register db_addr_t val;
+ db_strategy_t strategy;
+ db_expr_t *offp;
+{
+ register
+ unsigned int diff;
+ unsigned int newdiff;
+ register int i;
+ db_sym_t ret = DB_SYM_NULL, sym;
+
+ newdiff = diff = ~0;
+ db_last_symtab = 0;
+ for (i = 0; i < MAXNOSYMTABS; i++) {
+ if (!db_symtabs[i].name)
+ continue;
+ sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff);
+ if (newdiff < diff) {
+ db_last_symtab = &db_symtabs[i];
+ diff = newdiff;
+ ret = sym;
+ }
+ }
+ *offp = diff;
+ return ret;
+}
+
+/*
+ * Return name and value of a symbol
+ */
+void
+db_symbol_values(sym, namep, valuep)
+ db_sym_t sym;
+ char **namep;
+ db_expr_t *valuep;
+{
+ db_expr_t value;
+
+ if (sym == DB_SYM_NULL) {
+ *namep = 0;
+ return;
+ }
+
+ X_db_symbol_values(sym, namep, &value);
+
+ if (db_symbol_is_ambiguous(sym))
+ *namep = db_qualify(sym, db_last_symtab->name);
+ if (valuep)
+ *valuep = value;
+}
+
+
+/*
+ * Print a the closest symbol to value
+ *
+ * After matching the symbol according to the given strategy
+ * we print it in the name+offset format, provided the symbol's
+ * value is close enough (eg smaller than db_maxoff).
+ * We also attempt to print [filename:linenum] when applicable
+ * (eg for procedure names).
+ *
+ * If we could not find a reasonable name+offset representation,
+ * then we just print the value in hex. Small values might get
+ * bogus symbol associations, e.g. 3 might get some absolute
+ * value like _INCLUDE_VERSION or something, therefore we do
+ * not accept symbols whose value is zero (and use plain hex).
+ * Also, avoid printing as "end+0x????" which is useless.
+ * The variable db_lastsym is used instead of "end" in case we
+ * add support for symbols in loadable driver modules.
+ */
+
+extern char end[];
+unsigned int db_lastsym = (int)end;
+unsigned int db_maxoff = 0x10000000;
+
+
+void
+db_printsym(off, strategy)
+ db_expr_t off;
+ db_strategy_t strategy;
+{
+ db_expr_t d;
+ char *filename;
+ char *name;
+ db_expr_t value;
+ int linenum;
+ db_sym_t cursym;
+
+ if (off <= db_lastsym) {
+ cursym = db_search_symbol(off, strategy, &d);
+ db_symbol_values(cursym, &name, &value);
+ if (name && (d < db_maxoff) && value) {
+ db_printf("%s", name);
+ if (d)
+ db_printf("+%#r", d);
+ if (strategy == DB_STGY_PROC) {
+ if (db_line_at_pc(cursym, &filename, &linenum, off))
+ db_printf(" [%s:%d]", filename, linenum);
+ }
+ return;
+ }
+ }
+ db_printf("%#n", off);
+ return;
+}
+
+
+boolean_t
+db_line_at_pc( sym, filename, linenum, pc)
+ db_sym_t sym;
+ char **filename;
+ int *linenum;
+ db_expr_t pc;
+{
+ return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc);
+}
+
+int
+db_sym_numargs(sym, nargp, argnames)
+ db_sym_t sym;
+ int *nargp;
+ char **argnames;
+{
+ return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames);
+}
diff --git a/sys/ddb/db_sym.h b/sys/ddb/db_sym.h
new file mode 100644
index 00000000000..2bbe44a8764
--- /dev/null
+++ b/sys/ddb/db_sym.h
@@ -0,0 +1,99 @@
+/* $NetBSD: db_sym.h,v 1.6 1994/10/09 08:19:41 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: Alessandro Forin, Carnegie Mellon University
+ * Date: 8/90
+ */
+
+/*
+ * This module can handle multiple symbol tables
+ */
+typedef struct {
+ char *name; /* symtab name */
+ char *start; /* symtab location */
+ char *end;
+ char *private; /* optional machdep pointer */
+} db_symtab_t;
+
+extern db_symtab_t *db_last_symtab; /* where last symbol was found */
+
+/*
+ * Symbol representation is specific to the symtab style:
+ * BSD compilers use dbx' nlist, other compilers might use
+ * a different one
+ */
+typedef char * db_sym_t; /* opaque handle on symbols */
+#define DB_SYM_NULL ((db_sym_t)0)
+
+/*
+ * Non-stripped symbol tables will have duplicates, for instance
+ * the same string could match a parameter name, a local var, a
+ * global var, etc.
+ * We are most concern with the following matches.
+ */
+typedef int db_strategy_t; /* search strategy */
+
+#define DB_STGY_ANY 0 /* anything goes */
+#define DB_STGY_XTRN 1 /* only external symbols */
+#define DB_STGY_PROC 2 /* only procedures */
+
+extern boolean_t db_qualify_ambiguous_names;
+ /* if TRUE, check across symbol tables
+ * for multiple occurrences of a name.
+ * Might slow down quite a bit */
+
+/*
+ * Functions exported by the symtable module
+ */
+int db_add_symbol_table __P((char *, char *, char *, char *));
+ /* extend the list of symbol tables */
+
+void db_del_symbol_table __P((char *));
+ /* remove a symbol table from list */
+
+int db_value_of_name __P((char *, db_expr_t *));
+ /* find symbol value given name */
+
+db_sym_t db_search_symbol __P((db_addr_t, db_strategy_t, db_expr_t *));
+ /* find symbol given value */
+
+void db_symbol_values __P((db_sym_t, char **, db_expr_t *));
+ /* return name and value of symbol */
+
+#define db_find_sym_and_offset(val,namep,offp) \
+ db_symbol_values(db_search_symbol(val,DB_STGY_ANY,offp),namep,0)
+ /* find name&value given approx val */
+
+#define db_find_xtrn_sym_and_offset(val,namep,offp) \
+ db_symbol_values(db_search_symbol(val,DB_STGY_XTRN,offp),namep,0)
+ /* ditto, but no locals */
+
+int db_eqname __P((char *, char *, char));
+ /* strcmp, modulo leading char */
+
+void db_printsym __P((db_expr_t, db_strategy_t));
+ /* print closest symbol to a value */
diff --git a/sys/ddb/db_trap.c b/sys/ddb/db_trap.c
new file mode 100644
index 00000000000..8838986d91e
--- /dev/null
+++ b/sys/ddb/db_trap.c
@@ -0,0 +1,71 @@
+/* $NetBSD: db_trap.c,v 1.8 1994/12/02 06:07:37 gwr Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Trap entry point to kernel debugger.
+ */
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_run.h>
+#include <ddb/db_command.h>
+#include <ddb/db_break.h>
+
+db_trap(type, code)
+ int type, code;
+{
+ boolean_t bkpt;
+ boolean_t watchpt;
+
+ bkpt = IS_BREAKPOINT_TRAP(type, code);
+ watchpt = IS_WATCHPOINT_TRAP(type, code);
+
+ if (db_stop_at_pc(DDB_REGS, &bkpt)) {
+ if (db_inst_count) {
+ db_printf("After %d instructions (%d loads, %d stores),\n",
+ db_inst_count, db_load_count, db_store_count);
+ }
+ if (bkpt)
+ db_printf("Breakpoint at\t");
+ else if (watchpt)
+ db_printf("Watchpoint at\t");
+ else
+ db_printf("Stopped at\t");
+ db_dot = PC_REGS(DDB_REGS);
+ db_print_loc_and_inst(db_dot);
+
+ db_command_loop();
+ }
+
+ db_restart_at_pc(DDB_REGS, watchpt);
+}
diff --git a/sys/ddb/db_variables.c b/sys/ddb/db_variables.c
new file mode 100644
index 00000000000..21e6bcbf812
--- /dev/null
+++ b/sys/ddb/db_variables.c
@@ -0,0 +1,164 @@
+/* $NetBSD: db_variables.c,v 1.7 1994/10/09 08:56:28 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_variables.h>
+
+extern unsigned int db_maxoff;
+
+extern int db_radix;
+extern int db_max_width;
+extern int db_tab_stop_width;
+extern int db_max_line;
+
+struct db_variable db_vars[] = {
+ { "radix", &db_radix, FCN_NULL },
+ { "maxoff", (int *)&db_maxoff, FCN_NULL },
+ { "maxwidth", &db_max_width, FCN_NULL },
+ { "tabstops", &db_tab_stop_width, FCN_NULL },
+ { "lines", &db_max_line, FCN_NULL },
+};
+struct db_variable *db_evars = db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
+
+int
+db_find_variable(varp)
+ struct db_variable **varp;
+{
+ int t;
+ struct db_variable *vp;
+
+ t = db_read_token();
+ if (t == tIDENT) {
+ for (vp = db_vars; vp < db_evars; vp++) {
+ if (!strcmp(db_tok_string, vp->name)) {
+ *varp = vp;
+ return (1);
+ }
+ }
+ for (vp = db_regs; vp < db_eregs; vp++) {
+ if (!strcmp(db_tok_string, vp->name)) {
+ *varp = vp;
+ return (1);
+ }
+ }
+ }
+ db_error("Unknown variable\n");
+ /*NOTREACHED*/
+}
+
+int
+db_get_variable(valuep)
+ db_expr_t *valuep;
+{
+ struct db_variable *vp;
+
+ if (!db_find_variable(&vp))
+ return (0);
+
+ db_read_variable(vp, valuep);
+
+ return (1);
+}
+
+int
+db_set_variable(value)
+ db_expr_t value;
+{
+ struct db_variable *vp;
+
+ if (!db_find_variable(&vp))
+ return (0);
+
+ db_write_variable(vp, &value);
+
+ return (1);
+}
+
+
+db_read_variable(vp, valuep)
+ struct db_variable *vp;
+ db_expr_t *valuep;
+{
+ int (*func)() = vp->fcn;
+
+ if (func == FCN_NULL)
+ *valuep = *(vp->valuep);
+ else
+ (*func)(vp, valuep, DB_VAR_GET);
+}
+
+db_write_variable(vp, valuep)
+ struct db_variable *vp;
+ db_expr_t *valuep;
+{
+ int (*func)() = vp->fcn;
+
+ if (func == FCN_NULL)
+ *(vp->valuep) = *valuep;
+ else
+ (*func)(vp, valuep, DB_VAR_SET);
+}
+
+void
+db_set_cmd()
+{
+ db_expr_t value;
+ int (*func)();
+ struct db_variable *vp;
+ int t;
+
+ t = db_read_token();
+ if (t != tDOLLAR) {
+ db_error("Unknown variable\n");
+ /*NOTREACHED*/
+ }
+ if (!db_find_variable(&vp)) {
+ db_error("Unknown variable\n");
+ /*NOTREACHED*/
+ }
+
+ t = db_read_token();
+ if (t != tEQ)
+ db_unread_token(t);
+
+ if (!db_expression(&value)) {
+ db_error("No value\n");
+ /*NOTREACHED*/
+ }
+ if (db_read_token() != tEOL) {
+ db_error("?\n");
+ /*NOTREACHED*/
+ }
+
+ db_write_variable(vp, &value);
+}
diff --git a/sys/ddb/db_variables.h b/sys/ddb/db_variables.h
new file mode 100644
index 00000000000..8bdb6dea5d4
--- /dev/null
+++ b/sys/ddb/db_variables.h
@@ -0,0 +1,53 @@
+/* $NetBSD: db_variables.h,v 1.4 1994/06/29 06:31:24 cgd Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#ifndef _DB_VARIABLES_H_
+#define _DB_VARIABLES_H_
+
+/*
+ * Debugger variables.
+ */
+struct db_variable {
+ char *name; /* Name of variable */
+ int *valuep; /* value of variable */
+ /* function to call when reading/writing */
+ int (*fcn)(/* db_variable *vp, db_expr_t *valuep, int op */);
+#define DB_VAR_GET 0
+#define DB_VAR_SET 1
+};
+#define FCN_NULL ((int (*)())0)
+
+extern struct db_variable db_vars[]; /* debugger variables */
+extern struct db_variable *db_evars;
+extern struct db_variable db_regs[]; /* machine registers */
+extern struct db_variable *db_eregs;
+
+#endif /* _DB_VARIABLES_H_ */
diff --git a/sys/ddb/db_watch.c b/sys/ddb/db_watch.c
new file mode 100644
index 00000000000..ff3a5bbe32c
--- /dev/null
+++ b/sys/ddb/db_watch.c
@@ -0,0 +1,264 @@
+/* $NetBSD: db_watch.c,v 1.7 1994/10/09 08:30:15 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: Richard P. Draves, Carnegie Mellon University
+ * Date: 10/90
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_break.h>
+#include <ddb/db_watch.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+
+/*
+ * Watchpoints.
+ */
+
+boolean_t db_watchpoints_inserted = TRUE;
+
+#define NWATCHPOINTS 100
+struct db_watchpoint db_watch_table[NWATCHPOINTS];
+db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0];
+db_watchpoint_t db_free_watchpoints = 0;
+db_watchpoint_t db_watchpoint_list = 0;
+
+db_watchpoint_t
+db_watchpoint_alloc()
+{
+ register db_watchpoint_t watch;
+
+ if ((watch = db_free_watchpoints) != 0) {
+ db_free_watchpoints = watch->link;
+ return (watch);
+ }
+ if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
+ db_printf("All watchpoints used.\n");
+ return (0);
+ }
+ watch = db_next_free_watchpoint;
+ db_next_free_watchpoint++;
+
+ return (watch);
+}
+
+void
+db_watchpoint_free(watch)
+ register db_watchpoint_t watch;
+{
+ watch->link = db_free_watchpoints;
+ db_free_watchpoints = watch;
+}
+
+void
+db_set_watchpoint(map, addr, size)
+ vm_map_t map;
+ db_addr_t addr;
+ vm_size_t size;
+{
+ register db_watchpoint_t watch;
+
+ if (map == NULL) {
+ db_printf("No map.\n");
+ return;
+ }
+
+ /*
+ * Should we do anything fancy with overlapping regions?
+ */
+
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ if (db_map_equal(watch->map, map) &&
+ (watch->loaddr == addr) &&
+ (watch->hiaddr == addr+size)) {
+ db_printf("Already set.\n");
+ return;
+ }
+
+ watch = db_watchpoint_alloc();
+ if (watch == 0) {
+ db_printf("Too many watchpoints.\n");
+ return;
+ }
+
+ watch->map = map;
+ watch->loaddr = addr;
+ watch->hiaddr = addr+size;
+
+ watch->link = db_watchpoint_list;
+ db_watchpoint_list = watch;
+
+ db_watchpoints_inserted = FALSE;
+}
+
+void
+db_delete_watchpoint(map, addr)
+ vm_map_t map;
+ db_addr_t addr;
+{
+ register db_watchpoint_t watch;
+ register db_watchpoint_t *prev;
+
+ for (prev = &db_watchpoint_list;
+ (watch = *prev) != 0;
+ prev = &watch->link)
+ if (db_map_equal(watch->map, map) &&
+ (watch->loaddr <= addr) &&
+ (addr < watch->hiaddr)) {
+ *prev = watch->link;
+ db_watchpoint_free(watch);
+ return;
+ }
+
+ db_printf("Not set.\n");
+}
+
+void
+db_list_watchpoints()
+{
+ register db_watchpoint_t watch;
+
+ if (db_watchpoint_list == 0) {
+ db_printf("No watchpoints set\n");
+ return;
+ }
+
+ db_printf(" Map Address Size\n");
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ db_printf("%s%8x %8x %x\n",
+ db_map_current(watch->map) ? "*" : " ",
+ watch->map, watch->loaddr,
+ watch->hiaddr - watch->loaddr);
+}
+
+/* Delete watchpoint */
+/*ARGSUSED*/
+void
+db_deletewatch_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ db_delete_watchpoint(db_map_addr(addr), addr);
+}
+
+/* Set watchpoint */
+/*ARGSUSED*/
+void
+db_watchpoint_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ vm_size_t size;
+ db_expr_t value;
+
+ if (db_expression(&value))
+ size = (vm_size_t) value;
+ else
+ size = 4;
+ db_skip_to_eol();
+
+ db_set_watchpoint(db_map_addr(addr), addr, size);
+}
+
+/* list watchpoints */
+void
+db_listwatch_cmd()
+{
+ db_list_watchpoints();
+}
+
+void
+db_set_watchpoints()
+{
+ register db_watchpoint_t watch;
+
+ if (!db_watchpoints_inserted) {
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ pmap_protect(watch->map->pmap,
+ trunc_page(watch->loaddr),
+ round_page(watch->hiaddr),
+ VM_PROT_READ);
+
+ db_watchpoints_inserted = TRUE;
+ }
+}
+
+void
+db_clear_watchpoints()
+{
+ db_watchpoints_inserted = FALSE;
+}
+
+boolean_t
+db_find_watchpoint(map, addr, regs)
+ vm_map_t map;
+ db_addr_t addr;
+ db_regs_t *regs;
+{
+ register db_watchpoint_t watch;
+ db_watchpoint_t found = 0;
+
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ if (db_map_equal(watch->map, map)) {
+ if ((watch->loaddr <= addr) &&
+ (addr < watch->hiaddr))
+ return (TRUE);
+ else if ((trunc_page(watch->loaddr) <= addr) &&
+ (addr < round_page(watch->hiaddr)))
+ found = watch;
+ }
+
+ /*
+ * We didn't hit exactly on a watchpoint, but we are
+ * in a protected region. We want to single-step
+ * and then re-protect.
+ */
+
+ if (found) {
+ db_watchpoints_inserted = FALSE;
+ db_single_step(regs);
+ }
+
+ return (FALSE);
+}
diff --git a/sys/ddb/db_watch.h b/sys/ddb/db_watch.h
new file mode 100644
index 00000000000..9a3a8817600
--- /dev/null
+++ b/sys/ddb/db_watch.h
@@ -0,0 +1,53 @@
+/* $NetBSD: db_watch.h,v 1.8 1994/10/09 08:41:20 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 10/90
+ */
+
+#ifndef _DDB_DB_WATCH_
+#define _DDB_DB_WATCH_
+
+/*
+ * Watchpoint.
+ */
+typedef struct db_watchpoint {
+ vm_map_t map; /* in this map */
+ db_addr_t loaddr; /* from this address */
+ db_addr_t hiaddr; /* to this address */
+ struct db_watchpoint *link; /* link in in-use or free chain */
+} *db_watchpoint_t;
+
+boolean_t db_find_watchpoint __P((vm_map_t, db_addr_t, db_regs_t *));
+void db_set_watchpoints __P((void));
+void db_clear_watchpoints __P((void));
+
+void db_set_watchpoint __P((vm_map_t, db_addr_t, vm_size_t));
+void db_delete_watchpoint __P((vm_map_t, db_addr_t));
+void db_list_watchpoints __P((void));
+
+#endif _DDB_DB_WATCH_
diff --git a/sys/ddb/db_write_cmd.c b/sys/ddb/db_write_cmd.c
new file mode 100644
index 00000000000..8c324a33c98
--- /dev/null
+++ b/sys/ddb/db_write_cmd.c
@@ -0,0 +1,99 @@
+/* $NetBSD: db_write_cmd.c,v 1.5 1994/10/09 08:56:30 mycroft Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
+
+/*
+ * Write to file.
+ */
+/*ARGSUSED*/
+void
+db_write_cmd(address, have_addr, count, modif)
+ db_expr_t address;
+ boolean_t have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ register
+ db_addr_t addr;
+ register
+ db_expr_t old_value;
+ db_expr_t new_value;
+ register int size;
+ boolean_t wrote_one = FALSE;
+
+ addr = (db_addr_t) address;
+
+ switch (modif[0]) {
+ case 'b':
+ size = 1;
+ break;
+ case 'h':
+ size = 2;
+ break;
+ case 'l':
+ case '\0':
+ size = 4;
+ break;
+ default:
+ db_error("Unknown size\n");
+ /*NOTREACHED*/
+ }
+
+ while (db_expression(&new_value)) {
+ old_value = db_get_value(addr, size, FALSE);
+ db_printsym(addr, DB_STGY_ANY);
+ db_printf("\t\t%#8n\t=\t%#8n\n", old_value, new_value);
+ db_put_value(addr, size, new_value);
+ addr += size;
+
+ wrote_one = TRUE;
+ }
+
+ if (!wrote_one) {
+ db_error("Nothing written.\n");
+ /*NOTREACHED*/
+ }
+
+ db_next = addr;
+ db_prev = addr - size;
+
+ db_skip_to_eol();
+}
+