diff options
Diffstat (limited to 'sys/ddb')
-rw-r--r-- | sys/ddb/db_access.c | 97 | ||||
-rw-r--r-- | sys/ddb/db_access.h | 39 | ||||
-rw-r--r-- | sys/ddb/db_aout.c | 350 | ||||
-rw-r--r-- | sys/ddb/db_break.c | 348 | ||||
-rw-r--r-- | sys/ddb/db_break.h | 64 | ||||
-rw-r--r-- | sys/ddb/db_command.c | 507 | ||||
-rw-r--r-- | sys/ddb/db_command.h | 59 | ||||
-rw-r--r-- | sys/ddb/db_examine.c | 327 | ||||
-rw-r--r-- | sys/ddb/db_expr.c | 226 | ||||
-rw-r--r-- | sys/ddb/db_input.c | 246 | ||||
-rw-r--r-- | sys/ddb/db_lex.c | 276 | ||||
-rw-r--r-- | sys/ddb/db_lex.h | 72 | ||||
-rw-r--r-- | sys/ddb/db_output.c | 423 | ||||
-rw-r--r-- | sys/ddb/db_output.h | 38 | ||||
-rw-r--r-- | sys/ddb/db_print.c | 67 | ||||
-rw-r--r-- | sys/ddb/db_run.c | 381 | ||||
-rw-r--r-- | sys/ddb/db_run.h | 51 | ||||
-rw-r--r-- | sys/ddb/db_sym.c | 381 | ||||
-rw-r--r-- | sys/ddb/db_sym.h | 99 | ||||
-rw-r--r-- | sys/ddb/db_trap.c | 71 | ||||
-rw-r--r-- | sys/ddb/db_variables.c | 164 | ||||
-rw-r--r-- | sys/ddb/db_variables.h | 53 | ||||
-rw-r--r-- | sys/ddb/db_watch.c | 264 | ||||
-rw-r--r-- | sys/ddb/db_watch.h | 53 | ||||
-rw-r--r-- | sys/ddb/db_write_cmd.c | 99 |
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(); +} + |