From c1cfdb7aa5668ea0b9d1a5e0c8a07b6ff714bfac Mon Sep 17 00:00:00 2001 From: "William F. Jolitz" Date: Wed, 15 Apr 1992 23:00:47 -0800 Subject: [PATCH] 386BSD 0.1 development Work on file usr/src/sys.386bsd/ddb/db_access.c Work on file usr/src/sys.386bsd/ddb/db_access.h Work on file usr/src/sys.386bsd/ddb/db_variables.c Work on file usr/src/sys.386bsd/ddb/db_command.c Work on file usr/src/sys.386bsd/ddb/db_break.h Work on file usr/src/sys.386bsd/ddb/db_command.h Work on file usr/src/sys.386bsd/ddb/db_expr.c Work on file usr/src/sys.386bsd/ddb/db_examine.c Work on file usr/src/sys.386bsd/ddb/db_input.c Work on file usr/src/sys.386bsd/ddb/db_lex.c Work on file usr/src/sys.386bsd/ddb/db_lex.h Work on file usr/src/sys.386bsd/ddb/db_output.c Work on file usr/src/sys.386bsd/ddb/db_output.h Work on file usr/src/sys.386bsd/ddb/db_print.c Work on file usr/src/sys.386bsd/ddb/db_sym.c Work on file usr/src/sys.386bsd/ddb/db_sym.h Work on file usr/src/sys.386bsd/ddb/db_trap.c Work on file usr/src/sys.386bsd/ddb/db_variables.h Work on file usr/src/sys.386bsd/ddb/db_watch.h Work on file usr/src/sys.386bsd/ddb/db_watch.c Work on file usr/src/sys.386bsd/ddb/db_write_cmd.c Work on file usr/src/sys.386bsd/ddb/db_break.c Work on file usr/src/sys.386bsd/i386/i386/db_disasm.c Co-Authored-By: Lynne Greer Jolitz Synthesized-from: 386BSD-0.1 --- usr/src/sys.386bsd/ddb/db_access.c | 116 ++ usr/src/sys.386bsd/ddb/db_access.h | 55 + usr/src/sys.386bsd/ddb/db_break.c | 387 ++++++ usr/src/sys.386bsd/ddb/db_break.h | 84 ++ usr/src/sys.386bsd/ddb/db_command.c | 531 ++++++++ usr/src/sys.386bsd/ddb/db_command.h | 67 ++ usr/src/sys.386bsd/ddb/db_examine.c | 364 ++++++ usr/src/sys.386bsd/ddb/db_expr.c | 248 ++++ usr/src/sys.386bsd/ddb/db_input.c | 268 +++++ usr/src/sys.386bsd/ddb/db_lex.c | 295 +++++ usr/src/sys.386bsd/ddb/db_lex.h | 89 ++ usr/src/sys.386bsd/ddb/db_output.c | 379 ++++++ usr/src/sys.386bsd/ddb/db_output.h | 53 + usr/src/sys.386bsd/ddb/db_print.c | 104 ++ usr/src/sys.386bsd/ddb/db_sym.c | 360 ++++++ usr/src/sys.386bsd/ddb/db_sym.h | 114 ++ usr/src/sys.386bsd/ddb/db_trap.c | 106 ++ usr/src/sys.386bsd/ddb/db_variables.c | 186 +++ usr/src/sys.386bsd/ddb/db_variables.h | 72 ++ usr/src/sys.386bsd/ddb/db_watch.c | 294 +++++ usr/src/sys.386bsd/ddb/db_watch.h | 74 ++ usr/src/sys.386bsd/ddb/db_write_cmd.c | 120 ++ usr/src/sys.386bsd/i386/i386/db_disasm.c | 1397 ++++++++++++++++++++++ 23 files changed, 5763 insertions(+) create mode 100644 usr/src/sys.386bsd/ddb/db_access.c create mode 100644 usr/src/sys.386bsd/ddb/db_access.h create mode 100644 usr/src/sys.386bsd/ddb/db_break.c create mode 100644 usr/src/sys.386bsd/ddb/db_break.h create mode 100644 usr/src/sys.386bsd/ddb/db_command.c create mode 100644 usr/src/sys.386bsd/ddb/db_command.h create mode 100644 usr/src/sys.386bsd/ddb/db_examine.c create mode 100644 usr/src/sys.386bsd/ddb/db_expr.c create mode 100644 usr/src/sys.386bsd/ddb/db_input.c create mode 100644 usr/src/sys.386bsd/ddb/db_lex.c create mode 100644 usr/src/sys.386bsd/ddb/db_lex.h create mode 100644 usr/src/sys.386bsd/ddb/db_output.c create mode 100644 usr/src/sys.386bsd/ddb/db_output.h create mode 100644 usr/src/sys.386bsd/ddb/db_print.c create mode 100644 usr/src/sys.386bsd/ddb/db_sym.c create mode 100644 usr/src/sys.386bsd/ddb/db_sym.h create mode 100644 usr/src/sys.386bsd/ddb/db_trap.c create mode 100644 usr/src/sys.386bsd/ddb/db_variables.c create mode 100644 usr/src/sys.386bsd/ddb/db_variables.h create mode 100644 usr/src/sys.386bsd/ddb/db_watch.c create mode 100644 usr/src/sys.386bsd/ddb/db_watch.h create mode 100644 usr/src/sys.386bsd/ddb/db_write_cmd.c create mode 100644 usr/src/sys.386bsd/i386/i386/db_disasm.c diff --git a/usr/src/sys.386bsd/ddb/db_access.c b/usr/src/sys.386bsd/ddb/db_access.c new file mode 100644 index 0000000000..63368c0cbc --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_access.c @@ -0,0 +1,116 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_access.c,v $ + * Revision 1.1 1992/03/25 21:44:50 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:05:44 mrt + * Changed to new Mach copyright + * [91/01/31 16:16:22 mrt] + * + * Revision 2.2 90/08/27 21:48:20 dbg + * Fix type declarations. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#include "param.h" +#include "proc.h" +#include /* type definitions */ + +/* + * Access unaligned data items on aligned (longword) + * boundaries. + */ + +extern void db_read_bytes(); /* machine-dependent */ +extern void db_write_bytes(); /* machine-dependent */ + +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 int 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_MSF + for (i = 0; i < size; i++) +#else /* BYTE_LSF */ + for (i = size - 1; i >= 0; i--) +#endif + { + value = (value << 8) + (data[i] & 0xFF); + } + + if (size < 4) { + if (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 int size; + register db_expr_t value; +{ + char data[sizeof(int)]; + register int i; + +#if BYTE_MSF + for (i = size - 1; i >= 0; i--) +#else /* BYTE_LSF */ + for (i = 0; i < size; i++) +#endif + { + data[i] = value & 0xFF; + value >>= 8; + } + + db_write_bytes(addr, size, data); +} + diff --git a/usr/src/sys.386bsd/ddb/db_access.h b/usr/src/sys.386bsd/ddb/db_access.h new file mode 100644 index 0000000000..ddc5349148 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_access.h @@ -0,0 +1,55 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_access.h,v $ + * Revision 1.1 1992/03/25 21:44:53 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:05:49 mrt + * Changed to new Mach copyright + * [91/01/31 16:16:37 mrt] + * + * Revision 2.2 90/08/27 21:48:27 dbg + * Created. + * [90/08/07 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Data access functions for debugger. + */ +#include /* expression types */ + +extern db_expr_t db_get_value(/* db_addr_t addr, + int size, + boolean_t is_signed */); +extern void db_put_value(/* db_addr_t addr, + int size, + db_expr_t value */); diff --git a/usr/src/sys.386bsd/ddb/db_break.c b/usr/src/sys.386bsd/ddb/db_break.c new file mode 100644 index 0000000000..9db7a041a1 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_break.c @@ -0,0 +1,387 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_break.c,v $ + * Revision 1.1 1992/03/25 21:44:57 pace + * Initial revision + * + * Revision 2.7 91/02/05 17:06:00 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:01 mrt] + * + * Revision 2.6 91/01/08 15:09:03 rpd + * Added db_map_equal, db_map_current, db_map_addr. + * [90/11/10 rpd] + * + * Revision 2.5 90/11/05 14:26:32 rpd + * Initialize db_breakpoints_inserted to TRUE. + * [90/11/04 rpd] + * + * Revision 2.4 90/10/25 14:43:33 rwd + * Added map field to breakpoints. + * Added map argument to db_set_breakpoint, db_delete_breakpoint, + * db_find_breakpoint. Added db_find_breakpoint_here. + * [90/10/18 rpd] + * + * Revision 2.3 90/09/28 16:57:07 jsb + * Fixed db_breakpoint_free. + * [90/09/18 rpd] + * + * Revision 2.2 90/08/27 21:49:53 dbg + * Reflected changes in db_printsym()'s calling seq. + * [90/08/20 af] + * Clear breakpoints only if inserted. + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Breakpoints. + */ +#include "param.h" +#include "proc.h" +#include /* type definitions */ + +#include +#include +#include +#include +#include + +extern boolean_t db_map_equal(); +extern boolean_t db_map_current(); +extern vm_map_t db_map_addr(); + +#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 + +/* + * 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/usr/src/sys.386bsd/ddb/db_break.h b/usr/src/sys.386bsd/ddb/db_break.h new file mode 100644 index 0000000000..874cbcb5c3 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_break.h @@ -0,0 +1,84 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_break.h,v $ + * Revision 1.1 1992/03/25 21:44:59 pace + * Initial revision + * + * Revision 2.4 91/02/05 17:06:06 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:10 mrt] + * + * Revision 2.3 90/10/25 14:43:40 rwd + * Added map field to breakpoints. + * [90/10/18 rpd] + * + * Revision 2.2 90/08/27 21:50:00 dbg + * Modularized typedef names. + * [90/08/20 af] + * Add external defintions. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#ifndef _DDB_DB_BREAK_H_ +#define _DDB_DB_BREAK_H_ + +#include +#include + +/* + * Breakpoint. + */ + +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 */ +}; +typedef struct db_breakpoint *db_breakpoint_t; + +extern db_breakpoint_t db_find_breakpoint(); +extern db_breakpoint_t db_find_breakpoint_here(); +extern void db_set_breakpoints(); +extern void db_clear_breakpoints(); + +extern db_breakpoint_t db_set_temp_breakpoint(/* db_addr_t addr */); +extern void db_delete_temp_breakpoint(/* db_breakpoint_t bkpt */); + +#endif _DDB_DB_BREAK_H_ diff --git a/usr/src/sys.386bsd/ddb/db_command.c b/usr/src/sys.386bsd/ddb/db_command.c new file mode 100644 index 0000000000..637ba581be --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_command.c @@ -0,0 +1,531 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_command.c,v $ + * Revision 1.1 1992/03/25 21:45:02 pace + * Initial revision + * + * Revision 2.6 91/02/05 17:06:10 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:18 mrt] + * + * Revision 2.5 91/01/08 17:31:54 rpd + * Forward reference for db_fncall(); + * [91/01/04 12:35:17 rvb] + * + * Add call as a synonym for ! and match for next + * [91/01/04 12:14:48 rvb] + * + * Revision 2.4 90/11/07 16:49:15 rpd + * Added search. + * [90/11/06 rpd] + * + * Revision 2.3 90/10/25 14:43:45 rwd + * Changed db_fncall to print the result unsigned. + * [90/10/19 rpd] + * + * Added CS_MORE to db_watchpoint_cmd. + * [90/10/17 rpd] + * Added watchpoint commands: watch, dwatch, show watches. + * [90/10/16 rpd] + * + * Revision 2.2 90/08/27 21:50:10 dbg + * Remove 'listbreaks' - use 'show breaks' instead. Change 'show + * threads' to 'show all threads' to avoid clash with 'show thread'. + * Set 'dot' here from db_prev or db_next, depending on 'db_ed_style' + * flag and syntax table. + * [90/08/22 dbg] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Command dispatcher. + */ +#include "param.h" +#include "proc.h" +#include /* type definitions */ + +#include +#include + +#include + +/* + * Exported global variables + */ +boolean_t db_cmd_loop_done; +jmp_buf db_jmpbuf; +db_addr_t db_dot; +db_addr_t db_last_addr; +db_addr_t db_prev; +db_addr_t db_next; + +/* + * 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); +} + +/* + * Command table + */ +struct 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 command *more; /* another level of command */ +}; + +/* + * 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 command *table; + struct command **cmdp; /* out */ +{ + struct 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 command *table; +{ + register struct 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 command **last_cmdp; /* IN_OUT */ + struct command *cmd_table; +{ + struct 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; + } + } +} + +/* + * 'show' commands + */ +extern void db_listbreak_cmd(); +extern void db_listwatch_cmd(); +extern void db_show_regs(), db_show_one_thread(), db_show_all_threads(); +extern void vm_map_print(), vm_object_print(), vm_page_print(); +extern void ipc_port_print(); +void db_show_help(); + +struct command db_show_all_cmds[] = { +#if 0 + { "threads", db_show_all_threads,0, 0 }, +#endif + { (char *)0 } +}; + +struct 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 }, +#if 0 + { "thread", db_show_one_thread, 0, 0 }, +#endif + { "map", vm_map_print, 0, 0 }, + { "object", vm_object_print, 0, 0 }, +#if 0 + { "page", vm_page_print, 0, 0 }, +#endif +#if 0 + { "port", ipc_port_print, 0, 0 }, +#endif + { (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 command db_command_table[] = { + { "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 }, + { "show", 0, 0, db_show_cmds }, + { (char *)0, } +}; + +struct command *db_last_command = 0; + +void +db_help_cmd() +{ + struct command *cmd = db_command_table; + + while (cmd->name != 0) { + db_printf("%-12s", cmd->name); + db_end_line(); + cmd++; + } +} + +void +db_command_loop() +{ + /* + * Initialize 'prev' and 'next' to dot. + */ + db_prev = db_dot; + db_next = db_dot; + + db_cmd_loop_done = 0; + while (!db_cmd_loop_done) { + + (void) setjmp(db_jmpbuf); + if (db_print_position() != 0) + db_printf("\n"); + + db_printf("db> "); + (void) db_read_line(); + + db_command(&db_last_command, db_command_table); + } +} + +void +db_error(s) + char *s; +{ + if (s) + db_printf(s); + db_flush_lex(); + longjmp(db_jmpbuf, 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); +} + +int +strcmp(s1, s2) + register const char *s1, *s2; +{ + while (*s1 == *s2++) + if (*s1++ == 0) + return (0); + return (*(unsigned char *)s1 - *(unsigned char *)--s2); +} + + + + diff --git a/usr/src/sys.386bsd/ddb/db_command.h b/usr/src/sys.386bsd/ddb/db_command.h new file mode 100644 index 0000000000..938a3d6a28 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_command.h @@ -0,0 +1,67 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_command.h,v $ + * Revision 1.1 1992/03/25 21:45:05 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:15 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:28 mrt] + * + * Revision 2.2 90/08/27 21:50:19 dbg + * Replace db_last_address_examined with db_prev, db_next. + * [90/08/22 dbg] + * Created. + * [90/08/07 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Command loop declarations. + */ + +#include "param.h" +#include "proc.h" +#include + +extern void db_command_loop(); +extern void db_skip_to_eol(); + +extern void db_error(/* char * */); /* report error */ + +extern db_addr_t db_dot; /* current location */ +extern db_addr_t db_last_addr; /* last explicit address typed */ +extern db_addr_t db_prev; /* last address examined + or written */ +extern db_addr_t db_next; /* next address to be examined + or written */ + + diff --git a/usr/src/sys.386bsd/ddb/db_examine.c b/usr/src/sys.386bsd/ddb/db_examine.c new file mode 100644 index 0000000000..66f5f6858c --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_examine.c @@ -0,0 +1,364 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_examine.c,v $ + * Revision 1.1 1992/03/25 21:45:07 pace + * Initial revision + * + * Revision 2.4 91/02/05 17:06:20 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:37 mrt] + * + * Revision 2.3 90/11/07 16:49:23 rpd + * Added db_search_cmd, db_search. + * [90/11/06 rpd] + * + * Revision 2.2 90/08/27 21:50:38 dbg + * Add 'r', 'z' to print and examine formats. + * Change calling sequence of db_disasm. + * db_examine sets db_prev and db_next instead of explicitly + * advancing dot. + * [90/08/20 dbg] + * Reflected changes in db_printsym()'s calling seq. + * [90/08/20 af] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#include "param.h" +#include "proc.h" +#include /* type definitions */ + +#include +#include +#include +#include + +char db_examine_format[TOK_STRING_SIZE] = "x"; + +extern db_addr_t db_disasm(/* db_addr_t, boolean_t */); + /* instruction disassembler */ + +/* + * Examine (print) data. + */ +/*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 = 16; + while ((c = *fp++) != 0) { + switch (c) { + case 'b': + size = 1; + width = 4; + break; + case 'h': + size = 2; + width = 8; + break; + case 'l': + size = 4; + width = 16; + break; + case 'a': /* address */ + /* always forces a new line */ + if (db_print_position() != 0) + db_printf("\n"); + db_prev = addr; + db_printsym(addr, DB_STGY_ANY); + db_printf(":\t"); + break; + default: + if (db_print_position() == 0) { + /* If we hit a new symbol, print it */ + char * name; + db_expr_t off; + + db_find_sym_and_offset(addr, &name, &off); + if (off == 0) + db_printf("%s:\t", name); + else + db_printf("\t\t"); + + db_prev = addr; + } + + switch (c) { + 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(); + break; + } + } + } + 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, TRUE); +} + +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/usr/src/sys.386bsd/ddb/db_expr.c b/usr/src/sys.386bsd/ddb/db_expr.c new file mode 100644 index 0000000000..062662c48e --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_expr.c @@ -0,0 +1,248 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_expr.c,v $ + * Revision 1.1 1992/03/25 21:45:09 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:25 mrt + * Changed to new Mach copyright + * [91/01/31 16:17:46 mrt] + * + * Revision 2.2 90/08/27 21:50:57 dbg + * Use '..' instead of '$$' for db_prev. + * Use '+' for db_next. + * [90/08/22 dbg] + * + * Allow repeated unary operators. + * [90/08/20 dbg] + * + * Reflected back rename of db_symbol_value->db_value_of_name + * [90/08/20 af] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#include "param.h" +#include "proc.h" +#include +#include +#include +#include + +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/usr/src/sys.386bsd/ddb/db_input.c b/usr/src/sys.386bsd/ddb/db_input.c new file mode 100644 index 0000000000..5ec7824c51 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_input.c @@ -0,0 +1,268 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_input.c,v $ + * Revision 1.1 1992/03/25 21:45:10 pace + * Initial revision + * + * Revision 2.4 91/02/14 14:41:53 mrt + * Add input line editing. + * [90/11/11 dbg] + * + * Revision 2.3 91/02/05 17:06:32 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:13 mrt] + * + * Revision 2.2 90/08/27 21:51:03 dbg + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +#include "param.h" +#include "proc.h" +#include + +/* + * 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); + } while (c != CTRL('q')); + break; + + default: + /* drop on floor */ + break; + } +} + +cnmaygetc () +{ + return (-1); +} + +/* called from kdb_trap in db_interface.c */ +cnpollc (flag) +{ +} diff --git a/usr/src/sys.386bsd/ddb/db_lex.c b/usr/src/sys.386bsd/ddb/db_lex.c new file mode 100644 index 0000000000..dcfd90038a --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_lex.c @@ -0,0 +1,295 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_lex.c,v $ + * Revision 1.1 1992/03/25 21:45:13 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:36 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:20 mrt] + * + * Revision 2.2 90/08/27 21:51:10 dbg + * Add 'dotdot' token. + * [90/08/22 dbg] + * + * Allow backslash to quote any character into an identifier. + * Allow colon in identifier for symbol table qualification. + * [90/08/16 dbg] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Lexical analyzer. + */ +#include + +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) +{ + 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_tok_number; +char db_tok_string[TOK_STRING_SIZE]; + +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"); + db_flush_lex(); + return (tEOF); + } + 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"); + } + *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"); + } + *cp++ = c; + if (cp == db_tok_string+sizeof(db_tok_string)) { + db_error("String too long\n"); + db_flush_lex(); + return (tEOF); + } + 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/usr/src/sys.386bsd/ddb/db_lex.h b/usr/src/sys.386bsd/ddb/db_lex.h new file mode 100644 index 0000000000..56c5569499 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_lex.h @@ -0,0 +1,89 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_lex.h,v $ + * Revision 1.1 1992/03/25 21:45:15 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:41 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:28 mrt] + * + * Revision 2.2 90/08/27 21:51:16 dbg + * Add 'dotdot' token. + * [90/08/22 dbg] + * Export db_flush_lex. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Lexical analyzer. + */ +extern int db_read_line(); +extern void db_flush_line(); +extern int db_read_char(); +extern void db_unread_char(/* char c */); +extern int db_read_token(); +extern void db_unread_token(/* int t */); +extern void db_flush_lex(); + +extern int db_tok_number; +#define TOK_STRING_SIZE 120 +extern char db_tok_string[TOK_STRING_SIZE]; +extern 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/usr/src/sys.386bsd/ddb/db_output.c b/usr/src/sys.386bsd/ddb/db_output.c new file mode 100644 index 0000000000..5b1a9865d8 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_output.c @@ -0,0 +1,379 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_output.c,v $ + * Revision 1.1 1992/03/25 21:45:18 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:45 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:41 mrt] + * + * Revision 2.2 90/08/27 21:51:25 dbg + * Put extra features of db_doprnt in _doprnt. + * [90/08/20 dbg] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +/* + * Printf and character output for debugger. + */ + +#include "param.h" +#include + +/* + * 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. + */ +int db_output_position = 0; /* output column */ +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_width = 80; /* 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) { + cnputc('\t'); + last_print = next_tab; + } + else { + cnputc(' '); + last_print++; + } + } + db_last_non_space = db_output_position; +} + +/* + * Output character. Buffer whitespace. + */ +db_putchar(c) + int c; /* character to output */ +{ + 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++; + db_last_non_space = db_output_position; + } + else if (c == '\n') { + /* Return */ + cnputc(c); + db_output_position = 0; + db_last_non_space = 0; + 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); +} + +/* + * End line if too long. + */ +void +db_end_line() +{ + if (db_output_position >= db_max_width) + db_printf("\n"); +} + +/* + * Printing + */ +extern int db_radix; + +/*VARARGS1*/ +db_printf(char *fmt, ...) +{ + va_list listp; + va_start(listp, fmt); + db_printf_guts (fmt, listp); + va_end(listp); +} + +/* alternate name */ + +/*VARARGS1*/ +kdbprintf(char *fmt, ...) +{ + va_list listp; + va_start(listp, fmt); + db_printf_guts (fmt, listp); + va_end(listp); +} + +/* + * 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/usr/src/sys.386bsd/ddb/db_output.h b/usr/src/sys.386bsd/ddb/db_output.h new file mode 100644 index 0000000000..3ad599d8cc --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_output.h @@ -0,0 +1,53 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_output.h,v $ + * Revision 1.1 1992/03/25 21:45:20 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:06:49 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:48 mrt] + * + * Revision 2.2 90/08/27 21:51:32 dbg + * Created. + * [90/08/07 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 8/90 + */ + +/* + * Printing routines for kernel debugger. + */ + +extern void db_force_whitespace(); +extern int db_print_position(); +extern void db_end_line(); +extern int db_printf(); diff --git a/usr/src/sys.386bsd/ddb/db_print.c b/usr/src/sys.386bsd/ddb/db_print.c new file mode 100644 index 0000000000..48eef38c6a --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_print.c @@ -0,0 +1,104 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_print.c,v $ + * Revision 1.1 1992/03/25 21:45:22 pace + * Initial revision + * + * Revision 2.5 91/02/05 17:06:53 mrt + * Changed to new Mach copyright + * [91/01/31 16:18:56 mrt] + * + * Revision 2.4 90/10/25 14:43:54 rwd + * Changed db_show_regs to print unsigned. + * [90/10/19 rpd] + * Generalized the watchpoint support. + * [90/10/16 rwd] + * + * Revision 2.3 90/09/09 23:19:52 rpd + * Avoid totally incorrect guesses of symbol names for small values. + * [90/08/30 17:39:08 af] + * + * Revision 2.2 90/08/27 21:51:49 dbg + * Insist that 'show thread' be called with an explicit address. + * [90/08/22 dbg] + * + * Fix type for db_maxoff. + * [90/08/20 dbg] + * + * Do not dereference the "valuep" field of a variable directly, + * call the new db_read/write_variable functions instead. + * Reflected changes in symbol lookup functions. + * [90/08/20 af] + * Reduce lint. + * [90/08/10 14:33:44 dbg] + * + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +/* + * Miscellaneous printing. + */ +#include "param.h" +#include "proc.h" + +#include + +#include +#include +#include + +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/usr/src/sys.386bsd/ddb/db_sym.c b/usr/src/sys.386bsd/ddb/db_sym.c new file mode 100644 index 0000000000..0517c68521 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_sym.c @@ -0,0 +1,360 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_sym.c,v $ + * Revision 1.1 1992/03/25 21:45:27 pace + * Initial revision + * + * Revision 2.5 91/02/05 17:07:07 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:17 mrt] + * + * Revision 2.4 90/10/25 14:44:05 rwd + * Changed db_printsym to print unsigned. + * [90/10/19 rpd] + * + * Revision 2.3 90/09/09 23:19:56 rpd + * Avoid totally incorrect guesses of symbol names for small values. + * [90/08/30 17:39:48 af] + * + * Revision 2.2 90/08/27 21:52:18 dbg + * Removed nlist.h. Fixed some type declarations. + * Qualifier character is ':'. + * [90/08/20 dbg] + * Modularized symtab info into a new db_symtab_t type. + * Modified db_add_symbol_table and others accordingly. + * Defined db_sym_t, a new (opaque) type used to represent + * symbols. This should support all sort of future symtable + * formats. Functions like db_qualify take a db_sym_t now. + * New db_symbol_values() function to explode the content + * of a db_sym_t. + * db_search_symbol() replaces db_find_sym_and_offset(), which is + * now a macro defined in our (new) header file. This new + * function accepts more restrictive searches, which are + * entirely delegated to the symtab-specific code. + * Accordingly, db_printsym() accepts a strategy parameter. + * New db_line_at_pc() function. + * Renamed misleading db_eqsym into db_eqname. + * [90/08/20 10:47:06 af] + * + * Created. + * [90/07/25 dbg] + * + * Revision 2.1 90/07/26 16:43:52 dbg + * Created. + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#include "param.h" +#include "proc.h" +#include +#include + +/* + * 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 + */ +#define MAXNOSYMTABS 3 /* mach, ux, emulator */ + +db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},}; +int db_nsymtab = 0; + +db_symtab_t *db_last_symtab; + +db_sym_t db_lookup(); /* forward */ + +/* + * Add symbol table, with given name, to list of symbol tables. + */ +void +db_add_symbol_table(start, end, name, ref) + char *start; + char *end; + char *name; + char *ref; +{ + if (db_nsymtab >= MAXNOSYMTABS) { + printf ("No slots left for %s symbol table", name); + panic ("db_sym.c: db_add_symbol_table"); + } + + db_symtabs[db_nsymtab].start = start; + db_symtabs[db_nsymtab].end = end; + db_symtabs[db_nsymtab].name = name; + db_symtabs[db_nsymtab].private = ref; + db_nsymtab++; +} + +/* + * db_qualify("vm_map", "ux") returns "unix: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 = db_nsymtab; + 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 < db_nsymtab; i++) { + if (! strcmp(symstr, db_symtabs[i].name)) { + symtab_start = i; + symtab_end = i + 1; + break; + } + } + *cp = ':'; + if (i == db_nsymtab) { + db_error("invalid symbol table name"); + } + symstr = cp+1; + } + } + + /* + * Look in the specified set of symbol tables. + * Return on first match. + */ + for (i = symtab_start; i < symtab_end; i++) { + if (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 < db_nsymtab; i++) { + if (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 < db_nsymtab; i++) { + 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). + */ + +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; + + cursym = db_search_symbol(off, strategy, &d); + db_symbol_values(cursym, &name, &value); + if (name == 0 || d >= db_maxoff || value == 0) { + db_printf("%#n", off); + return; + } + 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); + } +} + + +boolean_t +db_line_at_pc( sym, filename, linenum, pc) +{ + return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc); +} diff --git a/usr/src/sys.386bsd/ddb/db_sym.h b/usr/src/sys.386bsd/ddb/db_sym.h new file mode 100644 index 0000000000..663f1cd420 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_sym.h @@ -0,0 +1,114 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_sym.h,v $ + * Revision 1.1 1992/03/25 21:45:29 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:07:12 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:27 mrt] + * + * Revision 2.2 90/08/27 21:52:39 dbg + * Changed type of db_sym_t to char * - it's a better type for an + * opaque pointer. + * [90/08/22 dbg] + * + * Created. + * [90/08/19 af] + * + */ +/* + * 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 + */ +extern void db_add_symbol_table(); + /* extend the list of symbol tables */ + +extern int db_value_of_name(/* char*, db_expr_t* */); + /* find symbol value given name */ + +extern db_sym_t db_search_symbol(/* db_expr_t, db_strategy_t, int* */); + /* find symbol given value */ + +extern void db_symbol_values(/* 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 */ + +extern int db_eqname(/* char*, char*, char */); + /* strcmp, modulo leading char */ + +extern void db_printsym(/* db_expr_t, db_strategy_t */); + /* print closest symbol to a value */ diff --git a/usr/src/sys.386bsd/ddb/db_trap.c b/usr/src/sys.386bsd/ddb/db_trap.c new file mode 100644 index 0000000000..099fab1439 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_trap.c @@ -0,0 +1,106 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_trap.c,v $ + * Revision 1.1 1992/03/25 21:45:31 pace + * Initial revision + * + * Revision 2.5 91/02/05 17:07:16 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:35 mrt] + * + * Revision 2.4 91/01/08 15:09:17 rpd + * Changed db_stop_at_pc's arguments. + * Print db_inst_count, db_load_count, db_store_count. + * [90/11/27 rpd] + * + * Revision 2.3 90/10/25 14:44:11 rwd + * From rpd. + * [90/10/19 17:03:17 rwd] + * + * Generalized the watchpoint support. + * [90/10/16 rwd] + * Added watchpoint support. + * [90/10/16 rpd] + * + * Revision 2.2 90/08/27 21:52:52 dbg + * Assign to db_dot before calling the print function. + * [90/08/20 af] + * Reduce lint. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +/* + * Trap entry point to kernel debugger. + */ +#include "param.h" +#include "proc.h" +#include +#include + +extern void db_restart_at_pc(); +extern boolean_t db_stop_at_pc(); + +extern int db_inst_count; +extern int db_load_count; +extern int db_store_count; + +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(&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(watchpt); +} diff --git a/usr/src/sys.386bsd/ddb/db_variables.c b/usr/src/sys.386bsd/ddb/db_variables.c new file mode 100644 index 0000000000..ed9512df52 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_variables.c @@ -0,0 +1,186 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_variables.c,v $ + * Revision 1.1 1992/03/25 21:45:33 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:07:19 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:46 mrt] + * + * Revision 2.2 90/08/27 21:53:24 dbg + * New db_read/write_variable functions. Should be used instead + * of dereferencing valuep directly, which might not be a true + * pointer if there is an fcn() access function. + * [90/08/20 af] + * + * Fix declarations. + * Check for trailing garbage after last expression on command line. + * [90/08/10 14:34:54 dbg] + * + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +#include "param.h" +#include "proc.h" +#include + +#include +#include + +extern unsigned int db_maxoff; + +extern int db_radix; +extern int db_max_width; +extern int db_tab_stop_width; + +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 }, +}; +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"); + return (0); +} + +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"); + return; + } + if (!db_find_variable(&vp)) { + db_error("Unknown variable\n"); + return; + } + + t = db_read_token(); + if (t != tEQ) + db_unread_token(t); + + if (!db_expression(&value)) { + db_error("No value\n"); + return; + } + if (db_read_token() != tEOL) { + db_error("?\n"); + } + + db_write_variable(vp, &value); +} diff --git a/usr/src/sys.386bsd/ddb/db_variables.h b/usr/src/sys.386bsd/ddb/db_variables.h new file mode 100644 index 0000000000..f958d2c383 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_variables.h @@ -0,0 +1,72 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_variables.h,v $ + * Revision 1.1 1992/03/25 21:45:35 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:07:23 mrt + * Changed to new Mach copyright + * [91/01/31 16:19:54 mrt] + * + * Revision 2.2 90/08/27 21:53:40 dbg + * Modularized typedef name. Documented the calling sequence of + * the (optional) access function of a variable. Now the valuep + * field can be made opaque, eg be an offset that fcn() resolves. + * [90/08/20 af] + * + * Created. + * [90/07/25 dbg] + * + */ +/* + * 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/usr/src/sys.386bsd/ddb/db_watch.c b/usr/src/sys.386bsd/ddb/db_watch.c new file mode 100644 index 0000000000..e69d906d93 --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_watch.c @@ -0,0 +1,294 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_watch.c,v $ + * Revision 1.1 1992/03/25 21:45:37 pace + * Initial revision + * + * Revision 2.5 91/02/05 17:07:27 mrt + * Changed to new Mach copyright + * [91/01/31 16:20:02 mrt] + * + * Revision 2.4 91/01/08 15:09:24 rpd + * Use db_map_equal, db_map_current, db_map_addr. + * [90/11/10 rpd] + * + * Revision 2.3 90/11/05 14:26:39 rpd + * Initialize db_watchpoints_inserted to TRUE. + * [90/11/04 rpd] + * + * Revision 2.2 90/10/25 14:44:16 rwd + * Made db_watchpoint_cmd parse a size argument. + * [90/10/17 rpd] + * Generalized the watchpoint support. + * [90/10/16 rwd] + * Created. + * [90/10/16 rpd] + * + */ +/* + * Author: Richard P. Draves, Carnegie Mellon University + * Date: 10/90 + */ + +#include "param.h" +#include "proc.h" +#include + +#include +#include +#include +#include +#include +#include + +/* + * Watchpoints. + */ + +extern boolean_t db_map_equal(); +extern boolean_t db_map_current(); +extern vm_map_t db_map_addr(); + +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/usr/src/sys.386bsd/ddb/db_watch.h b/usr/src/sys.386bsd/ddb/db_watch.h new file mode 100644 index 0000000000..9795755bfd --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_watch.h @@ -0,0 +1,74 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_watch.h,v $ + * Revision 1.1 1992/03/25 21:45:40 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:07:31 mrt + * Changed to new Mach copyright + * [91/01/31 16:20:09 mrt] + * + * Revision 2.2 90/10/25 14:44:21 rwd + * Generalized the watchpoint support. + * [90/10/16 rwd] + * Created. + * [90/10/16 rpd] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 10/90 + */ + +#ifndef _DDB_DB_WATCH_ +#define _DDB_DB_WATCH_ + +#include +#include + +/* + * 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; + +extern boolean_t db_find_watchpoint(/* vm_map_t map, db_addr_t addr, + db_regs_t *regs */); +extern void db_set_watchpoints(); +extern void db_clear_watchpoints(); + +extern void db_set_watchpoint(/* vm_map_t map, db_addr_t addr, vm_size_t size */); +extern void db_delete_watchpoint(/* vm_map_t map, db_addr_t addr */); +extern void db_list_watchpoints(); + +#endif _DDB_DB_WATCH_ diff --git a/usr/src/sys.386bsd/ddb/db_write_cmd.c b/usr/src/sys.386bsd/ddb/db_write_cmd.c new file mode 100644 index 0000000000..dce22a915c --- /dev/null +++ b/usr/src/sys.386bsd/ddb/db_write_cmd.c @@ -0,0 +1,120 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_write_cmd.c,v $ + * Revision 1.1 1992/03/25 21:45:42 pace + * Initial revision + * + * Revision 2.4 91/02/05 17:07:35 mrt + * Changed to new Mach copyright + * [91/01/31 16:20:19 mrt] + * + * Revision 2.3 90/10/25 14:44:26 rwd + * Changed db_write_cmd to print unsigned. + * [90/10/19 rpd] + * + * Revision 2.2 90/08/27 21:53:54 dbg + * Set db_prev and db_next instead of explicitly advancing dot. + * [90/08/22 dbg] + * Reflected changes in db_printsym()'s calling seq. + * [90/08/20 af] + * Warn user if nothing was written. + * [90/08/07 dbg] + * Created. + * [90/07/25 dbg] + * + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +#include "param.h" +#include "proc.h" +#include + +#include +#include +#include +#include + +/* + * 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"); + return; + } + + 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"); + + db_next = addr; + db_prev = addr - size; + + db_skip_to_eol(); +} + diff --git a/usr/src/sys.386bsd/i386/i386/db_disasm.c b/usr/src/sys.386bsd/i386/i386/db_disasm.c new file mode 100644 index 0000000000..20430b6741 --- /dev/null +++ b/usr/src/sys.386bsd/i386/i386/db_disasm.c @@ -0,0 +1,1397 @@ +/* + * 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. + */ +/* + * HISTORY + * $Log: db_disasm.c,v $ + * Revision 1.1 1992/03/25 21:42:01 pace + * Initial revision + * + * Revision 2.3 91/02/05 17:11:03 mrt + * Changed to new Mach copyright + * [91/02/01 17:31:03 mrt] + * + * Revision 2.2 90/08/27 21:55:56 dbg + * Fix register operand for move to/from control/test/debug + * register instructions. Add i486 instructions. + * [90/08/27 dbg] + * + * Import db_sym.h. Print instruction displacements in + * current radix (signed). Change calling sequence of + * db_disasm. + * [90/08/21 dbg] + * Fix includes. + * [90/08/08 dbg] + * Created. + * [90/07/25 dbg] + * + */ + +/* + * Instruction disassembler. + */ +#include "param.h" +#include "proc.h" +#include + +#include +#include + +/* + * Size attributes + */ +#define BYTE 0 +#define WORD 1 +#define LONG 2 +#define QUAD 3 +#define SNGL 4 +#define DBLR 5 +#define EXTR 6 +#define SDEP 7 +#define NONE 8 + +/* + * Addressing modes + */ +#define E 1 /* general effective address */ +#define Eind 2 /* indirect address (jump, call) */ +#define Ew 3 /* address, word size */ +#define Eb 4 /* address, byte size */ +#define R 5 /* register, in 'reg' field */ +#define Rw 6 /* word register, in 'reg' field */ +#define Ri 7 /* register in instruction */ +#define S 8 /* segment reg, in 'reg' field */ +#define Si 9 /* segment reg, in instruction */ +#define A 10 /* accumulator */ +#define BX 11 /* (bx) */ +#define CL 12 /* cl, for shifts */ +#define DX 13 /* dx, for IO */ +#define SI 14 /* si */ +#define DI 15 /* di */ +#define CR 16 /* control register */ +#define DR 17 /* debug register */ +#define TR 18 /* test register */ +#define I 19 /* immediate, unsigned */ +#define Is 20 /* immediate, signed */ +#define Ib 21 /* byte immediate, unsigned */ +#define Ibs 22 /* byte immediate, signed */ +#define Iw 23 /* word immediate, unsigned */ +#define Il 24 /* long immediate */ +#define O 25 /* direct address */ +#define Db 26 /* byte displacement from EIP */ +#define Dl 27 /* long displacement from EIP */ +#define o1 28 /* constant 1 */ +#define o3 29 /* constant 3 */ +#define OS 30 /* immediate offset/segment */ +#define ST 31 /* FP stack top */ +#define STI 32 /* FP stack */ +#define X 33 /* extended FP op */ +#define XA 34 /* for 'fstcw %ax' */ + +struct inst { + char * i_name; /* name */ + short i_has_modrm; /* has regmodrm byte */ + short i_size; /* operand size */ + int i_mode; /* addressing modes */ + char * i_extra; /* pointer to extra opcode table */ +}; + +#define op1(x) (x) +#define op2(x,y) ((x)|((y)<<8)) +#define op3(x,y,z) ((x)|((y)<<8)|((z)<<16)) + +struct finst { + char * f_name; /* name for memory instruction */ + int f_size; /* size for memory instruction */ + int f_rrmode; /* mode for rr instruction */ + char * f_rrname; /* name for rr instruction + (or pointer to table) */ +}; + +char * db_Grp6[] = { + "sldt", + "str", + "lldt", + "ltr", + "verr", + "verw", + "", + "" +}; + +char * db_Grp7[] = { + "sgdt", + "sidt", + "lgdt", + "lidt", + "smsw", + "", + "lmsw", + "invlpg" +}; + +char * db_Grp8[] = { + "", + "", + "", + "", + "bt", + "bts", + "btr", + "btc" +}; + +struct inst db_inst_0f0x[] = { +/*00*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp6 }, +/*01*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp7 }, +/*02*/ { "lar", TRUE, LONG, op2(E,R), 0 }, +/*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 }, +/*04*/ { "", FALSE, NONE, 0, 0 }, +/*05*/ { "", FALSE, NONE, 0, 0 }, +/*06*/ { "clts", FALSE, NONE, 0, 0 }, +/*07*/ { "", FALSE, NONE, 0, 0 }, + +/*08*/ { "invd", FALSE, NONE, 0, 0 }, +/*09*/ { "wbinvd",FALSE, NONE, 0, 0 }, +/*0a*/ { "", FALSE, NONE, 0, 0 }, +/*0b*/ { "", FALSE, NONE, 0, 0 }, +/*0c*/ { "", FALSE, NONE, 0, 0 }, +/*0d*/ { "", FALSE, NONE, 0, 0 }, +/*0e*/ { "", FALSE, NONE, 0, 0 }, +/*0f*/ { "", FALSE, NONE, 0, 0 }, +}; + +struct inst db_inst_0f2x[] = { +/*20*/ { "mov", TRUE, LONG, op2(CR,E), 0 }, /* use E for reg */ +/*21*/ { "mov", TRUE, LONG, op2(DR,E), 0 }, /* since mod == 11 */ +/*22*/ { "mov", TRUE, LONG, op2(E,CR), 0 }, +/*23*/ { "mov", TRUE, LONG, op2(E,DR), 0 }, +/*24*/ { "mov", TRUE, LONG, op2(TR,E), 0 }, +/*25*/ { "", FALSE, NONE, 0, 0 }, +/*26*/ { "mov", TRUE, LONG, op2(E,TR), 0 }, +/*27*/ { "", FALSE, NONE, 0, 0 }, + +/*28*/ { "", FALSE, NONE, 0, 0 }, +/*29*/ { "", FALSE, NONE, 0, 0 }, +/*2a*/ { "", FALSE, NONE, 0, 0 }, +/*2b*/ { "", FALSE, NONE, 0, 0 }, +/*2c*/ { "", FALSE, NONE, 0, 0 }, +/*2d*/ { "", FALSE, NONE, 0, 0 }, +/*2e*/ { "", FALSE, NONE, 0, 0 }, +/*2f*/ { "", FALSE, NONE, 0, 0 }, +}; + +struct inst db_inst_0f8x[] = { +/*80*/ { "jo", FALSE, NONE, op1(Dl), 0 }, +/*81*/ { "jno", FALSE, NONE, op1(Dl), 0 }, +/*82*/ { "jb", FALSE, NONE, op1(Dl), 0 }, +/*83*/ { "jnb", FALSE, NONE, op1(Dl), 0 }, +/*84*/ { "jz", FALSE, NONE, op1(Dl), 0 }, +/*85*/ { "jnz", FALSE, NONE, op1(Dl), 0 }, +/*86*/ { "jbe", FALSE, NONE, op1(Dl), 0 }, +/*87*/ { "jnbe", FALSE, NONE, op1(Dl), 0 }, + +/*88*/ { "js", FALSE, NONE, op1(Dl), 0 }, +/*89*/ { "jns", FALSE, NONE, op1(Dl), 0 }, +/*8a*/ { "jp", FALSE, NONE, op1(Dl), 0 }, +/*8b*/ { "jnp", FALSE, NONE, op1(Dl), 0 }, +/*8c*/ { "jl", FALSE, NONE, op1(Dl), 0 }, +/*8d*/ { "jnl", FALSE, NONE, op1(Dl), 0 }, +/*8e*/ { "jle", FALSE, NONE, op1(Dl), 0 }, +/*8f*/ { "jnle", FALSE, NONE, op1(Dl), 0 }, +}; + +struct inst db_inst_0f9x[] = { +/*90*/ { "seto", TRUE, NONE, op1(Eb), 0 }, +/*91*/ { "setno", TRUE, NONE, op1(Eb), 0 }, +/*92*/ { "setb", TRUE, NONE, op1(Eb), 0 }, +/*93*/ { "setnb", TRUE, NONE, op1(Eb), 0 }, +/*94*/ { "setz", TRUE, NONE, op1(Eb), 0 }, +/*95*/ { "setnz", TRUE, NONE, op1(Eb), 0 }, +/*96*/ { "setbe", TRUE, NONE, op1(Eb), 0 }, +/*97*/ { "setnbe",TRUE, NONE, op1(Eb), 0 }, + +/*98*/ { "sets", TRUE, NONE, op1(Eb), 0 }, +/*99*/ { "setns", TRUE, NONE, op1(Eb), 0 }, +/*9a*/ { "setp", TRUE, NONE, op1(Eb), 0 }, +/*9b*/ { "setnp", TRUE, NONE, op1(Eb), 0 }, +/*9c*/ { "setl", TRUE, NONE, op1(Eb), 0 }, +/*9d*/ { "setnl", TRUE, NONE, op1(Eb), 0 }, +/*9e*/ { "setle", TRUE, NONE, op1(Eb), 0 }, +/*9f*/ { "setnle",TRUE, NONE, op1(Eb), 0 }, +}; + +struct inst db_inst_0fax[] = { +/*a0*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*a1*/ { "pop", FALSE, NONE, op1(Si), 0 }, +/*a2*/ { "", FALSE, NONE, 0, 0 }, +/*a3*/ { "bt", TRUE, LONG, op2(E,R), 0 }, +/*a4*/ { "shld", TRUE, LONG, op3(Ib,E,R), 0 }, +/*a5*/ { "shld", TRUE, LONG, op3(CL,E,R), 0 }, +/*a6*/ { "", FALSE, NONE, 0, 0 }, +/*a7*/ { "", FALSE, NONE, 0, 0 }, + +/*a8*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*a9*/ { "pop", FALSE, NONE, op1(Si), 0 }, +/*aa*/ { "", FALSE, NONE, 0, 0 }, +/*ab*/ { "bts", TRUE, LONG, op2(E,R), 0 }, +/*ac*/ { "shrd", TRUE, LONG, op3(Ib,E,R), 0 }, +/*ad*/ { "shrd", TRUE, LONG, op3(CL,E,R), 0 }, +/*a6*/ { "", FALSE, NONE, 0, 0 }, +/*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 }, +}; + +struct inst db_inst_0fbx[] = { +/*b0*/ { "", FALSE, NONE, 0, 0 }, +/*b1*/ { "", FALSE, NONE, 0, 0 }, +/*b2*/ { "lss", TRUE, LONG, op2(E, R), 0 }, +/*b3*/ { "bts", TRUE, LONG, op2(R, E), 0 }, +/*b4*/ { "lfs", TRUE, LONG, op2(E, R), 0 }, +/*b5*/ { "lgs", TRUE, LONG, op2(E, R), 0 }, +/*b6*/ { "movzb", TRUE, LONG, op2(E, R), 0 }, +/*b7*/ { "movzw", TRUE, LONG, op2(E, R), 0 }, + +/*b8*/ { "", FALSE, NONE, 0, 0 }, +/*b9*/ { "", FALSE, NONE, 0, 0 }, +/*ba*/ { "", TRUE, LONG, op2(Is, E), (char *)db_Grp8 }, +/*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 }, +/*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 }, +/*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 }, +/*be*/ { "movsb", TRUE, LONG, op2(E, R), 0 }, +/*bf*/ { "movsw", TRUE, LONG, op2(E, R), 0 }, +}; + +struct inst db_inst_0fcx[] = { +/*c0*/ { "xadd", TRUE, BYTE, op2(R, E), 0 }, +/*c1*/ { "xadd", TRUE, LONG, op2(R, E), 0 }, +/*c2*/ { "", FALSE, NONE, 0, 0 }, +/*c3*/ { "", FALSE, NONE, 0, 0 }, +/*c4*/ { "", FALSE, NONE, 0, 0 }, +/*c5*/ { "", FALSE, NONE, 0, 0 }, +/*c6*/ { "", FALSE, NONE, 0, 0 }, +/*c7*/ { "", FALSE, NONE, 0, 0 }, +/*c8*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*c9*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*ca*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cb*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cc*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cd*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*ce*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +/*cf*/ { "bswap", FALSE, LONG, op1(Ri), 0 }, +}; + +struct inst db_inst_0fdx[] = { +/*c0*/ { "cmpxchg",TRUE, BYTE, op2(R, E), 0 }, +/*c1*/ { "cmpxchg",TRUE, LONG, op2(R, E), 0 }, +/*c2*/ { "", FALSE, NONE, 0, 0 }, +/*c3*/ { "", FALSE, NONE, 0, 0 }, +/*c4*/ { "", FALSE, NONE, 0, 0 }, +/*c5*/ { "", FALSE, NONE, 0, 0 }, +/*c6*/ { "", FALSE, NONE, 0, 0 }, +/*c7*/ { "", FALSE, NONE, 0, 0 }, +/*c8*/ { "", FALSE, NONE, 0, 0 }, +/*c9*/ { "", FALSE, NONE, 0, 0 }, +/*ca*/ { "", FALSE, NONE, 0, 0 }, +/*cb*/ { "", FALSE, NONE, 0, 0 }, +/*cc*/ { "", FALSE, NONE, 0, 0 }, +/*cd*/ { "", FALSE, NONE, 0, 0 }, +/*ce*/ { "", FALSE, NONE, 0, 0 }, +/*cf*/ { "", FALSE, NONE, 0, 0 }, +}; + +struct inst *db_inst_0f[] = { + db_inst_0f0x, + 0, + db_inst_0f2x, + 0, + 0, + 0, + 0, + 0, + db_inst_0f8x, + db_inst_0f9x, + db_inst_0fax, + db_inst_0fbx, + db_inst_0fcx, + db_inst_0fdx, + 0, + 0 +}; + +char * db_Esc92[] = { + "fnop", "", "", "", "", "", "", "" +}; +char * db_Esc93[] = { + "", "", "", "", "", "", "", "" +}; +char * db_Esc94[] = { + "fchs", "fabs", "", "", "ftst", "fxam", "", "" +}; +char * db_Esc95[] = { + "fld1", "fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","" +}; +char * db_Esc96[] = { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp", + "fincstp" +}; +char * db_Esc97[] = { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos" +}; + +char * db_Esca4[] = { + "", "fucompp","", "", "", "", "", "" +}; + +char * db_Escb4[] = { + "", "", "fnclex","fninit","", "", "", "" +}; + +char * db_Esce3[] = { + "", "fcompp","", "", "", "", "", "" +}; + +char * db_Escf4[] = { + "fnstsw","", "", "", "", "", "", "" +}; + +struct finst db_Esc8[] = { +/*0*/ { "fadd", SNGL, op2(STI,ST), 0 }, +/*1*/ { "fmul", SNGL, op2(STI,ST), 0 }, +/*2*/ { "fcom", SNGL, op2(STI,ST), 0 }, +/*3*/ { "fcomp", SNGL, op2(STI,ST), 0 }, +/*4*/ { "fsub", SNGL, op2(STI,ST), 0 }, +/*5*/ { "fsubr", SNGL, op2(STI,ST), 0 }, +/*6*/ { "fdiv", SNGL, op2(STI,ST), 0 }, +/*7*/ { "fdivr", SNGL, op2(STI,ST), 0 }, +}; + +struct finst db_Esc9[] = { +/*0*/ { "fld", SNGL, op1(STI), 0 }, +/*1*/ { "", NONE, op1(STI), "fxch" }, +/*2*/ { "fst", SNGL, op1(X), (char *)db_Esc92 }, +/*3*/ { "fstp", SNGL, op1(X), (char *)db_Esc93 }, +/*4*/ { "fldenv", NONE, op1(X), (char *)db_Esc94 }, +/*5*/ { "fldcw", NONE, op1(X), (char *)db_Esc95 }, +/*6*/ { "fnstenv",NONE, op1(X), (char *)db_Esc96 }, +/*7*/ { "fnstcw", NONE, op1(X), (char *)db_Esc97 }, +}; + +struct finst db_Esca[] = { +/*0*/ { "fiadd", WORD, 0, 0 }, +/*1*/ { "fimul", WORD, 0, 0 }, +/*2*/ { "ficom", WORD, 0, 0 }, +/*3*/ { "ficomp", WORD, 0, 0 }, +/*4*/ { "fisub", WORD, op1(X), (char *)db_Esca4 }, +/*5*/ { "fisubr", WORD, 0, 0 }, +/*6*/ { "fidiv", WORD, 0, 0 }, +/*7*/ { "fidivr", WORD, 0, 0 } +}; + +struct finst db_Escb[] = { +/*0*/ { "fild", WORD, 0, 0 }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fist", WORD, 0, 0 }, +/*3*/ { "fistp", WORD, 0, 0 }, +/*4*/ { "", WORD, op1(X), (char *)db_Escb4 }, +/*5*/ { "fld", EXTR, 0, 0 }, +/*6*/ { "", WORD, 0, 0 }, +/*7*/ { "fstp", EXTR, 0, 0 }, +}; + +struct finst db_Escc[] = { +/*0*/ { "fadd", DBLR, op2(ST,STI), 0 }, +/*1*/ { "fmul", DBLR, op2(ST,STI), 0 }, +/*2*/ { "fcom", DBLR, op2(ST,STI), 0 }, +/*3*/ { "fcomp", DBLR, op2(ST,STI), 0 }, +/*4*/ { "fsub", DBLR, op2(ST,STI), "fsubr" }, +/*5*/ { "fsubr", DBLR, op2(ST,STI), "fsub" }, +/*6*/ { "fdiv", DBLR, op2(ST,STI), "fdivr" }, +/*7*/ { "fdivr", DBLR, op2(ST,STI), "fdiv" }, +}; + +struct finst db_Escd[] = { +/*0*/ { "fld", DBLR, op1(STI), "ffree" }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fst", DBLR, op1(STI), 0 }, +/*3*/ { "fstp", DBLR, op1(STI), 0 }, +/*4*/ { "frstor", NONE, op1(STI), "fucom" }, +/*5*/ { "", NONE, op1(STI), "fucomp" }, +/*6*/ { "fnsave", NONE, 0, 0 }, +/*7*/ { "fnstsw", NONE, 0, 0 }, +}; + +struct finst db_Esce[] = { +/*0*/ { "fiadd", LONG, op2(ST,STI), "faddp" }, +/*1*/ { "fimul", LONG, op2(ST,STI), "fmulp" }, +/*2*/ { "ficom", LONG, 0, 0 }, +/*3*/ { "ficomp", LONG, op1(X), (char *)db_Esce3 }, +/*4*/ { "fisub", LONG, op2(ST,STI), "fsubrp" }, +/*5*/ { "fisubr", LONG, op2(ST,STI), "fsubp" }, +/*6*/ { "fidiv", LONG, op2(ST,STI), "fdivrp" }, +/*7*/ { "fidivr", LONG, op2(ST,STI), "fdivp" }, +}; + +struct finst db_Escf[] = { +/*0*/ { "fild", LONG, 0, 0 }, +/*1*/ { "", LONG, 0, 0 }, +/*2*/ { "fist", LONG, 0, 0 }, +/*3*/ { "fistp", LONG, 0, 0 }, +/*4*/ { "fbld", NONE, op1(XA), (char *)db_Escf4 }, +/*5*/ { "fld", QUAD, 0, 0 }, +/*6*/ { "fbstp", NONE, 0, 0 }, +/*7*/ { "fstp", QUAD, 0, 0 }, +}; + +struct finst *db_Esc_inst[] = { + db_Esc8, db_Esc9, db_Esca, db_Escb, + db_Escc, db_Escd, db_Esce, db_Escf +}; + +char * db_Grp1[] = { + "add", + "or", + "adc", + "sbb", + "and", + "sub", + "xor", + "cmp" +}; + +char * db_Grp2[] = { + "rol", + "ror", + "rcl", + "rcr", + "shl", + "shr", + "shl", + "sar" +}; + +struct inst db_Grp3[] = { + { "test", TRUE, NONE, op2(I,E), 0 }, + { "test", TRUE, NONE, op2(I,E), 0 }, + { "not", TRUE, NONE, op1(E), 0 }, + { "neg", TRUE, NONE, op1(E), 0 }, + { "mul", TRUE, NONE, op2(E,A), 0 }, + { "imul", TRUE, NONE, op2(E,A), 0 }, + { "div", TRUE, NONE, op2(E,A), 0 }, + { "idiv", TRUE, NONE, op2(E,A), 0 }, +}; + +struct inst db_Grp4[] = { + { "inc", TRUE, BYTE, op1(E), 0 }, + { "dec", TRUE, BYTE, op1(E), 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 } +}; + +struct inst db_Grp5[] = { + { "inc", TRUE, LONG, op1(E), 0 }, + { "dec", TRUE, LONG, op1(E), 0 }, + { "call", TRUE, NONE, op1(Eind),0 }, + { "lcall", TRUE, NONE, op1(Eind),0 }, + { "jmp", TRUE, NONE, op1(Eind),0 }, + { "ljmp", TRUE, NONE, op1(Eind),0 }, + { "push", TRUE, LONG, op1(E), 0 }, + { "", TRUE, NONE, 0, 0 } +}; + +struct inst db_inst_table[256] = { +/*00*/ { "add", TRUE, BYTE, op2(R, E), 0 }, +/*01*/ { "add", TRUE, LONG, op2(R, E), 0 }, +/*02*/ { "add", TRUE, BYTE, op2(E, R), 0 }, +/*03*/ { "add", TRUE, LONG, op2(E, R), 0 }, +/*04*/ { "add", FALSE, BYTE, op2(Is, A), 0 }, +/*05*/ { "add", FALSE, LONG, op2(Is, A), 0 }, +/*06*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*07*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*08*/ { "or", TRUE, BYTE, op2(R, E), 0 }, +/*09*/ { "or", TRUE, LONG, op2(R, E), 0 }, +/*0a*/ { "or", TRUE, BYTE, op2(E, R), 0 }, +/*0b*/ { "or", TRUE, LONG, op2(E, R), 0 }, +/*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 }, +/*0d*/ { "or", FALSE, LONG, op2(I, A), 0 }, +/*0e*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*0f*/ { "", FALSE, NONE, 0, 0 }, + +/*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 }, +/*11*/ { "adc", TRUE, LONG, op2(R, E), 0 }, +/*12*/ { "adc", TRUE, BYTE, op2(E, R), 0 }, +/*13*/ { "adc", TRUE, LONG, op2(E, R), 0 }, +/*14*/ { "adc", FALSE, BYTE, op2(Is, A), 0 }, +/*15*/ { "adc", FALSE, LONG, op2(Is, A), 0 }, +/*16*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*17*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*18*/ { "sbb", TRUE, BYTE, op2(R, E), 0 }, +/*19*/ { "sbb", TRUE, LONG, op2(R, E), 0 }, +/*1a*/ { "sbb", TRUE, BYTE, op2(E, R), 0 }, +/*1b*/ { "sbb", TRUE, LONG, op2(E, R), 0 }, +/*1c*/ { "sbb", FALSE, BYTE, op2(Is, A), 0 }, +/*1d*/ { "sbb", FALSE, LONG, op2(Is, A), 0 }, +/*1e*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*1f*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*20*/ { "and", TRUE, BYTE, op2(R, E), 0 }, +/*21*/ { "and", TRUE, LONG, op2(R, E), 0 }, +/*22*/ { "and", TRUE, BYTE, op2(E, R), 0 }, +/*23*/ { "and", TRUE, LONG, op2(E, R), 0 }, +/*24*/ { "and", FALSE, BYTE, op2(I, A), 0 }, +/*25*/ { "and", FALSE, LONG, op2(I, A), 0 }, +/*26*/ { "", FALSE, NONE, 0, 0 }, +/*27*/ { "aaa", FALSE, NONE, 0, 0 }, + +/*28*/ { "sub", TRUE, BYTE, op2(R, E), 0 }, +/*29*/ { "sub", TRUE, LONG, op2(R, E), 0 }, +/*2a*/ { "sub", TRUE, BYTE, op2(E, R), 0 }, +/*2b*/ { "sub", TRUE, LONG, op2(E, R), 0 }, +/*2c*/ { "sub", FALSE, BYTE, op2(Is, A), 0 }, +/*2d*/ { "sub", FALSE, LONG, op2(Is, A), 0 }, +/*2e*/ { "", FALSE, NONE, 0, 0 }, +/*2f*/ { "das", FALSE, NONE, 0, 0 }, + +/*30*/ { "xor", TRUE, BYTE, op2(R, E), 0 }, +/*31*/ { "xor", TRUE, LONG, op2(R, E), 0 }, +/*32*/ { "xor", TRUE, BYTE, op2(E, R), 0 }, +/*33*/ { "xor", TRUE, LONG, op2(E, R), 0 }, +/*34*/ { "xor", FALSE, BYTE, op2(I, A), 0 }, +/*35*/ { "xor", FALSE, LONG, op2(I, A), 0 }, +/*36*/ { "", FALSE, NONE, 0, 0 }, +/*37*/ { "daa", FALSE, NONE, 0, 0 }, + +/*38*/ { "cmp", TRUE, BYTE, op2(R, E), 0 }, +/*39*/ { "cmp", TRUE, LONG, op2(R, E), 0 }, +/*3a*/ { "cmp", TRUE, BYTE, op2(E, R), 0 }, +/*3b*/ { "cmp", TRUE, LONG, op2(E, R), 0 }, +/*3c*/ { "cmp", FALSE, BYTE, op2(Is, A), 0 }, +/*3d*/ { "cmp", FALSE, LONG, op2(Is, A), 0 }, +/*3e*/ { "", FALSE, NONE, 0, 0 }, +/*3f*/ { "aas", FALSE, NONE, 0, 0 }, + +/*40*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*41*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*42*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*43*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*44*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*45*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*46*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*47*/ { "inc", FALSE, LONG, op1(Ri), 0 }, + +/*48*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*49*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4a*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4b*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4c*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4d*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4e*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4f*/ { "dec", FALSE, LONG, op1(Ri), 0 }, + +/*50*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*51*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*52*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*53*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*54*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*55*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*56*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*57*/ { "push", FALSE, LONG, op1(Ri), 0 }, + +/*58*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*59*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5a*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5b*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5c*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5d*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5e*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5f*/ { "pop", FALSE, LONG, op1(Ri), 0 }, + +/*60*/ { "pusha", FALSE, LONG, 0, 0 }, +/*61*/ { "popa", FALSE, LONG, 0, 0 }, +/*62*/ { "bound", TRUE, LONG, op2(E, R), 0 }, +/*63*/ { "arpl", TRUE, NONE, op2(Ew,Rw), 0 }, + +/*64*/ { "", FALSE, NONE, 0, 0 }, +/*65*/ { "", FALSE, NONE, 0, 0 }, +/*66*/ { "", FALSE, NONE, 0, 0 }, +/*67*/ { "", FALSE, NONE, 0, 0 }, + +/*68*/ { "push", FALSE, LONG, op1(I), 0 }, +/*69*/ { "imul", TRUE, LONG, op3(I,E,R), 0 }, +/*6a*/ { "push", FALSE, LONG, op1(Ib), 0 }, +/*6b*/ { "imul", TRUE, LONG, op3(Ibs,E,R),0 }, +/*6c*/ { "ins", FALSE, BYTE, op2(DX, DI), 0 }, +/*6d*/ { "ins", FALSE, LONG, op2(DX, DI), 0 }, +/*6e*/ { "outs", FALSE, BYTE, op2(SI, DX), 0 }, +/*6f*/ { "outs", FALSE, LONG, op2(SI, DX), 0 }, + +/*70*/ { "jo", FALSE, NONE, op1(Db), 0 }, +/*71*/ { "jno", FALSE, NONE, op1(Db), 0 }, +/*72*/ { "jb", FALSE, NONE, op1(Db), 0 }, +/*73*/ { "jnb", FALSE, NONE, op1(Db), 0 }, +/*74*/ { "jz", FALSE, NONE, op1(Db), 0 }, +/*75*/ { "jnz", FALSE, NONE, op1(Db), 0 }, +/*76*/ { "jbe", FALSE, NONE, op1(Db), 0 }, +/*77*/ { "jnbe", FALSE, NONE, op1(Db), 0 }, + +/*78*/ { "js", FALSE, NONE, op1(Db), 0 }, +/*79*/ { "jns", FALSE, NONE, op1(Db), 0 }, +/*7a*/ { "jp", FALSE, NONE, op1(Db), 0 }, +/*7b*/ { "jnp", FALSE, NONE, op1(Db), 0 }, +/*7c*/ { "jl", FALSE, NONE, op1(Db), 0 }, +/*7d*/ { "jnl", FALSE, NONE, op1(Db), 0 }, +/*7e*/ { "jle", FALSE, NONE, op1(Db), 0 }, +/*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 }, + +/*80*/ { "", TRUE, BYTE, op2(I, E), (char *)db_Grp1 }, +/*81*/ { "", TRUE, LONG, op2(I, E), (char *)db_Grp1 }, +/*82*/ { "", TRUE, BYTE, op2(Is,E), (char *)db_Grp1 }, +/*83*/ { "", TRUE, LONG, op2(Ibs,E), (char *)db_Grp1 }, +/*84*/ { "test", TRUE, BYTE, op2(R, E), 0 }, +/*85*/ { "test", TRUE, LONG, op2(R, E), 0 }, +/*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 }, +/*87*/ { "xchg", TRUE, LONG, op2(R, E), 0 }, + +/*88*/ { "mov", TRUE, BYTE, op2(R, E), 0 }, +/*89*/ { "mov", TRUE, LONG, op2(R, E), 0 }, +/*8a*/ { "mov", TRUE, BYTE, op2(E, R), 0 }, +/*8b*/ { "mov", TRUE, LONG, op2(E, R), 0 }, +/*8c*/ { "mov", TRUE, NONE, op2(S, Ew), 0 }, +/*8d*/ { "lea", TRUE, LONG, op2(E, R), 0 }, +/*8e*/ { "mov", TRUE, NONE, op2(Ew, S), 0 }, +/*8f*/ { "pop", TRUE, LONG, op1(E), 0 }, + +/*90*/ { "nop", FALSE, NONE, 0, 0 }, +/*91*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*92*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*93*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*94*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*95*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, + +/*98*/ { "cbw", FALSE, SDEP, 0, "cwde" }, /* cbw/cwde */ +/*99*/ { "cwd", FALSE, SDEP, 0, "cdq" }, /* cwd/cdq */ +/*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 }, +/*9b*/ { "wait", FALSE, NONE, 0, 0 }, +/*9c*/ { "pushf", FALSE, LONG, 0, 0 }, +/*9d*/ { "popf", FALSE, LONG, 0, 0 }, +/*9e*/ { "sahf", FALSE, NONE, 0, 0 }, +/*9f*/ { "lahf", FALSE, NONE, 0, 0 }, + +/*a0*/ { "mov", FALSE, BYTE, op2(O, A), 0 }, +/*a1*/ { "mov", FALSE, LONG, op2(O, A), 0 }, +/*a2*/ { "mov", FALSE, BYTE, op2(A, O), 0 }, +/*a3*/ { "mov", FALSE, LONG, op2(A, O), 0 }, +/*a4*/ { "movs", FALSE, BYTE, op2(SI,DI), 0 }, +/*a5*/ { "movs", FALSE, LONG, op2(SI,DI), 0 }, +/*a6*/ { "cmps", FALSE, BYTE, op2(SI,DI), 0 }, +/*a7*/ { "cmps", FALSE, LONG, op2(SI,DI), 0 }, + +/*a8*/ { "test", FALSE, BYTE, op2(I, A), 0 }, +/*a9*/ { "test", FALSE, LONG, op2(I, A), 0 }, +/*aa*/ { "stos", FALSE, BYTE, op1(DI), 0 }, +/*ab*/ { "stos", FALSE, LONG, op1(DI), 0 }, +/*ac*/ { "ldos", FALSE, BYTE, op1(SI), 0 }, +/*ad*/ { "ldos", FALSE, LONG, op1(SI), 0 }, +/*ae*/ { "scas", FALSE, BYTE, op1(SI), 0 }, +/*af*/ { "scas", FALSE, LONG, op1(SI), 0 }, + +/*b0*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b1*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b2*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b3*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b4*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b5*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b6*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b7*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, + +/*b8*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*b9*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*ba*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bb*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bc*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bd*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*be*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bf*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, + +/*c0*/ { "", TRUE, BYTE, op2(Ib, E), (char *)db_Grp2 }, +/*c1*/ { "", TRUE, LONG, op2(Ib, E), (char *)db_Grp2 }, +/*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 }, +/*c3*/ { "ret", FALSE, NONE, 0, 0 }, +/*c4*/ { "les", TRUE, LONG, op2(E, R), 0 }, +/*c5*/ { "lds", TRUE, LONG, op2(E, R), 0 }, +/*c6*/ { "mov", TRUE, BYTE, op2(I, E), 0 }, +/*c7*/ { "mov", TRUE, LONG, op2(I, E), 0 }, + +/*c8*/ { "enter", FALSE, NONE, op2(Ib, Iw), 0 }, +/*c9*/ { "leave", FALSE, NONE, 0, 0 }, +/*ca*/ { "lret", FALSE, NONE, op1(Iw), 0 }, +/*cb*/ { "lret", FALSE, NONE, 0, 0 }, +/*cc*/ { "int", FALSE, NONE, op1(o3), 0 }, +/*cd*/ { "int", FALSE, NONE, op1(Ib), 0 }, +/*ce*/ { "into", FALSE, NONE, 0, 0 }, +/*cf*/ { "iret", FALSE, NONE, 0, 0 }, + +/*d0*/ { "", TRUE, BYTE, op2(o1, E), (char *)db_Grp2 }, +/*d1*/ { "", TRUE, LONG, op2(o1, E), (char *)db_Grp2 }, +/*d2*/ { "", TRUE, BYTE, op2(CL, E), (char *)db_Grp2 }, +/*d3*/ { "", TRUE, LONG, op2(CL, E), (char *)db_Grp2 }, +/*d4*/ { "aam", TRUE, NONE, 0, 0 }, +/*d5*/ { "aad", TRUE, NONE, 0, 0 }, +/*d6*/ { "", FALSE, NONE, 0, 0 }, +/*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 }, + +/*d8*/ { "", TRUE, NONE, 0, (char *)db_Esc8 }, +/*d9*/ { "", TRUE, NONE, 0, (char *)db_Esc9 }, +/*da*/ { "", TRUE, NONE, 0, (char *)db_Esca }, +/*db*/ { "", TRUE, NONE, 0, (char *)db_Escb }, +/*dc*/ { "", TRUE, NONE, 0, (char *)db_Escc }, +/*dd*/ { "", TRUE, NONE, 0, (char *)db_Escd }, +/*de*/ { "", TRUE, NONE, 0, (char *)db_Esce }, +/*df*/ { "", TRUE, NONE, 0, (char *)db_Escf }, + +/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 }, +/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 }, +/*e2*/ { "loop", FALSE, NONE, op1(Db), 0 }, +/*e3*/ { "jcxz", FALSE, SDEP, op1(Db), "jecxz" }, +/*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 }, +/*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 }, +/*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 }, +/*e7*/ { "out", FALSE, LONG, op2(A, Ib) , 0 }, + +/*e8*/ { "call", FALSE, NONE, op1(Dl), 0 }, +/*e9*/ { "jmp", FALSE, NONE, op1(Dl), 0 }, +/*ea*/ { "ljmp", FALSE, NONE, op1(OS), 0 }, +/*eb*/ { "jmp", FALSE, NONE, op1(Db), 0 }, +/*ec*/ { "in", FALSE, BYTE, op2(DX, A), 0 }, +/*ed*/ { "in", FALSE, LONG, op2(DX, A) , 0 }, +/*ee*/ { "out", FALSE, BYTE, op2(A, DX), 0 }, +/*ef*/ { "out", FALSE, LONG, op2(A, DX) , 0 }, + +/*f0*/ { "", FALSE, NONE, 0, 0 }, +/*f1*/ { "", FALSE, NONE, 0, 0 }, +/*f2*/ { "", FALSE, NONE, 0, 0 }, +/*f3*/ { "", FALSE, NONE, 0, 0 }, +/*f4*/ { "hlt", FALSE, NONE, 0, 0 }, +/*f5*/ { "cmc", FALSE, NONE, 0, 0 }, +/*f6*/ { "", TRUE, BYTE, 0, (char *)db_Grp3 }, +/*f7*/ { "", TRUE, LONG, 0, (char *)db_Grp3 }, + +/*f8*/ { "clc", FALSE, NONE, 0, 0 }, +/*f9*/ { "stc", FALSE, NONE, 0, 0 }, +/*fa*/ { "cli", FALSE, NONE, 0, 0 }, +/*fb*/ { "sti", FALSE, NONE, 0, 0 }, +/*fc*/ { "cld", FALSE, NONE, 0, 0 }, +/*fd*/ { "std", FALSE, NONE, 0, 0 }, +/*fe*/ { "", TRUE, NONE, 0, (char *)db_Grp4 }, +/*ff*/ { "", TRUE, NONE, 0, (char *)db_Grp5 }, +}; + +struct inst db_bad_inst = + { "???", FALSE, NONE, 0, 0 } +; + +#define f_mod(byte) ((byte)>>6) +#define f_reg(byte) (((byte)>>3)&0x7) +#define f_rm(byte) ((byte)&0x7) + +#define sib_ss(byte) ((byte)>>6) +#define sib_index(byte) (((byte)>>3)&0x7) +#define sib_base(byte) ((byte)&0x7) + +struct i_addr { + int is_reg; /* if reg, reg number is in 'disp' */ + int disp; + char * base; + char * index; + int ss; +}; + +char * db_index_reg_16[8] = { + "%bx,%si", + "%bx,%di", + "%bp,%si", + "%bp,%di", + "%si", + "%di", + "%bp", + "%bx" +}; + +char * db_reg[3][8] = { + "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", + "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" +}; + +char * db_seg_reg[8] = { + "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "", "" +}; + +/* + * lengths for size attributes + */ +int db_lengths[] = { + 1, /* BYTE */ + 2, /* WORD */ + 4, /* LONG */ + 8, /* QUAD */ + 4, /* SNGL */ + 8, /* DBLR */ + 10, /* EXTR */ +}; + +#define get_value_inc(result, loc, size, is_signed) \ + result = db_get_value((loc), (size), (is_signed)); \ + (loc) += (size); + +/* + * Read address at location and return updated location. + */ +db_addr_t +db_read_address(loc, short_addr, regmodrm, addrp) + db_addr_t loc; + int short_addr; + int regmodrm; + struct i_addr *addrp; /* out */ +{ + int mod, rm, sib, index, ss, disp; + + mod = f_mod(regmodrm); + rm = f_rm(regmodrm); + + if (mod == 3) { + addrp->is_reg = TRUE; + addrp->disp = rm; + return (loc); + } + addrp->is_reg = FALSE; + addrp->index = 0; + + if (short_addr) { + addrp->index = 0; + addrp->ss = 0; + switch (mod) { + case 0: + if (rm == 6) { + get_value_inc(disp, loc, 2, TRUE); + addrp->disp = disp; + addrp->base = 0; + } + else { + addrp->disp = 0; + addrp->base = db_index_reg_16[rm]; + } + break; + case 1: + get_value_inc(disp, loc, 1, TRUE); + addrp->disp = disp; + addrp->base = db_index_reg_16[rm]; + break; + case 2: + get_value_inc(disp, loc, 2, TRUE); + addrp->disp = disp; + addrp->base = db_index_reg_16[rm]; + break; + } + } + else { + if (mod != 3 && rm == 4) { + get_value_inc(sib, loc, 1, FALSE); + rm = sib_base(sib); + index = sib_index(sib); + if (index != 4) + addrp->index = db_reg[LONG][index]; + addrp->ss = sib_ss(sib); + } + + switch (mod) { + case 0: + if (rm == 5) { + get_value_inc(addrp->disp, loc, 4, FALSE); + addrp->base = 0; + } + else { + addrp->disp = 0; + addrp->base = db_reg[LONG][rm]; + } + break; + + case 1: + get_value_inc(disp, loc, 1, TRUE); + addrp->disp = disp; + addrp->base = db_reg[LONG][rm]; + break; + + case 2: + get_value_inc(disp, loc, 4, FALSE); + addrp->disp = disp; + addrp->base = db_reg[LONG][rm]; + break; + } + } + return (loc); +} + +void +db_print_address(seg, size, addrp) + char * seg; + int size; + struct i_addr *addrp; +{ + if (addrp->is_reg) { + db_printf("%s", db_reg[size][addrp->disp]); + return; + } + + if (seg) { + db_printf("%s:", seg); + } + + db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY); + if (addrp->base != 0 || addrp->index != 0) { + db_printf("("); + if (addrp->base) + db_printf("%s", addrp->base); + if (addrp->index) + db_printf(",%s,%d", addrp->index, 1<ss); + db_printf(")"); + } +} + +/* + * Disassemble floating-point ("escape") instruction + * and return updated location. + */ +db_addr_t +db_disasm_esc(loc, inst, short_addr, size, seg) + db_addr_t loc; + int inst; + int short_addr; + int size; + char * seg; +{ + int regmodrm; + struct finst *fp; + int mod; + struct i_addr address; + char * name; + + get_value_inc(regmodrm, loc, 1, FALSE); + fp = &db_Esc_inst[inst - 0xd8][f_reg(regmodrm)]; + mod = f_mod(regmodrm); + if (mod != 3) { + /* + * Normal address modes. + */ + loc = db_read_address(loc, short_addr, regmodrm, &address); + db_printf(fp->f_name); + switch(fp->f_size) { + case SNGL: + db_printf("s"); + break; + case DBLR: + db_printf("l"); + break; + case EXTR: + db_printf("t"); + break; + case WORD: + db_printf("s"); + break; + case LONG: + db_printf("l"); + break; + case QUAD: + db_printf("q"); + break; + default: + break; + } + db_printf("\t"); + db_print_address(seg, BYTE, &address); + } + else { + /* + * 'reg-reg' - special formats + */ + switch (fp->f_rrmode) { + case op2(ST,STI): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + db_printf("%s\t%%st,%%st(%d)",name,f_rm(regmodrm)); + break; + case op2(STI,ST): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + db_printf("%s\t%%st(%d),%%st",name, f_rm(regmodrm)); + break; + case op1(STI): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + db_printf("%s\t%%st(%d)",name, f_rm(regmodrm)); + break; + case op1(X): + db_printf("%s", ((char **)fp->f_rrname)[f_rm(regmodrm)]); + break; + case op1(XA): + db_printf("%s\t%%ax", + ((char **)fp->f_rrname)[f_rm(regmodrm)]); + break; + default: + db_printf(""); + break; + } + } + + return (loc); +} + +/* + * Disassemble instruction at 'loc'. 'altfmt' specifies an + * (optional) alternate format. Return address of start of + * next instruction. + */ +db_addr_t +db_disasm(loc, altfmt) + db_addr_t loc; + boolean_t altfmt; +{ + int inst; + int size; + int short_addr; + char * seg; + struct inst * ip; + char * i_name; + int i_size; + int i_mode; + int regmodrm; + boolean_t first; + int displ; + int prefix; + int imm; + int imm2; + int len; + struct i_addr address; + + get_value_inc(inst, loc, 1, FALSE); + short_addr = FALSE; + size = LONG; + seg = 0; + + /* + * Get prefixes + */ + prefix = TRUE; + do { + switch (inst) { + case 0x66: /* data16 */ + size = WORD; + break; + case 0x67: + short_addr = TRUE; + break; + case 0x26: + seg = "%es"; + break; + case 0x36: + seg = "%ss"; + break; + case 0x2e: + seg = "%cs"; + break; + case 0x3e: + seg = "%ds"; + break; + case 0x64: + seg = "%fs"; + break; + case 0x65: + seg = "%gs"; + break; + case 0xf0: + db_printf("lock "); + break; + case 0xf2: + db_printf("repne "); + break; + case 0xf3: + db_printf("repe "); /* XXX repe VS rep */ + break; + default: + prefix = FALSE; + break; + } + if (prefix) { + get_value_inc(inst, loc, 1, FALSE); + } + } while (prefix); + + if (inst >= 0xd8 && inst <= 0xdf) { + loc = db_disasm_esc(loc, inst, short_addr, size, seg); + db_printf("\n"); + return (loc); + } + + if (inst == 0x0f) { + get_value_inc(inst, loc, 1, FALSE); + ip = db_inst_0f[inst>>4]; + if (ip == 0) { + ip = &db_bad_inst; + } + else { + ip = &ip[inst&0xf]; + } + } + else + ip = &db_inst_table[inst]; + + if (ip->i_has_modrm) { + get_value_inc(regmodrm, loc, 1, FALSE); + loc = db_read_address(loc, short_addr, regmodrm, &address); + } + + i_name = ip->i_name; + i_size = ip->i_size; + i_mode = ip->i_mode; + + if (ip->i_extra == (char *)db_Grp1 || + ip->i_extra == (char *)db_Grp2 || + ip->i_extra == (char *)db_Grp6 || + ip->i_extra == (char *)db_Grp7 || + ip->i_extra == (char *)db_Grp8) { + i_name = ((char **)ip->i_extra)[f_reg(regmodrm)]; + } + else if (ip->i_extra == (char *)db_Grp3) { + ip = (struct inst *)ip->i_extra; + ip = &ip[f_reg(regmodrm)]; + i_name = ip->i_name; + i_mode = ip->i_mode; + } + else if (ip->i_extra == (char *)db_Grp4 || + ip->i_extra == (char *)db_Grp5) { + ip = (struct inst *)ip->i_extra; + ip = &ip[f_reg(regmodrm)]; + i_name = ip->i_name; + i_mode = ip->i_mode; + i_size = ip->i_size; + } + + if (i_size == SDEP) { + if (size == WORD) + db_printf(i_name); + else + db_printf(ip->i_extra); + } + else { + db_printf(i_name); + if (i_size != NONE) { + if (i_size == BYTE) { + db_printf("b"); + size = BYTE; + } + else if (i_size == WORD) { + db_printf("w"); + size = WORD; + } + else if (size == WORD) + db_printf("w"); + else + db_printf("l"); + } + } + db_printf("\t"); + for (first = TRUE; + i_mode != 0; + i_mode >>= 8, first = FALSE) + { + if (!first) + db_printf(","); + + switch (i_mode & 0xFF) { + + case E: + db_print_address(seg, size, &address); + break; + + case Eind: + db_printf("*"); + db_print_address(seg, size, &address); + break; + + case Ew: + db_print_address(seg, WORD, &address); + break; + + case Eb: + db_print_address(seg, BYTE, &address); + break; + + case R: + db_printf("%s", db_reg[size][f_reg(regmodrm)]); + break; + + case Rw: + db_printf("%s", db_reg[WORD][f_reg(regmodrm)]); + break; + + case Ri: + db_printf("%s", db_reg[size][f_rm(inst)]); + break; + + case S: + db_printf("%s", db_seg_reg[f_reg(regmodrm)]); + break; + + case Si: + db_printf("%s", db_seg_reg[f_reg(inst)]); + break; + + case A: + db_printf("%s", db_reg[size][0]); /* acc */ + break; + + case BX: + if (seg) + db_printf("%s:", seg); + db_printf("(%s)", short_addr ? "%bx" : "%ebx"); + break; + + case CL: + db_printf("%%cl"); + break; + + case DX: + db_printf("%%dx"); + break; + + case SI: + if (seg) + db_printf("%s:", seg); + db_printf("(%s)", short_addr ? "%si" : "%esi"); + break; + + case DI: + db_printf("%%es:(%s)", short_addr ? "%di" : "%edi"); + break; + + case CR: + db_printf("%%cr%d", f_reg(regmodrm)); + break; + + case DR: + db_printf("%%dr%d", f_reg(regmodrm)); + break; + + case TR: + db_printf("%%tr%d", f_reg(regmodrm)); + break; + + case I: + len = db_lengths[size]; + get_value_inc(imm, loc, len, FALSE);/* unsigned */ + db_printf("$%#n", imm); + break; + + case Is: + len = db_lengths[size]; + get_value_inc(imm, loc, len, TRUE); /* signed */ + db_printf("$%#r", imm); + break; + + case Ib: + get_value_inc(imm, loc, 1, FALSE); /* unsigned */ + db_printf("$%#n", imm); + break; + + case Ibs: + get_value_inc(imm, loc, 1, TRUE); /* signed */ + db_printf("$%#r", imm); + break; + + case Iw: + get_value_inc(imm, loc, 2, FALSE); /* unsigned */ + db_printf("$%#n", imm); + break; + + case Il: + get_value_inc(imm, loc, 4, FALSE); + db_printf("$%#n", imm); + break; + + case O: + if (short_addr) { + get_value_inc(displ, loc, 2, TRUE); + } + else { + get_value_inc(displ, loc, 4, TRUE); + } + if (seg) + db_printf("%s:%#r",seg, displ); + else + db_printsym((db_addr_t)displ, DB_STGY_ANY); + break; + + case Db: + get_value_inc(displ, loc, 1, TRUE); + db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN); + break; + + case Dl: + get_value_inc(displ, loc, 4, TRUE); + db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN); + break; + + case o1: + db_printf("$1"); + break; + + case o3: + db_printf("$3"); + break; + + case OS: + get_value_inc(imm, loc, 4, FALSE); /* offset */ + get_value_inc(imm2, loc, 2, FALSE); /* segment */ + db_printf("$%#n,%#n", imm2, imm); + break; + } + } + + if (altfmt == 0) { + if (inst == 0xe9 || inst == 0xeb) { + /* + * GAS pads to longword boundary after unconditional jumps. + */ + loc = (loc + (4-1)) & ~(4-1); + } + } + db_printf("\n"); + return (loc); +} + -- 2.20.1