aboutsummaryrefslogtreecommitdiff
path: root/ddb
diff options
context:
space:
mode:
authorPasha <pasha@member.fsf.org>2024-02-20 18:49:50 +0000
committerPasha <pasha@member.fsf.org>2024-02-20 18:49:50 +0000
commit5e0b8d508ed51004bd836384293be00950ee62c9 (patch)
treee3f16b1aa8b7177032ce3ec429fbad2b1d92a876 /ddb
downloadgnumach-riscv-5e0b8d508ed51004bd836384293be00950ee62c9.tar.gz
gnumach-riscv-5e0b8d508ed51004bd836384293be00950ee62c9.tar.bz2
init gnumach copy
Diffstat (limited to 'ddb')
-rw-r--r--ddb/db_access.c136
-rw-r--r--ddb/db_access.h79
-rw-r--r--ddb/db_break.c746
-rw-r--r--ddb/db_break.h111
-rw-r--r--ddb/db_command.c594
-rw-r--r--ddb/db_command.h80
-rw-r--r--ddb/db_cond.c185
-rw-r--r--ddb/db_cond.h39
-rw-r--r--ddb/db_elf.c232
-rw-r--r--ddb/db_elf.h52
-rw-r--r--ddb/db_examine.c664
-rw-r--r--ddb/db_examine.h92
-rw-r--r--ddb/db_expr.c382
-rw-r--r--ddb/db_expr.h26
-rw-r--r--ddb/db_ext_symtab.c123
-rw-r--r--ddb/db_input.c414
-rw-r--r--ddb/db_input.h33
-rw-r--r--ddb/db_lex.c454
-rw-r--r--ddb/db_lex.h99
-rw-r--r--ddb/db_macro.c197
-rw-r--r--ddb/db_macro.h53
-rw-r--r--ddb/db_mp.c339
-rw-r--r--ddb/db_mp.h35
-rw-r--r--ddb/db_output.c217
-rw-r--r--ddb/db_output.h46
-rw-r--r--ddb/db_print.c573
-rw-r--r--ddb/db_print.h68
-rw-r--r--ddb/db_run.c430
-rw-r--r--ddb/db_run.h94
-rw-r--r--ddb/db_sym.c532
-rw-r--r--ddb/db_sym.h264
-rw-r--r--ddb/db_task_thread.c326
-rw-r--r--ddb/db_task_thread.h73
-rw-r--r--ddb/db_trap.c115
-rw-r--r--ddb/db_trap.h34
-rw-r--r--ddb/db_variables.c224
-rw-r--r--ddb/db_variables.h88
-rw-r--r--ddb/db_watch.c329
-rw-r--r--ddb/db_watch.h80
-rw-r--r--ddb/db_write_cmd.c111
-rw-r--r--ddb/db_write_cmd.h34
-rw-r--r--ddb/nlist.h63
-rw-r--r--ddb/stab.h73
-rw-r--r--ddb/tr.h117
44 files changed, 9056 insertions, 0 deletions
diff --git a/ddb/db_access.c b/ddb/db_access.c
new file mode 100644
index 0000000..509c1ba
--- /dev/null
+++ b/ddb/db_access.c
@@ -0,0 +1,136 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+#include <mach/boolean.h>
+#include <machine/db_machdep.h> /* type definitions */
+#include <machine/db_interface.h> /* function definitions */
+#include <machine/setjmp.h>
+#include <kern/task.h>
+#include <ddb/db_access.h>
+
+
+
+/*
+ * Access unaligned data items on aligned (longword)
+ * boundaries.
+ */
+
+int db_access_level = DB_ACCESS_LEVEL;
+
+/*
+ * This table is for sign-extending things.
+ * Therefore its entries are signed, and yes
+ * they are infact negative numbers.
+ * So don't you put no more Us in it. Or Ls either.
+ * Otherwise there is no point having it, n'est pas ?
+ */
+static int db_extend[sizeof(int)+1] = { /* table for sign-extending */
+ 0,
+ 0xFFFFFF80,
+ 0xFFFF8000,
+ 0xFF800000,
+ 0x80000000
+};
+
+db_expr_t
+db_get_task_value(
+ db_addr_t addr,
+ int size,
+ boolean_t is_signed,
+ task_t task)
+{
+ char data[sizeof(db_expr_t)];
+ db_expr_t value;
+ int i;
+
+ if (!db_read_bytes(addr, size, data, task))
+ return 0;
+
+ 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 <= sizeof(int)) {
+ if (is_signed && (value & db_extend[size]) != 0)
+ value |= db_extend[size];
+ }
+ return (value);
+}
+
+void
+db_put_task_value(
+ db_addr_t addr,
+ int size,
+ db_expr_t value,
+ task_t task)
+{
+ char data[sizeof(db_expr_t)];
+ 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, task);
+}
+
+db_expr_t
+db_get_value(
+ db_addr_t addr,
+ int size,
+ boolean_t is_signed)
+{
+ return(db_get_task_value(addr, size, is_signed, TASK_NULL));
+}
+
+void
+db_put_value(
+ db_addr_t addr,
+ int size,
+ db_expr_t value)
+{
+ db_put_task_value(addr, size, value, TASK_NULL);
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_access.h b/ddb/db_access.h
new file mode 100644
index 0000000..3bda5a4
--- /dev/null
+++ b/ddb/db_access.h
@@ -0,0 +1,79 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Data access functions for debugger.
+ */
+
+#ifndef _DDB_DB_ACCESS_H_
+#define _DDB_DB_ACCESS_H_
+
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+#include <ddb/db_task_thread.h>
+#include <machine/vm_param.h>
+
+/* implementation dependent access capability */
+#define DB_ACCESS_KERNEL 0 /* only kernel space */
+#define DB_ACCESS_CURRENT 1 /* kernel or current task space */
+#define DB_ACCESS_ANY 2 /* any space */
+
+#ifndef DB_ACCESS_LEVEL
+#define DB_ACCESS_LEVEL DB_ACCESS_KERNEL
+#endif /* DB_ACCESS_LEVEL */
+
+#ifndef DB_VALID_KERN_ADDR
+#define DB_VALID_KERN_ADDR(addr) ((addr) >= VM_MIN_KERNEL_ADDRESS \
+ && (addr) < VM_MAX_KERNEL_ADDRESS)
+#define DB_VALID_ADDRESS(addr,user) ((user != 0) ^ DB_VALID_KERN_ADDR(addr))
+#define DB_PHYS_EQ(task1,addr1,task2,addr2) 0
+#define DB_CHECK_ACCESS(addr,size,task) db_is_current_task(task)
+#endif /* DB_VALID_KERN_ADDR */
+
+extern int db_access_level;
+
+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 );
+
+extern db_expr_t db_get_task_value( db_addr_t addr,
+ int size,
+ boolean_t is_signed,
+ task_t task );
+
+extern void db_put_task_value( db_addr_t addr,
+ int size,
+ db_expr_t value,
+ task_t task );
+
+#endif /* _DDB_DB_ACCESS_H_ */
diff --git a/ddb/db_break.c b/ddb/db_break.c
new file mode 100644
index 0000000..374dc6a
--- /dev/null
+++ b/ddb/db_break.c
@@ -0,0 +1,746 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+
+/*
+ * Breakpoints.
+ */
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+#include <machine/db_interface.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_break.h>
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_command.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_output.h>
+#include <ddb/db_cond.h>
+#include <ddb/db_expr.h>
+
+#define NBREAKPOINTS 100
+#define NTHREAD_LIST (NBREAKPOINTS*3)
+
+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;
+
+static struct db_thread_breakpoint db_thread_break_list[NTHREAD_LIST];
+static db_thread_breakpoint_t db_free_thread_break_list = 0;
+static boolean_t db_thread_break_init = FALSE;
+static int db_breakpoint_number = 0;
+
+static db_breakpoint_t
+db_breakpoint_alloc(void)
+{
+ 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);
+}
+
+static void
+db_breakpoint_free(db_breakpoint_t bkpt)
+{
+ bkpt->link = db_free_breakpoints;
+ db_free_breakpoints = bkpt;
+}
+
+static int
+db_add_thread_breakpoint(
+ const db_breakpoint_t bkpt,
+ vm_offset_t task_thd,
+ int count,
+ boolean_t task_bpt)
+{
+ db_thread_breakpoint_t tp;
+
+ if (db_thread_break_init == FALSE) {
+ for (tp = db_thread_break_list;
+ tp < &db_thread_break_list[NTHREAD_LIST-1]; tp++)
+ tp->tb_next = tp+1;
+ tp->tb_next = 0;
+ db_free_thread_break_list = db_thread_break_list;
+ db_thread_break_init = TRUE;
+ }
+ if (db_free_thread_break_list == 0)
+ return (-1);
+ tp = db_free_thread_break_list;
+ db_free_thread_break_list = tp->tb_next;
+ tp->tb_is_task = task_bpt;
+ tp->tb_task_thd = task_thd;
+ tp->tb_count = count;
+ tp->tb_init_count = count;
+ tp->tb_cond = 0;
+ tp->tb_number = ++db_breakpoint_number;
+ tp->tb_next = bkpt->threads;
+ bkpt->threads = tp;
+ return(0);
+}
+
+static int
+db_delete_thread_breakpoint(
+ db_breakpoint_t bkpt,
+ vm_offset_t task_thd)
+{
+ db_thread_breakpoint_t tp;
+ db_thread_breakpoint_t *tpp;
+
+ if (task_thd == 0) {
+ /* delete all the thread-breakpoints */
+
+ for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
+ db_cond_free(tp);
+
+ *tpp = db_free_thread_break_list;
+ db_free_thread_break_list = bkpt->threads;
+ bkpt->threads = 0;
+ return 0;
+ } else {
+ /* delete the specified thread-breakpoint */
+
+ for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
+ if (tp->tb_task_thd == task_thd) {
+ db_cond_free(tp);
+ *tpp = tp->tb_next;
+ tp->tb_next = db_free_thread_break_list;
+ db_free_thread_break_list = tp;
+ return 0;
+ }
+
+ return -1; /* not found */
+ }
+}
+
+static db_thread_breakpoint_t __attribute__ ((pure))
+db_find_thread_breakpoint(
+ const db_breakpoint_t bkpt,
+ const thread_t thread)
+{
+ db_thread_breakpoint_t tp;
+ task_t task = (thread == THREAD_NULL)? TASK_NULL: thread->task;
+
+ for (tp = bkpt->threads; tp; tp = tp->tb_next) {
+ if (tp->tb_is_task) {
+ if (tp->tb_task_thd == (vm_offset_t)task)
+ break;
+ continue;
+ }
+ if (tp->tb_task_thd == (vm_offset_t)thread || tp->tb_task_thd == 0)
+ break;
+ }
+ return(tp);
+}
+
+db_thread_breakpoint_t
+db_find_thread_breakpoint_here(
+ const task_t task,
+ db_addr_t addr)
+{
+ db_breakpoint_t bkpt;
+
+ bkpt = db_find_breakpoint(task, addr);
+ if (bkpt == 0)
+ return(0);
+ return(db_find_thread_breakpoint(bkpt, current_thread()));
+}
+
+db_thread_breakpoint_t
+db_find_breakpoint_number(
+ int num,
+ db_breakpoint_t *bkptp)
+{
+ db_thread_breakpoint_t tp;
+ db_breakpoint_t bkpt;
+
+ for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
+ for (tp = bkpt->threads; tp; tp = tp->tb_next) {
+ if (tp->tb_number == num) {
+ if (bkptp)
+ *bkptp = bkpt;
+ return(tp);
+ }
+ }
+ }
+ return(0);
+}
+
+static void
+db_force_delete_breakpoint(
+ db_breakpoint_t bkpt,
+ vm_offset_t task_thd,
+ boolean_t is_task)
+{
+ db_printf("deleted a stale breakpoint at ");
+ if (bkpt->task == TASK_NULL || db_lookup_task(bkpt->task) >= 0)
+ db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
+ else
+ db_printf("%#X", bkpt->address);
+ if (bkpt->task)
+ db_printf(" in task %X", bkpt->task);
+ if (task_thd)
+ db_printf(" for %s %X", (is_task)? "task": "thread", task_thd);
+ db_printf("\n");
+ db_delete_thread_breakpoint(bkpt, task_thd);
+}
+
+void
+db_check_breakpoint_valid(void)
+{
+ db_thread_breakpoint_t tbp, tbp_next;
+ db_breakpoint_t bkpt, *bkptp;
+
+ bkptp = &db_breakpoint_list;
+ for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
+ if (bkpt->task != TASK_NULL) {
+ if (db_lookup_task(bkpt->task) < 0) {
+ db_force_delete_breakpoint(bkpt, 0, FALSE);
+ *bkptp = bkpt->link;
+ db_breakpoint_free(bkpt);
+ continue;
+ }
+ } else {
+ for (tbp = bkpt->threads; tbp; tbp = tbp_next) {
+ tbp_next = tbp->tb_next;
+ if (tbp->tb_task_thd == 0)
+ continue;
+ if ((tbp->tb_is_task &&
+ db_lookup_task((task_t)(tbp->tb_task_thd)) < 0) ||
+ (!tbp->tb_is_task &&
+ db_lookup_thread((thread_t)(tbp->tb_task_thd)) < 0)) {
+ db_force_delete_breakpoint(bkpt,
+ tbp->tb_task_thd, tbp->tb_is_task);
+ }
+ }
+ if (bkpt->threads == 0) {
+ db_put_task_value(bkpt->address, BKPT_SIZE,
+ bkpt->bkpt_inst, bkpt->task);
+ *bkptp = bkpt->link;
+ db_breakpoint_free(bkpt);
+ continue;
+ }
+ }
+ bkptp = &bkpt->link;
+ }
+}
+
+db_breakpoint_t
+db_set_breakpoint(
+ const task_t task,
+ db_addr_t addr,
+ int count,
+ const thread_t thread,
+ boolean_t task_bpt)
+{
+ db_breakpoint_t bkpt;
+ db_breakpoint_t alloc_bkpt = 0;
+ vm_offset_t task_thd;
+
+ bkpt = db_find_breakpoint(task, addr);
+ if (bkpt) {
+ if (thread == THREAD_NULL
+ || db_find_thread_breakpoint(bkpt, thread)) {
+ db_printf("Already set.\n");
+ return NULL;
+ }
+ } else {
+ if (!DB_CHECK_ACCESS(addr, BKPT_SIZE, task)) {
+ db_printf("Cannot set break point at %X\n", addr);
+ return NULL;
+ }
+ alloc_bkpt = bkpt = db_breakpoint_alloc();
+ if (bkpt == 0) {
+ db_printf("Too many breakpoints.\n");
+ return NULL;
+ }
+ bkpt->task = task;
+ bkpt->flags = (task && thread == THREAD_NULL)?
+ (BKPT_USR_GLOBAL|BKPT_1ST_SET): 0;
+ bkpt->address = addr;
+ bkpt->threads = 0;
+ }
+ if (db_breakpoint_list == 0)
+ db_breakpoint_number = 0;
+ task_thd = (task_bpt)? (vm_offset_t)(thread->task): (vm_offset_t)thread;
+ if (db_add_thread_breakpoint(bkpt, task_thd, count, task_bpt) < 0) {
+ if (alloc_bkpt)
+ db_breakpoint_free(alloc_bkpt);
+ db_printf("Too many thread_breakpoints.\n");
+ return NULL;
+ } else {
+ db_printf("set breakpoint #%d\n", db_breakpoint_number);
+ if (alloc_bkpt) {
+ bkpt->link = db_breakpoint_list;
+ db_breakpoint_list = bkpt;
+ }
+ return bkpt;
+ }
+}
+
+static void
+db_delete_breakpoint(
+ const task_t task,
+ db_addr_t addr,
+ vm_offset_t task_thd)
+{
+ db_breakpoint_t bkpt;
+ db_breakpoint_t *prev;
+
+ for (prev = &db_breakpoint_list; (bkpt = *prev) != 0;
+ prev = &bkpt->link) {
+ if ((bkpt->task == task
+ || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
+ && bkpt->address == addr)
+ break;
+ }
+ if (bkpt && (bkpt->flags & BKPT_SET_IN_MEM)) {
+ db_printf("cannot delete it now.\n");
+ return;
+ }
+ if (bkpt == 0
+ || db_delete_thread_breakpoint(bkpt, task_thd) < 0) {
+ db_printf("Not set.\n");
+ return;
+ }
+ if (bkpt->threads == 0) {
+ *prev = bkpt->link;
+ db_breakpoint_free(bkpt);
+ }
+}
+
+db_breakpoint_t __attribute__ ((pure))
+db_find_breakpoint(
+ const task_t task,
+ db_addr_t addr)
+{
+ db_breakpoint_t bkpt;
+
+ for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
+ if ((bkpt->task == task
+ || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
+ && bkpt->address == addr)
+ return (bkpt);
+ }
+ return (0);
+}
+
+boolean_t
+db_find_breakpoint_here(
+ const task_t task,
+ db_addr_t addr)
+{
+ db_breakpoint_t bkpt;
+
+ for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
+ if ((bkpt->task == task
+ || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
+ && bkpt->address == addr)
+ return(TRUE);
+ if ((bkpt->flags & BKPT_USR_GLOBAL) == 0 &&
+ DB_PHYS_EQ(task, addr, bkpt->task, bkpt->address))
+ return (TRUE);
+ }
+ return(FALSE);
+}
+
+boolean_t db_breakpoints_inserted = TRUE;
+
+void
+db_set_breakpoints(void)
+{
+ db_breakpoint_t bkpt;
+ task_t task;
+ db_expr_t inst;
+ task_t cur_task;
+
+ cur_task = (current_thread())? current_thread()->task: TASK_NULL;
+ if (!db_breakpoints_inserted) {
+ for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
+ if (bkpt->flags & BKPT_SET_IN_MEM)
+ continue;
+ task = bkpt->task;
+ if (bkpt->flags & BKPT_USR_GLOBAL) {
+ if ((bkpt->flags & BKPT_1ST_SET) == 0) {
+ if (cur_task == TASK_NULL)
+ continue;
+ task = cur_task;
+ } else
+ bkpt->flags &= ~BKPT_1ST_SET;
+ }
+ if (DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
+ inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE,
+ task);
+ if (inst == BKPT_SET(inst))
+ continue;
+ bkpt->bkpt_inst = inst;
+ db_put_task_value(bkpt->address,
+ BKPT_SIZE,
+ BKPT_SET(bkpt->bkpt_inst), task);
+ bkpt->flags |= BKPT_SET_IN_MEM;
+ } else {
+ db_printf("Warning: cannot set breakpoint at %X ",
+ bkpt->address);
+ if (task)
+ db_printf("in task %X\n", task);
+ else
+ db_printf("in kernel space\n");
+ }
+ }
+ db_breakpoints_inserted = TRUE;
+ }
+}
+
+void
+db_clear_breakpoints(void)
+{
+ db_breakpoint_t bkpt, *bkptp;
+ task_t task;
+ task_t cur_task;
+ db_expr_t inst;
+
+ cur_task = (current_thread())? current_thread()->task: TASK_NULL;
+ if (db_breakpoints_inserted) {
+ bkptp = &db_breakpoint_list;
+ for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
+ task = bkpt->task;
+ if (bkpt->flags & BKPT_USR_GLOBAL) {
+ if (cur_task == TASK_NULL) {
+ bkptp = &bkpt->link;
+ continue;
+ }
+ task = cur_task;
+ }
+ if ((bkpt->flags & BKPT_SET_IN_MEM)
+ && DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
+ inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE,
+ task);
+ if (inst != BKPT_SET(inst)) {
+ if (bkpt->flags & BKPT_USR_GLOBAL) {
+ bkptp = &bkpt->link;
+ continue;
+ }
+ db_force_delete_breakpoint(bkpt, 0, FALSE);
+ *bkptp = bkpt->link;
+ db_breakpoint_free(bkpt);
+ continue;
+ }
+ db_put_task_value(bkpt->address, BKPT_SIZE,
+ bkpt->bkpt_inst, task);
+ bkpt->flags &= ~BKPT_SET_IN_MEM;
+ }
+ bkptp = &bkpt->link;
+ }
+ 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(
+ task_t task,
+ db_addr_t addr)
+{
+ db_breakpoint_t bkpt;
+
+ bkpt = db_breakpoint_alloc();
+ if (bkpt == 0) {
+ db_printf("Too many breakpoints.\n");
+ return 0;
+ }
+ bkpt->task = task;
+ bkpt->address = addr;
+ bkpt->flags = BKPT_TEMP;
+ bkpt->threads = 0;
+ if (db_add_thread_breakpoint(bkpt, 0, 1, FALSE) < 0) {
+ if (bkpt)
+ db_breakpoint_free(bkpt);
+ db_printf("Too many thread_breakpoints.\n");
+ return 0;
+ }
+ bkpt->bkpt_inst = db_get_task_value(bkpt->address, BKPT_SIZE,
+ FALSE, task);
+ db_put_task_value(bkpt->address, BKPT_SIZE,
+ BKPT_SET(bkpt->bkpt_inst), task);
+ return bkpt;
+}
+
+void
+db_delete_temp_breakpoint(
+ task_t task,
+ db_breakpoint_t bkpt)
+{
+ db_put_task_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst, task);
+ db_delete_thread_breakpoint(bkpt, 0);
+ db_breakpoint_free(bkpt);
+}
+
+/*
+ * List breakpoints.
+ */
+static void
+db_list_breakpoints(void)
+{
+ db_breakpoint_t bkpt;
+
+ if (db_breakpoint_list == 0) {
+ db_printf("No breakpoints set\n");
+ return;
+ }
+
+ db_printf(" No Space Thread Cnt Address(Cond)\n");
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ {
+ db_thread_breakpoint_t tp;
+ int task_id;
+ int thread_id;
+
+ if (bkpt->threads) {
+ for (tp = bkpt->threads; tp; tp = tp->tb_next) {
+ db_printf("%3d ", tp->tb_number);
+ if (bkpt->flags & BKPT_USR_GLOBAL)
+ db_printf("user ");
+ else if (bkpt->task == TASK_NULL)
+ db_printf("kernel ");
+ else if ((task_id = db_lookup_task(bkpt->task)) < 0)
+ db_printf("%0*X ", 2*sizeof(vm_offset_t), bkpt->task);
+ else
+ db_printf("task%-3d ", task_id);
+ if (tp->tb_task_thd == 0) {
+ db_printf("all ");
+ } else {
+ if (tp->tb_is_task) {
+ task_id = db_lookup_task((task_t)(tp->tb_task_thd));
+ if (task_id < 0)
+ db_printf("%0*X ", 2*sizeof(vm_offset_t),
+ tp->tb_task_thd);
+ else
+ db_printf("task%03d ", task_id);
+ } else {
+ thread_t thd = (thread_t)(tp->tb_task_thd);
+ task_id = db_lookup_task(thd->task);
+ thread_id = db_lookup_task_thread(thd->task, thd);
+ if (task_id < 0 || thread_id < 0)
+ db_printf("%0*X ", 2*sizeof(vm_offset_t),
+ tp->tb_task_thd);
+ else
+ db_printf("task%03d.%-3d ", task_id, thread_id);
+ }
+ }
+ db_printf("%3d ", tp->tb_init_count);
+ db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
+ if (tp->tb_cond > 0) {
+ db_printf("(");
+ db_cond_print(tp);
+ db_printf(")");
+ }
+ db_printf("\n");
+ }
+ } else {
+ if (bkpt->task == TASK_NULL)
+ db_printf(" ? kernel ");
+ else
+ db_printf("%*X ", 2*sizeof(vm_offset_t), bkpt->task);
+ db_printf("(?) ");
+ db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
+ db_printf("\n");
+ }
+ }
+}
+
+/* Delete breakpoint */
+/*ARGSUSED*/
+void
+db_delete_cmd(
+ db_expr_t addr_,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ int n;
+ thread_t thread;
+ vm_offset_t task_thd;
+ boolean_t user_global = FALSE;
+ boolean_t task_bpt = FALSE;
+ boolean_t user_space = FALSE;
+ boolean_t thd_bpt = FALSE;
+ db_expr_t addr;
+ int t;
+
+ t = db_read_token();
+ if (t == tSLASH) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ db_printf("Bad modifier \"%s\"\n", db_tok_string);
+ db_error(0);
+ }
+ user_global = db_option(db_tok_string, 'U');
+ user_space = (user_global)? TRUE: db_option(db_tok_string, 'u');
+ task_bpt = db_option(db_tok_string, 'T');
+ thd_bpt = db_option(db_tok_string, 't');
+ if (task_bpt && user_global)
+ db_error("Cannot specify both 'T' and 'U' option\n");
+ t = db_read_token();
+ }
+ if (t == tHASH) {
+ db_thread_breakpoint_t tbp;
+ db_breakpoint_t bkpt;
+
+ if (db_read_token() != tNUMBER) {
+ db_printf("Bad break point number #%s\n", db_tok_string);
+ db_error(0);
+ }
+ if ((tbp = db_find_breakpoint_number(db_tok_number, &bkpt)) == 0) {
+ db_printf("No such break point #%d\n", db_tok_number);
+ db_error(0);
+ }
+ db_delete_breakpoint(bkpt->task, bkpt->address, tbp->tb_task_thd);
+ return;
+ }
+ db_unread_token(t);
+ if (!db_expression(&addr)) {
+ /*
+ * We attempt to pick up the user_space indication from db_dot,
+ * so that a plain "d" always works.
+ */
+ addr = (db_expr_t)db_dot;
+ if (!user_space && !DB_VALID_ADDRESS((vm_offset_t)addr, FALSE))
+ user_space = TRUE;
+ }
+ if (!DB_VALID_ADDRESS((vm_offset_t) addr, user_space)) {
+ db_printf("Address %#X is not in %s space\n", addr,
+ (user_space)? "user": "kernel");
+ db_error(0);
+ }
+ if (thd_bpt || task_bpt) {
+ for (n = 0; db_get_next_thread(&thread, n); n++) {
+ if (thread == THREAD_NULL)
+ db_error("No active thread\n");
+ if (task_bpt) {
+ if (thread->task == TASK_NULL)
+ db_error("No task\n");
+ task_thd = (vm_offset_t) (thread->task);
+ } else
+ task_thd = (user_global)? 0: (vm_offset_t) thread;
+ db_delete_breakpoint(db_target_space(thread, user_space),
+ (db_addr_t)addr, task_thd);
+ }
+ } else {
+ db_delete_breakpoint(db_target_space(THREAD_NULL, user_space),
+ (db_addr_t)addr, 0);
+ }
+}
+
+/* Set breakpoint with skip count */
+/*ARGSUSED*/
+void
+db_breakpoint_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ int n;
+ thread_t thread;
+ boolean_t user_global = db_option(modif, 'U');
+ boolean_t task_bpt = db_option(modif, 'T');
+ boolean_t user_space;
+
+ if (count == -1)
+ count = 1;
+
+ if (!task_bpt && db_option(modif,'t'))
+ task_bpt = TRUE;
+
+ if (task_bpt && user_global)
+ db_error("Cannot specify both 'T' and 'U'\n");
+ user_space = (user_global)? TRUE: db_option(modif, 'u');
+ if (user_space && db_access_level < DB_ACCESS_CURRENT)
+ db_error("User space break point is not supported\n");
+ if (!task_bpt && !DB_VALID_ADDRESS((vm_offset_t)addr, user_space)) {
+ /* if the user has explicitly specified user space,
+ do not insert a breakpoint into the kernel */
+ if (user_space)
+ db_error("Invalid user space address\n");
+ user_space = TRUE;
+ db_printf("%#X is in user space\n", addr);
+ }
+ if (db_option(modif, 't') || task_bpt) {
+ for (n = 0; db_get_next_thread(&thread, n); n++) {
+ if (thread == THREAD_NULL)
+ db_error("No active thread\n");
+ if (task_bpt && thread->task == TASK_NULL)
+ db_error("No task\n");
+ if (db_access_level <= DB_ACCESS_CURRENT && user_space
+ && thread->task != db_current_task())
+ db_error("Cannot set break point in inactive user space\n");
+ db_set_breakpoint(db_target_space(thread, user_space),
+ (db_addr_t)addr, count,
+ (user_global)? THREAD_NULL: thread,
+ task_bpt);
+ }
+ } else {
+ db_set_breakpoint(db_target_space(THREAD_NULL, user_space),
+ (db_addr_t)addr,
+ count, THREAD_NULL, FALSE);
+ }
+}
+
+/* list breakpoints */
+void
+db_listbreak_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ db_list_breakpoints();
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_break.h b/ddb/db_break.h
new file mode 100644
index 0000000..9f0ee95
--- /dev/null
+++ b/ddb/db_break.h
@@ -0,0 +1,111 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#ifndef _DDB_DB_BREAK_H_
+#define _DDB_DB_BREAK_H_
+
+#include <machine/db_machdep.h>
+#include <kern/thread.h>
+#include <kern/task.h>
+#include <mach/boolean.h>
+
+/*
+ * thread list at the same breakpoint address
+ */
+struct db_thread_breakpoint {
+ vm_offset_t tb_task_thd; /* target task or thread */
+ boolean_t tb_is_task; /* task qualified */
+ short tb_number; /* breakpoint number */
+ short tb_init_count; /* skip count(initial value) */
+ short tb_count; /* current skip count */
+ short tb_cond; /* break condition */
+ struct db_thread_breakpoint *tb_next; /* next chain */
+};
+
+typedef struct db_thread_breakpoint *db_thread_breakpoint_t;
+
+/*
+ * Breakpoint.
+ */
+
+struct db_breakpoint {
+ task_t task; /* target task */
+ db_addr_t address; /* set here */
+ db_thread_breakpoint_t threads; /* thread */
+ int flags; /* flags: */
+#define BKPT_SINGLE_STEP 0x2 /* to simulate single step */
+#define BKPT_TEMP 0x4 /* temporary */
+#define BKPT_USR_GLOBAL 0x8 /* global user space break point */
+#define BKPT_SET_IN_MEM 0x10 /* break point is set in memory */
+#define BKPT_1ST_SET 0x20 /* 1st time set of user global bkpt */
+#define BKPT_EXTERNAL 0x40 /* break point is not from ddb */
+ vm_size_t 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( const task_t task, db_addr_t addr) __attribute__ ((pure));
+extern boolean_t db_find_breakpoint_here( const task_t task, db_addr_t addr);
+extern void db_set_breakpoints(void);
+extern void db_clear_breakpoints(void);
+extern db_thread_breakpoint_t db_find_thread_breakpoint_here
+ ( const task_t task, db_addr_t addr );
+extern db_thread_breakpoint_t db_find_breakpoint_number
+ ( int num, db_breakpoint_t *bkptp);
+
+extern db_breakpoint_t db_set_temp_breakpoint( task_t task, db_addr_t addr);
+extern void db_delete_temp_breakpoint
+ ( task_t task, db_breakpoint_t bkpt);
+
+extern db_breakpoint_t db_set_breakpoint(const task_t task, db_addr_t addr,
+ int count, const thread_t thread,
+ boolean_t task_bpt);
+
+void db_listbreak_cmd(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char *modif);
+
+void db_delete_cmd(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_breakpoint_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+extern void db_check_breakpoint_valid(void);
+
+#endif /* _DDB_DB_BREAK_H_ */
diff --git a/ddb/db_command.c b/ddb/db_command.c
new file mode 100644
index 0000000..4671fe8
--- /dev/null
+++ b/ddb/db_command.c
@@ -0,0 +1,594 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+/*
+ * Command dispatcher.
+ */
+
+#include <string.h>
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+#include <ddb/db_command.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_macro.h>
+#include <ddb/db_expr.h>
+#include <ddb/db_examine.h>
+#include <ddb/db_print.h>
+#include <ddb/db_break.h>
+#include <ddb/db_watch.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_write_cmd.h>
+#include <ddb/db_run.h>
+#include <ddb/db_cond.h>
+
+#include <machine/setjmp.h>
+#include <machine/db_interface.h>
+#include <kern/debug.h>
+#include <kern/thread.h>
+#include <kern/slab.h>
+#include <ipc/ipc_pset.h> /* 4proto */
+#include <ipc/ipc_port.h> /* 4proto */
+
+#include <vm/vm_print.h>
+#include <vm/vm_page.h>
+#include <ipc/ipc_print.h>
+#include <ipc/mach_port.h>
+#include <kern/lock.h>
+
+/*
+ * Exported global variables
+ */
+boolean_t db_cmd_loop_done;
+jmp_buf_t *db_recover = 0;
+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;
+
+/*
+ * 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.
+ */
+static int
+db_cmd_search(
+ const char * name,
+ const struct db_command *table,
+ const struct db_command **cmdp /* out */)
+{
+ const struct db_command *cmd;
+ int result = CMD_NONE;
+
+ for (cmd = table; cmd->name != 0; cmd++) {
+ const char *lp;
+ char *rp;
+ 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 (!strncmp(name, "help", strlen(name)))
+ result = CMD_HELP;
+ }
+ return (result);
+}
+
+static void
+db_cmd_list(const struct db_command *table)
+{
+ const struct db_command *cmd;
+
+ for (cmd = table; cmd->name != 0; cmd++) {
+ db_printf("%-12s", cmd->name);
+ db_end_line();
+ }
+}
+
+static void
+db_command(
+ const struct db_command **last_cmdp, /* IN_OUT */
+ struct db_command *cmd_table)
+{
+ const struct db_command *cmd = NULL;
+ int t;
+ char modif[TOK_STRING_SIZE];
+ db_expr_t addr, count;
+ boolean_t have_addr = FALSE;
+ int result;
+
+ t = db_read_token();
+ if (t == tEOL || t == tSEMI_COLON) {
+ /* empty line repeats last command, at 'next' */
+ cmd = *last_cmdp;
+ addr = (db_expr_t)db_next;
+ have_addr = FALSE;
+ count = 1;
+ modif[0] = '\0';
+ if (t == tSEMI_COLON)
+ db_unread_token(t);
+ }
+ else if (t == tEXCL) {
+ 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:
+ if (db_exec_macro(db_tok_string) == 0)
+ return;
+ db_printf("No such command \"%s\"\n", db_tok_string);
+ 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 \"/%s\"\n", db_tok_string);
+ 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 after ','\n");
+ db_flush_lex();
+ return;
+ }
+ }
+ else {
+ db_unread_token(t);
+ count = -1;
+ }
+ }
+ }
+ *last_cmdp = cmd;
+ if (cmd != NULL) {
+ /*
+ * 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;
+ }
+ }
+}
+
+static void
+db_command_list(
+ const struct db_command **last_cmdp, /* IN_OUT */
+ struct db_command *cmd_table)
+{
+ do {
+ db_command(last_cmdp, cmd_table);
+ db_skip_to_eol();
+ } while (db_read_token() == tSEMI_COLON && db_cmd_loop_done == FALSE);
+}
+
+struct db_command db_show_all_cmds[] = {
+ { "tasks", db_show_all_tasks, 0, 0 },
+ { "threads", db_show_all_threads, 0, 0 },
+ { "slocks", (db_command_fun_t)db_show_all_slocks, 0, 0 },
+ { "runqs", (db_command_fun_t)db_show_all_runqs, 0, 0 },
+ { (char *)0 }
+};
+
+struct db_command db_show_cmds[] = {
+ { "all", 0, 0, db_show_all_cmds },
+ { "registers", (db_command_fun_t)db_show_regs, 0, 0 },
+ { "breaks", db_listbreak_cmd, 0, 0 },
+ { "watches", db_listwatch_cmd, 0, 0 },
+ { "thread", db_show_one_thread, 0, 0 },
+ { "task", db_show_one_task, 0, 0 },
+ { "macro", db_show_macro, CS_OWN, 0 },
+ { "map", vm_map_print, 0, 0 },
+ { "object", (db_command_fun_t)vm_object_print, 0, 0 },
+ { "page", (db_command_fun_t)vm_page_print, 0, 0 },
+ { "copy", (db_command_fun_t)vm_map_copy_print, 0, 0 },
+ { "port", (db_command_fun_t)ipc_port_print, 0, 0 },
+ { "pset", (db_command_fun_t)ipc_pset_print, 0, 0 },
+ { "kmsg", (db_command_fun_t)ipc_kmsg_print, 0, 0 },
+ { "msg", (db_command_fun_t)ipc_msg_print, 0, 0 },
+ { "ipc_port", db_show_port_id, 0, 0 },
+ { "slabinfo", (db_command_fun_t)db_show_slab_info, 0, 0 },
+ { "vmstat", (db_command_fun_t)db_show_vmstat, 0, 0 },
+ { (char *)0, }
+};
+
+void
+db_debug_all_traps_cmd(db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char *modif);
+void
+db_debug_port_references_cmd(db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char *modif);
+
+struct db_command db_debug_cmds[] = {
+ { "traps", db_debug_all_traps_cmd, 0, 0 },
+ { "references", db_debug_port_references_cmd, 0, 0 },
+ { (char *)0, }
+};
+
+struct db_command db_command_table[] = {
+#ifdef DB_MACHINE_COMMANDS
+ /* this must be the first entry, if it exists */
+ { "machine", 0, 0, 0},
+#endif
+ { "print", (db_command_fun_t)db_print_cmd, CS_OWN, 0 },
+ { "examine", db_examine_cmd, CS_MORE|CS_SET_DOT, 0 },
+ { "x", db_examine_cmd, CS_MORE|CS_SET_DOT, 0 },
+ { "xf", db_examine_forward, CS_SET_DOT, 0 },
+ { "xb", db_examine_backward, CS_SET_DOT, 0 },
+ { "whatis", db_whatis_cmd, CS_MORE, 0 },
+ { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 },
+ { "set", (db_command_fun_t)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, CS_OWN, 0 },
+ { "d", db_delete_cmd, CS_OWN, 0 },
+ { "break", db_breakpoint_cmd, CS_MORE, 0 },
+ { "dwatch", db_deletewatch_cmd, CS_MORE, 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 },
+ { "cond", db_cond_cmd, CS_OWN, 0 },
+ { "call", (db_command_fun_t)db_fncall, CS_OWN, 0 },
+ { "macro", db_def_macro_cmd, CS_OWN, 0 },
+ { "dmacro", db_del_macro_cmd, CS_OWN, 0 },
+ { "show", 0, 0, db_show_cmds },
+ { "debug", 0, 0, db_debug_cmds },
+ { "reset", (db_command_fun_t)db_reset_cpu, 0, 0 },
+ { "reboot", (db_command_fun_t)db_reset_cpu, 0, 0 },
+ { "halt", (db_command_fun_t)db_halt_cpu, 0, 0 },
+ { (char *)0, }
+};
+
+#ifdef DB_MACHINE_COMMANDS
+
+/* this function should be called to install the machine dependent
+ commands. It should be called before the debugger is enabled */
+void db_machine_commands_install(struct db_command *ptr)
+{
+ db_command_table[0].more = ptr;
+ return;
+}
+
+#endif /* DB_MACHINE_COMMANDS */
+
+
+const struct db_command *db_last_command = 0;
+
+void
+db_help_cmd(void)
+{
+ struct db_command *cmd = db_command_table;
+
+ while (cmd->name != 0) {
+ db_printf("%-12s", cmd->name);
+ db_end_line();
+ cmd++;
+ }
+}
+
+void
+db_command_loop(void)
+{
+ jmp_buf_t db_jmpbuf;
+ jmp_buf_t *prev = db_recover;
+ extern int db_output_line;
+ extern int db_macro_level;
+
+ /*
+ * Initialize 'prev' and 'next' to dot.
+ */
+ db_prev = db_dot;
+ db_next = db_dot;
+
+ db_cmd_loop_done = FALSE;
+ while (!db_cmd_loop_done) {
+ (void) _setjmp(db_recover = &db_jmpbuf);
+ db_macro_level = 0;
+ if (db_print_position() != 0)
+ db_printf("\n");
+ db_output_line = 0;
+ db_printf("db%s", (db_default_thread)? "t": "");
+#if NCPUS > 1
+ db_printf("{%d}", cpu_number());
+#endif
+ db_printf("> ");
+
+ (void) db_read_line("!!");
+ db_command_list(&db_last_command, db_command_table);
+ }
+
+ db_recover = prev;
+}
+
+boolean_t
+db_exec_cmd_nest(
+ char *cmd,
+ int size)
+{
+ struct db_lex_context lex_context;
+
+ db_cmd_loop_done = FALSE;
+ if (cmd) {
+ db_save_lex_context(&lex_context);
+ db_switch_input(cmd, size /**OLD, &lex_context OLD**/);
+ }
+ db_command_list(&db_last_command, db_command_table);
+ if (cmd)
+ db_restore_lex_context(&lex_context);
+ return(db_cmd_loop_done == FALSE);
+}
+
+void db_error(const char *s)
+{
+ extern int db_macro_level;
+
+ db_macro_level = 0;
+ if (db_recover) {
+ if (s)
+ db_printf(s);
+ db_flush_lex();
+ _longjmp(db_recover, 1);
+ }
+ else
+ {
+ if (s)
+ db_printf(s);
+ panic("db_error");
+ }
+}
+
+/*
+ * Call random function:
+ * !expr(arg,arg,arg)
+ */
+void
+db_fncall(void)
+{
+ db_expr_t fn_addr;
+#define MAXARGS 11
+ db_expr_t args[MAXARGS];
+ int nargs = 0;
+ db_expr_t retval;
+ typedef db_expr_t(*function_t)(db_expr_t, db_expr_t, db_expr_t,
+ db_expr_t, db_expr_t, db_expr_t,
+ db_expr_t, db_expr_t, db_expr_t,
+ db_expr_t);
+ function_t func;
+ int t;
+
+ if (!db_expression(&fn_addr)) {
+ db_printf("Bad function \"%s\"\n", db_tok_string);
+ db_flush_lex();
+ return;
+ }
+ func = (function_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;
+ }
+ }
+ 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);
+}
+
+boolean_t __attribute__ ((pure))
+db_option(
+ const char *modif,
+ int option)
+{
+ const char *p;
+
+ for (p = modif; *p; p++)
+ if (*p == option)
+ return(TRUE);
+ return(FALSE);
+}
+
+void
+db_debug_all_traps_cmd(db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char *modif)
+{
+ if (strcmp (modif, "on") == 0)
+ db_debug_all_traps (TRUE);
+ else if (strcmp (modif, "off") == 0)
+ db_debug_all_traps (FALSE);
+ else
+ db_error ("debug traps /on|/off\n");
+}
+
+void
+db_debug_port_references_cmd(db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char *modif)
+{
+ if (strcmp (modif, "on") == 0)
+ db_debug_port_references (TRUE);
+ else if (strcmp (modif, "off") == 0)
+ db_debug_port_references (FALSE);
+ else
+ db_error ("debug references /on|/off\n");
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_command.h b/ddb/db_command.h
new file mode 100644
index 0000000..73690a4
--- /dev/null
+++ b/ddb/db_command.h
@@ -0,0 +1,80 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992,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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#ifndef _DDB_DB_COMMAND_H_
+#define _DDB_DB_COMMAND_H_
+
+#if MACH_KDB
+
+/*
+ * Command loop declarations.
+ */
+
+#include <machine/db_machdep.h>
+#include <machine/setjmp.h>
+
+extern void db_command_loop(void);
+extern boolean_t db_option(const char *, int) __attribute__ ((pure));
+
+extern void db_error(const char *) __attribute__ ((noreturn)); /* 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 */
+extern jmp_buf_t * db_recover; /* error recovery */
+
+typedef void (*db_command_fun_t)(db_expr_t, boolean_t, db_expr_t, const char *);
+
+/*
+ * Command table
+ */
+struct db_command {
+ char * name; /* command name */
+ db_command_fun_t fcn; /* function to call */
+ int flag; /* extra info: */
+#define CS_OWN 0x1 /* non-standard syntax */
+#define CS_MORE 0x2 /* standard syntax, but may have other
+ words at end */
+#define CS_SET_DOT 0x100 /* set dot after command */
+ struct db_command *more; /* another level of command */
+};
+
+extern boolean_t db_exec_cmd_nest(char *cmd, int size);
+
+void db_fncall(void);
+
+void db_help_cmd(void);
+
+#endif /* MACH_KDB */
+
+#endif /* _DDB_DB_COMMAND_H_ */
diff --git a/ddb/db_cond.c b/ddb/db_cond.c
new file mode 100644
index 0000000..d45d9b8
--- /dev/null
+++ b/ddb/db_cond.c
@@ -0,0 +1,185 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+
+#if MACH_KDB
+
+#include <machine/db_machdep.h>
+#include <machine/setjmp.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_break.h>
+#include <ddb/db_command.h>
+#include <ddb/db_cond.h>
+#include <ddb/db_expr.h>
+#include <ddb/db_output.h>
+
+#include <kern/debug.h>
+
+
+#define DB_MAX_COND 10 /* maximum conditions to be set */
+
+int db_ncond_free = DB_MAX_COND; /* free condition */
+struct db_cond {
+ int c_size; /* size of cond */
+ char c_cond_cmd[DB_LEX_LINE_SIZE]; /* cond & cmd */
+} db_cond[DB_MAX_COND];
+
+void
+db_cond_free(db_thread_breakpoint_t bkpt)
+{
+ if (bkpt->tb_cond > 0) {
+ db_cond[bkpt->tb_cond-1].c_size = 0;
+ db_ncond_free++;
+ bkpt->tb_cond = 0;
+ }
+}
+
+boolean_t
+db_cond_check(db_thread_breakpoint_t bkpt)
+{
+ struct db_cond *cp;
+ db_expr_t value;
+ int t;
+ jmp_buf_t db_jmpbuf;
+ extern jmp_buf_t *db_recover;
+
+ if (bkpt->tb_cond <= 0) /* no condition */
+ return(TRUE);
+ db_dot = PC_REGS(DDB_REGS);
+ db_prev = db_dot;
+ db_next = db_dot;
+ if (_setjmp(db_recover = &db_jmpbuf)) {
+ /*
+ * in case of error, return true to enter interactive mode
+ */
+ return(TRUE);
+ }
+
+ /*
+ * switch input, and evalutate condition
+ */
+ cp = &db_cond[bkpt->tb_cond - 1];
+ db_switch_input(cp->c_cond_cmd, cp->c_size);
+ if (!db_expression(&value)) {
+ db_printf("error: condition evaluation error\n");
+ return(TRUE);
+ }
+ if (value == 0 || --(bkpt->tb_count) > 0)
+ return(FALSE);
+
+ /*
+ * execute a command list if exist
+ */
+ bkpt->tb_count = bkpt->tb_init_count;
+ if ((t = db_read_token()) != tEOL) {
+ db_unread_token(t);
+ return(db_exec_cmd_nest(0, 0));
+ }
+ return(TRUE);
+}
+
+void
+db_cond_print(const db_thread_breakpoint_t bkpt)
+{
+ char *p, *ep;
+ struct db_cond *cp;
+
+ if (bkpt->tb_cond <= 0)
+ return;
+ cp = &db_cond[bkpt->tb_cond-1];
+ p = cp->c_cond_cmd;
+ ep = p + cp->c_size;
+ while (p < ep) {
+ if (*p == '\n' || *p == 0)
+ break;
+ db_putchar(*p++);
+ }
+}
+
+void
+db_cond_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ int c;
+ struct db_cond *cp;
+ char *p;
+ db_expr_t value;
+ db_thread_breakpoint_t bkpt;
+
+ if (db_read_token() != tHASH || db_read_token() != tNUMBER) {
+ db_printf("#<number> expected instead of \"%s\"\n", db_tok_string);
+ db_error(0);
+ return;
+ }
+ if ((bkpt = db_find_breakpoint_number(db_tok_number, 0)) == 0) {
+ db_printf("No such break point #%d\n", db_tok_number);
+ db_error(0);
+ return;
+ }
+ /*
+ * if the break point already has a condition, free it first
+ */
+ if (bkpt->tb_cond > 0) {
+ cp = &db_cond[bkpt->tb_cond - 1];
+ db_cond_free(bkpt);
+ } else {
+ if (db_ncond_free <= 0) {
+ db_error("Too many conditions\n");
+ return;
+ }
+ for (cp = db_cond; cp < &db_cond[DB_MAX_COND]; cp++)
+ if (cp->c_size == 0)
+ break;
+ if (cp >= &db_cond[DB_MAX_COND])
+ panic("bad db_cond_free");
+ }
+ for (c = db_read_char(); c == ' ' || c == '\t'; c = db_read_char());
+ for (p = cp->c_cond_cmd; c >= 0; c = db_read_char())
+ *p++ = c;
+ /*
+ * switch to saved data and call db_expression to check the condition.
+ * If no condition is supplied, db_expression will return false.
+ * In this case, clear previous condition of the break point.
+ * If condition is supplied, set the condition to the permanent area.
+ * Note: db_expression will not return here, if the condition
+ * expression is wrong.
+ */
+ db_switch_input(cp->c_cond_cmd, p - cp->c_cond_cmd);
+ if (!db_expression(&value)) {
+ /* since condition is already freed, do nothing */
+ db_flush_lex();
+ return;
+ }
+ db_flush_lex();
+ db_ncond_free--;
+ cp->c_size = p - cp->c_cond_cmd;
+ bkpt->tb_cond = (cp - db_cond) + 1;
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_cond.h b/ddb/db_cond.h
new file mode 100644
index 0000000..c867c6e
--- /dev/null
+++ b/ddb/db_cond.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Barry deFreese.
+ */
+
+#ifndef _DDB_DB_COND_H_
+#define _DDB_DB_COND_H_
+
+#include <sys/types.h>
+#include <machine/db_machdep.h>
+
+extern void db_cond_free (const db_thread_breakpoint_t bkpt);
+
+extern boolean_t db_cond_check (db_thread_breakpoint_t bkpt);
+
+extern void db_cond_print (db_thread_breakpoint_t bkpt);
+
+extern void db_cond_cmd (
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif);
+
+#endif /* _DDB_DB_COND_H_ */
diff --git a/ddb/db_elf.c b/ddb/db_elf.c
new file mode 100644
index 0000000..5ccfdd5
--- /dev/null
+++ b/ddb/db_elf.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2014 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+/*
+ * Symbol table routines for ELF format files.
+ */
+
+#include <string.h>
+#include <mach/std_types.h>
+#include <mach/exec/elf.h>
+#include <machine/db_machdep.h> /* data types */
+#include <machine/vm_param.h>
+#include <ddb/db_output.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_elf.h>
+
+#ifndef DB_NO_ELF
+
+struct db_symtab_elf {
+ int type;
+ Elf_Sym *start;
+ Elf_Sym *end;
+ char *strings;
+ char *map_pointer; /* symbols are for this map only,
+ if not null */
+ char name[SYMTAB_NAME_LEN];
+ /* symtab name */
+};
+
+boolean_t
+elf_db_sym_init (unsigned shdr_num,
+ vm_size_t shdr_size,
+ vm_offset_t shdr_addr,
+ unsigned shdr_shndx,
+ char *name,
+ char *task_addr)
+{
+ Elf_Shdr *shdr, *symtab, *strtab;
+ const char *shstrtab;
+ unsigned i;
+
+ if (shdr_num == 0)
+ return FALSE;
+
+ if (shdr_size != sizeof *shdr)
+ return FALSE;
+
+ shdr = (Elf_Shdr *) shdr_addr;
+
+ if (shdr[shdr_shndx].sh_type != SHT_STRTAB)
+ return FALSE;
+
+ shstrtab = (const char *) phystokv (shdr[shdr_shndx].sh_addr);
+
+ symtab = strtab = NULL;
+ for (i = 0; i < shdr_num; i++)
+ switch (shdr[i].sh_type) {
+ case SHT_SYMTAB:
+ if (symtab)
+ db_printf ("Ignoring additional ELF symbol table at %d\n", i);
+ else
+ symtab = &shdr[i];
+ break;
+
+ case SHT_STRTAB:
+ if (strcmp (&shstrtab[shdr[i].sh_name], ".strtab") == 0) {
+ if (strtab)
+ db_printf ("Ignoring additional ELF string table at %d\n", i);
+ else
+ strtab = &shdr[i];
+ }
+ break;
+ }
+
+ if (symtab == NULL || strtab == NULL)
+ return FALSE;
+
+ if (db_add_symbol_table (SYMTAB_ELF,
+ (char *) phystokv (symtab->sh_addr),
+ (char *) phystokv (symtab->sh_addr)+symtab->sh_size,
+ name,
+ (char *) phystokv (strtab->sh_addr),
+ task_addr)) {
+ db_printf ("Loaded ELF symbol table for %s (%d symbols)\n",
+ name, symtab->sh_size / sizeof (Elf_Sym));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * lookup symbol by name
+ */
+db_sym_t
+elf_db_lookup (db_symtab_t *stab,
+ char *symstr)
+{
+ struct db_symtab_elf *self = (struct db_symtab_elf *) stab;
+ Elf_Sym *s;
+
+ for (s = self->start; s < self->end; s++)
+ if (strcmp (symstr, &self->strings[s->st_name]) == 0)
+ return (db_sym_t) s;
+
+ return NULL;
+}
+
+db_sym_t
+elf_db_search_symbol (db_symtab_t *stab,
+ db_addr_t off,
+ db_strategy_t strategy,
+ db_expr_t *diffp) /* in/out */
+{
+ struct db_symtab_elf *self = (struct db_symtab_elf *) stab;
+ unsigned long diff = *diffp;
+ Elf_Sym *s, *symp = NULL;
+
+ for (s = self->start; s < self->end; s++) {
+ if (s->st_name == 0)
+ continue;
+
+ if (strategy == DB_STGY_XTRN && (ELF_ST_BIND(s->st_info) != STB_GLOBAL))
+ continue;
+
+ if (off >= s->st_value) {
+ if (ELF_ST_TYPE(s->st_info) != STT_FUNC)
+ continue;
+
+ if (off - s->st_value < diff) {
+ diff = off - s->st_value;
+ symp = s;
+ if (diff == 0 && (ELF_ST_BIND(s->st_info) == STB_GLOBAL))
+ break;
+ } else if (off - s->st_value == diff) {
+ if (symp == NULL)
+ symp = s;
+ else if ((ELF_ST_BIND(symp->st_info) != STB_GLOBAL)
+ && (ELF_ST_BIND(s->st_info) == STB_GLOBAL))
+ symp = s; /* pick the external symbol */
+ }
+ }
+ }
+
+ if (symp == NULL)
+ *diffp = off;
+ else
+ *diffp = diff;
+
+ return (db_sym_t) symp;
+}
+
+/*
+ * Return the name and value for a symbol.
+ */
+void
+elf_db_symbol_values (db_symtab_t *stab,
+ db_sym_t sym,
+ char **namep,
+ db_expr_t *valuep)
+{
+ struct db_symtab_elf *self = (struct db_symtab_elf *) stab;
+ Elf_Sym *s = (Elf_Sym *) sym;
+
+ if (namep)
+ *namep = &self->strings[s->st_name];
+ if (valuep)
+ *valuep = s->st_value;
+}
+
+/*
+ * Find filename and lineno within, given the current pc.
+ */
+boolean_t
+elf_db_line_at_pc (db_symtab_t *stab,
+ db_sym_t sym,
+ char **file,
+ int *line,
+ db_addr_t pc)
+{
+ /* XXX Parse DWARF information. */
+ return FALSE;
+}
+
+#endif /* DB_NO_ELF */
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_elf.h b/ddb/db_elf.h
new file mode 100644
index 0000000..12b8286
--- /dev/null
+++ b/ddb/db_elf.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _DDB_DB_ELF_H_
+#define _DDB_DB_ELF_H_
+
+#include <ddb/db_sym.h>
+#include <machine/db_machdep.h>
+
+extern boolean_t
+elf_db_line_at_pc(
+ db_symtab_t *stab,
+ db_sym_t sym,
+ char **file,
+ int *line,
+ db_addr_t pc);
+
+extern db_sym_t
+elf_db_lookup(
+ db_symtab_t *stab,
+ char * symstr);
+
+extern db_sym_t
+elf_db_search_symbol(
+ db_symtab_t * symtab,
+ db_addr_t off,
+ db_strategy_t strategy,
+ db_expr_t *diffp);
+
+extern void
+elf_db_symbol_values(
+ db_symtab_t *stab,
+ db_sym_t sym,
+ char **namep,
+ db_expr_t *valuep);
+
+#endif /* _DDB_DB_ELF_H_ */
diff --git a/ddb/db_examine.c b/ddb/db_examine.c
new file mode 100644
index 0000000..1941fc3
--- /dev/null
+++ b/ddb/db_examine.c
@@ -0,0 +1,664 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992,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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+#include <machine/db_interface.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_examine.h>
+#include <ddb/db_expr.h>
+#include <ddb/db_print.h>
+#include <kern/thread.h>
+#include <kern/task.h>
+#include <kern/smp.h>
+#include <mach/vm_param.h>
+#include <vm/vm_map.h>
+
+#define db_thread_to_task(thread) ((thread)? thread->task: TASK_NULL)
+
+char db_examine_format[TOK_STRING_SIZE] = "x";
+int db_examine_count = 1;
+db_addr_t db_examine_prev_addr = 0;
+thread_t db_examine_thread = THREAD_NULL;
+
+/*
+ * Examine (print) data.
+ */
+/*ARGSUSED*/
+void
+db_examine_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ thread_t thread;
+
+ if (modif[0] != '\0')
+ db_strcpy(db_examine_format, modif);
+
+ if (count == -1)
+ count = 1;
+ db_examine_count = count;
+ if (db_option(modif, 't'))
+ {
+ if (!db_get_next_thread(&thread, 0))
+ return;
+ }
+ else
+ if (db_option(modif, 'u'))
+ thread = current_thread();
+ else
+ thread = THREAD_NULL;
+
+ db_examine_thread = thread;
+ db_examine((db_addr_t) addr, db_examine_format, count,
+ db_thread_to_task(thread));
+}
+
+/* ARGSUSED */
+void
+db_examine_forward(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ db_examine(db_next, db_examine_format, db_examine_count,
+ db_thread_to_task(db_examine_thread));
+}
+
+/* ARGSUSED */
+void
+db_examine_backward(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+
+ db_examine(db_examine_prev_addr - (db_next - db_examine_prev_addr),
+ db_examine_format, db_examine_count,
+ db_thread_to_task(db_examine_thread));
+}
+
+void
+db_examine(
+ db_addr_t addr,
+ const char * fmt, /* format string */
+ int count, /* repeat count */
+ task_t task)
+{
+ int c;
+ db_expr_t value;
+ int size; /* in bytes */
+ int width;
+ const char * fp;
+
+ db_examine_prev_addr = addr;
+ while (--count >= 0) {
+ fp = fmt;
+ size = 4;
+ width = 4*size;
+ while ((c = *fp++) != 0) {
+ switch (c) {
+ case 'b':
+ size = 1;
+ width = 4*size;
+ break;
+ case 'h':
+ size = 2;
+ width = 4*size;
+ break;
+ case 'l':
+ size = 4;
+ width = 4*size;
+ break;
+ case 'q':
+ size = 8;
+ width = 4*size;
+ break;
+ case 'a': /* address */
+ case 'A': /* function address */
+ /* always forces a new line */
+ if (db_print_position() != 0)
+ db_printf("\n");
+ db_prev = addr;
+ db_task_printsym(addr,
+ (c == 'a')?DB_STGY_ANY:DB_STGY_PROC,
+ task);
+ db_printf(":\t");
+ break;
+ case 'm':
+ db_next = db_xcdump(addr, size, count + 1, task);
+ return;
+ default:
+ if (db_print_position() == 0) {
+ /* If we hit a new symbol, print it */
+ char * name;
+ db_addr_t off;
+
+ db_find_task_sym_and_offset(addr, &name, &off, task);
+ if (off == 0)
+ db_printf("%s:\t", name);
+ else
+ db_printf("\t\t");
+
+ db_prev = addr;
+ }
+
+ switch (c) {
+ case ',': /* skip one unit w/o printing */
+ addr += size;
+ break;
+
+ case 'r': /* signed, current radix */
+ value = db_get_task_value(addr,size,TRUE,task);
+ addr += size;
+ db_printf("%-*R", width, value);
+ break;
+ case 'x': /* unsigned hex */
+ value = db_get_task_value(addr,size,FALSE,task);
+ addr += size;
+ db_printf("%-*X", width, value);
+ break;
+ case 'z': /* signed hex */
+ value = db_get_task_value(addr,size,TRUE,task);
+ addr += size;
+ db_printf("%-*Z", width, value);
+ break;
+ case 'd': /* signed decimal */
+ value = db_get_task_value(addr,size,TRUE,task);
+ addr += size;
+ db_printf("%-*D", width, value);
+ break;
+ case 'U': /* unsigned decimal */
+ value = db_get_task_value(addr,size,FALSE,task);
+ addr += size;
+ db_printf("%-*U", width, value);
+ break;
+ case 'o': /* unsigned octal */
+ value = db_get_task_value(addr,size,FALSE,task);
+ addr += size;
+ db_printf("%-*O", width, value);
+ break;
+ case 'c': /* character */
+ value = db_get_task_value(addr,1,FALSE,task);
+ addr += 1;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ break;
+ case 's': /* null-terminated string */
+ for (;;) {
+ value = db_get_task_value(addr,1,FALSE,task);
+ 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, task);
+ break;
+ case 'I': /* instruction, alternate form */
+ addr = db_disasm(addr, TRUE, task);
+ break;
+ default:
+ break;
+ }
+ if (db_print_position() != 0)
+ db_end_line();
+ break;
+ }
+ }
+ }
+ db_next = addr;
+}
+
+/*
+ * Find out what this address may be
+ */
+/*ARGSUSED*/
+void
+db_whatis_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ /* TODO: Add whatever you can think of */
+
+ int i;
+
+ {
+ /* tasks */
+
+ task_t task;
+ int task_id = 0;
+ processor_set_t pset;
+ thread_t thread;
+ int thread_id;
+ vm_map_entry_t entry;
+
+ queue_iterate(&all_psets, pset, processor_set_t, all_psets)
+ queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
+ if (addr >= (vm_offset_t) task
+ && addr < (vm_offset_t) task + sizeof(*task))
+ db_printf("%3d %0*X %s [%d]\n",
+ task_id,
+ 2*sizeof(vm_offset_t),
+ task,
+ task->name,
+ task->thread_count);
+
+ if (addr >= (vm_offset_t) task->map
+ && addr < (vm_offset_t) task->map + sizeof(*(task->map)))
+ db_printf("$map%d %X for $task%d %s\n",
+ task_id, (vm_offset_t) task->map, task_id, task->name);
+
+ for (entry = vm_map_first_entry(task->map);
+ entry != vm_map_to_entry(task->map);
+ entry = entry->vme_next)
+ if (addr >= (vm_offset_t) entry
+ && addr < (vm_offset_t) entry + sizeof(*entry))
+ db_printf("$map%d %X for $task%d %s entry 0x%X: ",
+ task_id, (vm_offset_t) task->map, task_id, task->name,
+ (vm_offset_t) entry);
+
+ if (pmap_whatis(task->map->pmap, addr))
+ db_printf(" in $task%d %s\n", task_id, task->name);
+
+ if ((task == current_task() || task == kernel_task)
+ && addr >= vm_map_min(task->map)
+ && addr < vm_map_max(task->map)) {
+ db_printf("inside $map%d of $task%d %s\n", task_id, task_id, task->name);
+
+ for (entry = vm_map_first_entry(task->map);
+ entry != vm_map_to_entry(task->map);
+ entry = entry->vme_next)
+ if (addr >= entry->vme_start
+ && addr < entry->vme_end) {
+ db_printf(" entry 0x%X: ", (vm_offset_t) entry);
+ if (entry->is_sub_map)
+ db_printf("submap=0x%X, offset=0x%X\n",
+ (vm_offset_t) entry->object.sub_map,
+ (vm_offset_t) entry->offset);
+ else
+ db_printf("object=0x%X, offset=0x%X\n",
+ (vm_offset_t) entry->object.vm_object,
+ (vm_offset_t) entry->offset);
+ }
+ }
+
+ thread_id = 0;
+ queue_iterate(&task->thread_list, thread, thread_t, thread_list) {
+ if (addr >= (vm_offset_t) thread
+ && addr < (vm_offset_t) thread + sizeof(*thread)) {
+ db_printf("In $task%d %s\n", task_id, task->name);
+ db_print_thread(thread, thread_id, 0);
+ }
+ if (addr >= thread->kernel_stack
+ && addr < thread->kernel_stack + KERNEL_STACK_SIZE) {
+ db_printf("In $task%d %s\n", task_id, task->name);
+ db_printf(" on stack of $thread%d.%d\n", task_id, thread_id);
+ db_print_thread(thread, thread_id, 0);
+ }
+ thread_id++;
+ }
+ task_id++;
+ }
+ }
+
+ pmap_whatis(kernel_pmap, addr);
+
+ {
+ /* runqs */
+ if (addr >= (vm_offset_t) &default_pset.runq
+ && addr < (vm_offset_t) &default_pset.runq + sizeof(default_pset.runq))
+ db_printf("default runq %p\n", &default_pset.runq);
+ for (i = 0; i < smp_get_numcpus(); i++) {
+ processor_t proc = cpu_to_processor(i);
+ if (addr >= (vm_offset_t) &proc->runq
+ && addr < (vm_offset_t) &proc->runq + sizeof(proc->runq))
+ db_printf("Processor #%d runq %p\n", &proc->runq);
+ }
+ }
+
+ {
+ /* stacks */
+ for (i = 0; i < smp_get_numcpus(); i++) {
+ if (addr >= percpu_array[i].active_stack
+ && addr < percpu_array[i].active_stack + KERNEL_STACK_SIZE)
+ db_printf("Processor #%d active stack\n", i);
+ }
+ }
+
+ db_whatis_slab(addr);
+
+ {
+ /* page */
+ phys_addr_t pa;
+ if (DB_VALID_KERN_ADDR(addr))
+ pa = kvtophys(addr);
+ else
+ pa = pmap_extract(current_task()->map->pmap, addr);
+
+ if (pa) {
+ struct vm_page *page = vm_page_lookup_pa(pa);
+ db_printf("phys %llx, page %p\n", (unsigned long long) pa, page);
+ if (page) {
+ const char *types[] = {
+ [VM_PT_FREE] = "free",
+ [VM_PT_RESERVED] = "reserved",
+ [VM_PT_TABLE] = "table",
+ [VM_PT_KERNEL] = "kernel",
+ };
+ db_printf(" %s\n", types[page->type]);
+ db_printf(" free %u\n", page->free);
+ db_printf(" external %u\n", page->external);
+ db_printf(" busy %u\n", page->busy);
+ db_printf(" private %u\n", page->private);
+ db_printf(" object %lx\n", page->object);
+ db_printf(" offset %lx\n", page->offset);
+ db_printf(" wired %u\n", page->wire_count);
+ db_printf(" segment %u\n", page->seg_index);
+ db_printf(" order %u\n", page->order);
+ }
+ }
+ }
+}
+
+/*
+ * Print value.
+ */
+char db_print_format = 'x';
+
+/*ARGSUSED*/
+void
+db_print_cmd(void)
+{
+ db_expr_t value;
+ int t;
+ task_t task = TASK_NULL;
+
+ if ((t = db_read_token()) == tSLASH) {
+ if (db_read_token() != tIDENT) {
+ db_printf("Bad modifier \"/%s\"\n", db_tok_string);
+ db_error(0);
+ /* NOTREACHED */
+ }
+ if (db_tok_string[0])
+ db_print_format = db_tok_string[0];
+ if (db_option(db_tok_string, 't') && db_default_thread)
+ task = db_default_thread->task;
+ } else
+ db_unread_token(t);
+
+ for ( ; ; ) {
+ t = db_read_token();
+ if (t == tSTRING) {
+ db_printf("%s", db_tok_string);
+ continue;
+ }
+ db_unread_token(t);
+ if (!db_expression(&value))
+ break;
+ switch (db_print_format) {
+ case 'a':
+ db_task_printsym((db_addr_t)value, DB_STGY_ANY, task);
+ break;
+ case 'r':
+ db_printf("%*r", 3+2*sizeof(db_expr_t), value);
+ break;
+ case 'x':
+ db_printf("%*x", 2*sizeof(db_expr_t), value);
+ break;
+ case 'z':
+ db_printf("%*z", 2*sizeof(db_expr_t), value);
+ break;
+ case 'd':
+ db_printf("%*d", 3+2*sizeof(db_expr_t), value);
+ break;
+ case 'u':
+ db_printf("%*u", 3+2*sizeof(db_expr_t), value);
+ break;
+ case 'o':
+ db_printf("%o", 4*sizeof(db_expr_t), value);
+ break;
+ case 'c':
+ value = value & 0xFF;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ break;
+ default:
+ db_printf("Unknown format %c\n", db_print_format);
+ db_print_format = 'x';
+ db_error(0);
+ }
+ }
+}
+
+void
+db_print_loc_and_inst(
+ db_addr_t loc,
+ task_t task)
+{
+ db_task_printsym(loc, DB_STGY_PROC, task);
+ db_printf(":\t");
+ (void) db_disasm(loc, TRUE, task);
+}
+
+void
+db_strcpy(char *dst, const char *src)
+{
+ while ((*dst++ = *src++))
+ ;
+}
+
+/*
+ * Search for a value in memory.
+ * Syntax: search [/bhl] addr value [mask] [,count] [thread]
+ */
+void
+db_search_cmd(
+ db_expr_t e,
+ boolean_t b,
+ db_expr_t e2,
+ const char * cc)
+{
+ int t;
+ db_addr_t addr;
+ int size = 0;
+ db_expr_t value;
+ db_expr_t mask;
+ db_addr_t count;
+ thread_t thread;
+ boolean_t thread_flag = FALSE;
+ char *p;
+
+ t = db_read_token();
+ if (t == tSLASH) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ bad_modifier:
+ db_printf("Bad modifier \"/%s\"\n", db_tok_string);
+ db_flush_lex();
+ return;
+ }
+
+ for (p = db_tok_string; *p; p++) {
+ switch(*p) {
+ case 'b':
+ size = sizeof(char);
+ break;
+ case 'h':
+ size = sizeof(short);
+ break;
+ case 'l':
+ size = sizeof(long);
+ break;
+ case 't':
+ thread_flag = TRUE;
+ break;
+ default:
+ goto bad_modifier;
+ }
+ }
+ } else {
+ db_unread_token(t);
+ size = sizeof(int);
+ }
+
+ if (!db_expression((db_expr_t *)&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 = ~0;
+
+ t = db_read_token();
+ if (t == tCOMMA) {
+ if (!db_expression((db_expr_t *)&count)) {
+ db_printf("Count missing\n");
+ db_flush_lex();
+ return;
+ }
+ } else {
+ db_unread_token(t);
+ count = -1; /* effectively forever */
+ }
+ if (thread_flag) {
+ if (!db_get_next_thread(&thread, 0))
+ return;
+ } else
+ thread = THREAD_NULL;
+
+ db_search(addr, size, value, mask, count, db_thread_to_task(thread));
+}
+
+void
+db_search(
+ db_addr_t addr,
+ int size,
+ db_expr_t value,
+ db_expr_t mask,
+ unsigned int count,
+ task_t task)
+{
+ while (count-- != 0) {
+ db_prev = addr;
+ if ((db_get_task_value(addr, size, FALSE, task) & mask) == value)
+ break;
+ addr += size;
+ }
+ db_next = addr;
+}
+
+#define DB_XCDUMP_NC 16
+
+int
+db_xcdump(
+ db_addr_t addr,
+ int size,
+ int count,
+ task_t task)
+{
+ int i, n;
+ db_expr_t value;
+ int bcount;
+ db_addr_t off;
+ char *name;
+ char data[DB_XCDUMP_NC];
+
+ db_find_task_sym_and_offset(addr, &name, &off, task);
+ for (n = count*size; n > 0; n -= bcount) {
+ db_prev = addr;
+ if (off == 0) {
+ db_printf("%s:\n", name);
+ off = -1;
+ }
+ db_printf("%0*X:%s", 2*sizeof(db_addr_t), addr,
+ (size != 1)? " ": "");
+ bcount = ((n > DB_XCDUMP_NC)? DB_XCDUMP_NC: n);
+ if (trunc_page(addr) != trunc_page(addr+bcount-1)) {
+ db_addr_t next_page_addr = trunc_page(addr+bcount-1);
+ if (!DB_CHECK_ACCESS(next_page_addr, sizeof(int), task))
+ bcount = next_page_addr - addr;
+ }
+ if (!db_read_bytes(addr, bcount, data, task)) {
+ db_printf("*\n");
+ continue;
+ }
+ for (i = 0; i < bcount && off != 0; i += size) {
+ if (i % 4 == 0)
+ db_printf(" ");
+ value = db_get_task_value(addr, size, FALSE, task);
+ db_printf("%0*x ", size*2, value);
+ addr += size;
+ db_find_task_sym_and_offset(addr, &name, &off, task);
+ }
+ db_printf("%*s",
+ ((DB_XCDUMP_NC-i)/size)*(size*2+1)+(DB_XCDUMP_NC-i)/4,
+ "");
+ bcount = i;
+ db_printf("%s*", (size != 1)? " ": "");
+ for (i = 0; i < bcount; i++) {
+ value = data[i];
+ db_printf("%c", (value >= ' ' && value <= '~')? value: '.');
+ }
+ db_printf("*\n");
+ }
+ return(addr);
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_examine.h b/ddb/db_examine.h
new file mode 100644
index 0000000..c76fa2a
--- /dev/null
+++ b/ddb/db_examine.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Barry deFreese.
+ */
+
+#ifndef _DDB_DB_EXAMINE_H_
+#define _DDB_DB_EXAMINE_H_
+
+#include <sys/types.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_expr.h>
+
+extern void db_examine_cmd (
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char *modif);
+
+extern void db_strcpy (char *dst, const char *src);
+
+extern void db_examine (
+ db_addr_t addr,
+ const char *fmt,
+ int count,
+ task_t task);
+
+void db_examine_forward(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_examine_backward(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+extern void db_print_loc_and_inst (
+ db_addr_t loc,
+ task_t task);
+
+int db_xcdump(
+ db_addr_t addr,
+ int size,
+ int count,
+ task_t task);
+
+extern void db_whatis_cmd (
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char *modif);
+
+void db_print_cmd(void);
+
+void db_search_cmd(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_search(
+ db_addr_t addr,
+ int size,
+ db_expr_t value,
+ db_expr_t mask,
+ unsigned int count,
+ task_t task);
+
+/* instruction disassembler */
+extern db_addr_t db_disasm(
+ db_addr_t pc,
+ boolean_t altform,
+ task_t task);
+
+#endif /* _DDB_DB_EXAMINE_H_ */
diff --git a/ddb/db_expr.c b/ddb/db_expr.c
new file mode 100644
index 0000000..90edb6f
--- /dev/null
+++ b/ddb/db_expr.c
@@ -0,0 +1,382 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+#include <ddb/db_expr.h>
+#include <ddb/db_output.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_variables.h>
+#include <kern/task.h>
+
+static boolean_t
+db_term(db_expr_t *valuep)
+{
+ int t;
+
+ switch(t = db_read_token()) {
+ case tIDENT:
+ if (!db_value_of_name(db_tok_string, valuep)) {
+ db_printf("Symbol \"%s\" not found\n", db_tok_string);
+ db_error(0);
+ /*NOTREACHED*/
+ }
+ return (TRUE);
+ case tNUMBER:
+ *valuep = db_tok_number;
+ return (TRUE);
+ case tDOT:
+ *valuep = (db_expr_t)db_dot;
+ return (TRUE);
+ case tDOTDOT:
+ *valuep = (db_expr_t)db_prev;
+ return (TRUE);
+ case tPLUS:
+ *valuep = (db_expr_t) db_next;
+ return (TRUE);
+ case tQUOTE:
+ *valuep = (db_expr_t)db_last_addr;
+ return (TRUE);
+ case tDOLLAR:
+ if (!db_get_variable(valuep))
+ return (FALSE);
+ return (TRUE);
+ case tLPAREN:
+ if (!db_expression(valuep)) {
+ db_error("Unmached ()s\n");
+ /*NOTREACHED*/
+ }
+ t = db_read_token();
+ if (t != tRPAREN) {
+ db_printf("')' expected at \"%s...\"\n", db_tok_string);
+ db_error(0);
+ /*NOTREACHED*/
+ }
+ return (TRUE);
+ default:
+ db_unread_token(t);
+ return (FALSE);
+ }
+}
+
+int
+db_size_option(const char *modif, boolean_t *u_option, boolean_t *t_option)
+{
+ const char *p;
+ int size = sizeof(int);
+
+ *u_option = FALSE;
+ *t_option = FALSE;
+ for (p = modif; *p; p++) {
+ switch(*p) {
+ case 'b':
+ size = sizeof(char);
+ break;
+ case 'h':
+ size = sizeof(short);
+ break;
+ case 'l':
+ size = sizeof(long);
+ break;
+ case 'u':
+ *u_option = TRUE;
+ break;
+ case 't':
+ *t_option = TRUE;
+ break;
+ }
+ }
+ return(size);
+}
+
+static boolean_t
+db_unary(db_expr_t *valuep)
+{
+ int t;
+ int size;
+ boolean_t u_opt, t_opt;
+ task_t task;
+ extern task_t db_default_task;
+
+ t = db_read_token();
+ if (t == tMINUS) {
+ if (!db_unary(valuep)) {
+ db_error("Expression syntax error after '-'\n");
+ /*NOTREACHED*/
+ }
+ *valuep = -*valuep;
+ return (TRUE);
+ }
+ if (t == tSTAR) {
+ /* indirection */
+ if (!db_unary(valuep)) {
+ db_error("Expression syntax error after '*'\n");
+ /*NOTREACHED*/
+ }
+ task = TASK_NULL;
+ size = sizeof(db_addr_t);
+ u_opt = FALSE;
+ t = db_read_token();
+ if (t == tIDENT && db_tok_string[0] == ':') {
+ size = db_size_option(&db_tok_string[1], &u_opt, &t_opt);
+ if (t_opt)
+ task = db_default_task;
+ } else
+ db_unread_token(t);
+ *valuep = db_get_task_value((db_addr_t)*valuep, size, !u_opt, task);
+ return (TRUE);
+ }
+ if (t == tEXCL) {
+ if (!db_unary(valuep)) {
+ db_error("Expression syntax error after '!'\n");
+ /*NOTREACHED*/
+ }
+ *valuep = (!(*valuep));
+ return (TRUE);
+ }
+ db_unread_token(t);
+ return (db_term(valuep));
+}
+
+static boolean_t
+db_mult_expr(db_expr_t *valuep)
+{
+ db_expr_t lhs = 0, rhs;
+ int t;
+ char c;
+
+ if (!db_unary(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tSTAR || t == tSLASH || t == tPCT || t == tHASH
+ || t == tBIT_AND) {
+ c = db_tok_string[0];
+ if (!db_term(&rhs)) {
+ db_printf("Expression syntax error after '%c'\n", c);
+ db_error(0);
+ /*NOTREACHED*/
+ }
+ switch(t) {
+ case tSTAR:
+ lhs *= rhs;
+ break;
+ case tBIT_AND:
+ lhs &= rhs;
+ break;
+ default:
+ 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);
+}
+
+static boolean_t
+db_add_expr(db_expr_t *valuep)
+{
+ db_expr_t lhs, rhs;
+ int t;
+ char c;
+
+ if (!db_mult_expr(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tPLUS || t == tMINUS || t == tBIT_OR) {
+ c = db_tok_string[0];
+ if (!db_mult_expr(&rhs)) {
+ db_printf("Expression syntax error after '%c'\n", c);
+ db_error(0);
+ /*NOTREACHED*/
+ }
+ if (t == tPLUS)
+ lhs += rhs;
+ else if (t == tMINUS)
+ lhs -= rhs;
+ else
+ lhs |= rhs;
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+static boolean_t
+db_shift_expr(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_printf("Expression syntax error after \"%s\"\n",
+ (t == tSHIFT_L)? "<<": ">>");
+ db_error(0);
+ /*NOTREACHED*/
+ }
+ if (rhs < 0) {
+ db_error("Negative shift amount\n");
+ /*NOTREACHED*/
+ }
+ if (t == tSHIFT_L)
+ lhs <<= rhs;
+ else {
+ /* Shift right is unsigned */
+ lhs = (natural_t) lhs >> rhs;
+ }
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+static boolean_t
+db_logical_relation_expr(db_expr_t *valuep)
+{
+ db_expr_t lhs, rhs;
+ int t;
+ char op[3];
+
+ if (!db_shift_expr(&lhs))
+ return(FALSE);
+
+ t = db_read_token();
+ while (t == tLOG_EQ || t == tLOG_NOT_EQ
+ || t == tGREATER || t == tGREATER_EQ
+ || t == tLESS || t == tLESS_EQ) {
+ op[0] = db_tok_string[0];
+ op[1] = db_tok_string[1];
+ op[2] = 0;
+ if (!db_shift_expr(&rhs)) {
+ db_printf("Expression syntax error after \"%s\"\n", op);
+ db_error(0);
+ /*NOTREACHED*/
+ }
+ switch(t) {
+ case tLOG_EQ:
+ lhs = (lhs == rhs);
+ break;
+ case tLOG_NOT_EQ:
+ lhs = (lhs != rhs);
+ break;
+ case tGREATER:
+ lhs = (lhs > rhs);
+ break;
+ case tGREATER_EQ:
+ lhs = (lhs >= rhs);
+ break;
+ case tLESS:
+ lhs = (lhs < rhs);
+ break;
+ case tLESS_EQ:
+ lhs = (lhs <= rhs);
+ break;
+ }
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+static boolean_t
+db_logical_and_expr(db_expr_t *valuep)
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_logical_relation_expr(&lhs))
+ return(FALSE);
+
+ t = db_read_token();
+ while (t == tLOG_AND) {
+ if (!db_logical_relation_expr(&rhs)) {
+ db_error("Expression syntax error after \"&&\"\n");
+ /*NOTREACHED*/
+ }
+ lhs = (lhs && rhs);
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+static boolean_t
+db_logical_or_expr(db_expr_t *valuep)
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_logical_and_expr(&lhs))
+ return(FALSE);
+
+ t = db_read_token();
+ while (t == tLOG_OR) {
+ if (!db_logical_and_expr(&rhs)) {
+ db_error("Expression syntax error after \"||\"\n");
+ /*NOTREACHED*/
+ }
+ lhs = (lhs || rhs);
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+int
+db_expression(db_expr_t *valuep)
+{
+ return (db_logical_or_expr(valuep));
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_expr.h b/ddb/db_expr.h
new file mode 100644
index 0000000..9c304e6
--- /dev/null
+++ b/ddb/db_expr.h
@@ -0,0 +1,26 @@
+/*
+ * (c) Copyright 1992, 1993, 1994, 1995 OPEN SOFTWARE FOUNDATION, INC.
+ * ALL RIGHTS RESERVED
+ */
+/*
+ * OSF RI nmk19b2 5/2/95
+ */
+
+#ifndef _DDB_DB_EXPR_H_
+#define _DDB_DB_EXPR_H_
+
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+
+
+/* Prototypes for functions exported by this module.
+ */
+
+int db_size_option(
+ const char *modif,
+ boolean_t *u_option,
+ boolean_t *t_option);
+
+int db_expression(db_expr_t *valuep);
+
+#endif /* !_DDB_DB_EXPR_H_ */
diff --git a/ddb/db_ext_symtab.c b/ddb/db_ext_symtab.c
new file mode 100644
index 0000000..db7bec2
--- /dev/null
+++ b/ddb/db_ext_symtab.c
@@ -0,0 +1,123 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+
+#if MACH_KDB
+
+#if MACH_DEBUG
+
+#include <mach/mach_types.h> /* vm_address_t */
+#include <mach/std_types.h> /* pointer_t */
+#include <mach/vm_param.h>
+#include <vm/vm_map.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_user.h>
+#include <kern/host.h>
+#include <kern/mach_debug.server.h>
+#include <kern/task.h>
+#include <ddb/db_sym.h>
+
+
+
+/*
+ * Loads a symbol table for an external file into the kernel debugger.
+ * The symbol table data is an array of characters. It is assumed that
+ * the caller and the kernel debugger agree on its format.
+ */
+kern_return_t
+host_load_symbol_table(
+ host_t host,
+ task_t task,
+ const char * name,
+ pointer_t symtab,
+ unsigned int symtab_count)
+{
+ kern_return_t result;
+ vm_offset_t symtab_start;
+ vm_offset_t symtab_end;
+ vm_map_t map;
+ vm_map_copy_t symtab_copy_object;
+
+ if (host == HOST_NULL)
+ return (KERN_INVALID_ARGUMENT);
+
+ /*
+ * Copy the symbol table array into the kernel.
+ * We make a copy of the copy object, and clear
+ * the old one, so that returning error will not
+ * deallocate the data twice.
+ */
+ symtab_copy_object = (vm_map_copy_t) symtab;
+ result = vm_map_copyout(
+ kernel_map,
+ &symtab_start,
+ vm_map_copy_copy(symtab_copy_object));
+ if (result != KERN_SUCCESS)
+ return (result);
+
+ symtab_end = symtab_start + symtab_count;
+
+ /*
+ * Add the symbol table.
+ * Do not keep a reference for the task map. XXX
+ */
+ if (task == TASK_NULL)
+ map = VM_MAP_NULL;
+ else
+ map = task->map;
+ if (!X_db_sym_init((char *)symtab_start,
+ (char *)symtab_end,
+ name,
+ (char *)map))
+ {
+ /*
+ * Not enough room for symbol table - failure.
+ */
+ (void) vm_deallocate(kernel_map,
+ symtab_start,
+ symtab_count);
+ return (KERN_FAILURE);
+ }
+
+ /*
+ * Wire down the symbol table
+ */
+ (void) vm_map_pageable(kernel_map,
+ symtab_start,
+ round_page(symtab_end),
+ VM_PROT_READ|VM_PROT_WRITE,
+ TRUE, TRUE);
+
+ /*
+ * Discard the original copy object
+ */
+ vm_map_copy_discard(symtab_copy_object);
+
+ return (KERN_SUCCESS);
+}
+
+#endif /* MACH_DEBUG */
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_input.c b/ddb/db_input.c
new file mode 100644
index 0000000..357474b
--- /dev/null
+++ b/ddb/db_input.c
@@ -0,0 +1,414 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992,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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+#include <device/cons.h>
+#include <ddb/db_command.h>
+#include <ddb/db_input.h>
+#include <ddb/db_output.h>
+
+#ifndef DB_HISTORY_SIZE
+#define DB_HISTORY_SIZE 4000
+#endif /* DB_HISTORY_SIZE */
+
+/*
+ * 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 */
+#if DB_HISTORY_SIZE != 0
+char db_history[DB_HISTORY_SIZE]; /* start of history buffer */
+int db_history_size = DB_HISTORY_SIZE;/* size of history buffer */
+char * db_history_curr = db_history; /* start of current line */
+char * db_history_last = db_history; /* start of last line */
+char * db_history_prev = (char *) 0; /* start of previous line */
+#endif
+
+#define CTRL(c) ((c) & 0x1f)
+#define isspace(c) ((c) == ' ' || (c) == '\t')
+#define BLANK ' '
+#define BACKUP '\b'
+
+static void
+db_putstring(const char *s, int count)
+{
+ while (--count >= 0)
+ cnputc(*s++);
+}
+
+static void
+db_putnchars(int c, int count)
+{
+ while (--count >= 0)
+ cnputc(c);
+}
+
+/*
+ * Delete N characters, forward or backward
+ */
+#define DEL_FWD 0
+#define DEL_BWD 1
+static void
+db_delete(
+ int n,
+ int bwd)
+{
+ 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;
+}
+
+static void
+db_delete_line(void)
+{
+ db_delete(db_le - db_lc, DEL_FWD);
+ db_delete(db_lc - db_lbuf_start, DEL_BWD);
+ db_le = db_lc = db_lbuf_start;
+}
+
+#if DB_HISTORY_SIZE != 0
+#define INC_DB_CURR() \
+ do { \
+ db_history_curr++; \
+ if (db_history_curr > \
+ db_history + db_history_size - 1) \
+ db_history_curr = db_history; \
+ } while (0)
+#define DEC_DB_CURR() \
+ do { \
+ db_history_curr--; \
+ if (db_history_curr < db_history) \
+ db_history_curr = db_history + \
+ db_history_size - 1; \
+ } while (0)
+#endif /* DB_HISTORY_SIZE */
+
+/* returns TRUE at end-of-line */
+static boolean_t
+db_inputchar(int c)
+{
+ static int escaped, csi;
+ int was_escaped = escaped, was_csi = csi;
+ escaped = 0;
+ csi = 0;
+
+ switch (c) {
+ case CTRL('b'):
+ left:
+ /* back up one character */
+ if (db_lc > db_lbuf_start) {
+ cnputc(BACKUP);
+ db_lc--;
+ }
+ break;
+ case CTRL('f'):
+ right:
+ /* 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('u'):
+ /* delete line */
+ db_delete_line();
+ 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;
+#if DB_HISTORY_SIZE != 0
+ case CTRL('p'):
+ up:
+ DEC_DB_CURR();
+ while (db_history_curr != db_history_last) {
+ DEC_DB_CURR();
+ if (*db_history_curr == '\0')
+ break;
+ }
+ db_delete_line();
+ if (db_history_curr == db_history_last) {
+ INC_DB_CURR();
+ db_le = db_lc = db_lbuf_start;
+ } else {
+ char *p;
+ INC_DB_CURR();
+ for (p = db_history_curr, db_le = db_lbuf_start;
+ *p; ) {
+ *db_le++ = *p++;
+ if (p == db_history + db_history_size) {
+ p = db_history;
+ }
+ }
+ db_lc = db_le;
+ }
+ db_putstring(db_lbuf_start, db_le - db_lbuf_start);
+ break;
+ case CTRL('n'):
+ down:
+ while (db_history_curr != db_history_last) {
+ if (*db_history_curr == '\0')
+ break;
+ INC_DB_CURR();
+ }
+ if (db_history_curr != db_history_last) {
+ INC_DB_CURR();
+ db_delete_line();
+ if (db_history_curr != db_history_last) {
+ char *p;
+ for (p = db_history_curr,
+ db_le = db_lbuf_start; *p;) {
+ *db_le++ = *p++;
+ if (p == db_history +
+ db_history_size) {
+ p = db_history;
+ }
+ }
+ db_lc = db_le;
+ }
+ db_putstring(db_lbuf_start, db_le - db_lbuf_start);
+ }
+ break;
+#endif /* DB_HISTORY_SIZE */
+ 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':
+#if DB_HISTORY_SIZE != 0
+ /*
+ * Check whether current line is the same
+ * as previous saved line. If it is, don`t
+ * save it.
+ */
+ if (db_history_curr == db_history_prev) {
+ char *pp, *pc;
+
+ /*
+ * Is it the same?
+ */
+ for (pp = db_history_prev, pc = db_lbuf_start;
+ pc != db_le && *pp; ) {
+ if (*pp != *pc)
+ break;
+ if (++pp == db_history + db_history_size) {
+ pp = db_history;
+ }
+ pc++;
+ }
+ if (!*pp && pc == db_le) {
+ /*
+ * Repeated previous line. Don`t save.
+ */
+ db_history_curr = db_history_last;
+ *db_le++ = c;
+ return (TRUE);
+ }
+ }
+ if (db_le != db_lbuf_start) {
+ char *p;
+ db_history_prev = db_history_last;
+ for (p = db_lbuf_start; p != db_le; p++) {
+ *db_history_last++ = *p;
+ if (db_history_last == db_history +
+ db_history_size) {
+ db_history_last = db_history;
+ }
+ }
+ *db_history_last++ = '\0';
+ }
+ db_history_curr = db_history_last;
+#endif /* DB_HISTORY_SIZE */
+ *db_le++ = c;
+ return (TRUE);
+ case '\033':
+ escaped = 1;
+ break;
+ case '[':
+ if (was_escaped)
+ csi = 1;
+ else
+ goto plain;
+ break;
+ case 'A':
+ if (was_csi)
+ goto up;
+ else
+ goto plain;
+ case 'B':
+ if (was_csi)
+ goto down;
+ else
+ goto plain;
+ case 'C':
+ if (was_csi)
+ goto right;
+ else
+ goto plain;
+ case 'D':
+ if (was_csi)
+ goto left;
+ else
+ goto plain;
+
+ default:
+ plain:
+ if (db_le == db_lbuf_end) {
+ cnputc('\007');
+ }
+ else if (c >= ' ' && c <= '~') {
+ 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 (FALSE);
+}
+
+int
+db_readline(
+ char * lstart,
+ int lsize)
+{
+ db_force_whitespace(); /* synch output position */
+
+ db_lbuf_start = lstart;
+ db_lbuf_end = lstart + lsize - 1;
+ 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(void)
+{
+ 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;
+ }
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_input.h b/ddb/db_input.h
new file mode 100644
index 0000000..352f035
--- /dev/null
+++ b/ddb/db_input.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Barry deFreese.
+ */
+
+#ifndef _DDB_DB_INPUT_H_
+#define _DDB_DB_INPUT_H_
+
+#include <sys/types.h>
+
+/* Needs to be implemented by each arch. */
+extern void kdb_kintr(void);
+
+extern int db_readline (char *lstart, int lsize);
+
+extern void db_check_interrupt(void);
+
+#endif /* _DDB_DB_INPUT_H_ */
diff --git a/ddb/db_lex.c b/ddb/db_lex.c
new file mode 100644
index 0000000..49063e1
--- /dev/null
+++ b/ddb/db_lex.c
@@ -0,0 +1,454 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+/*
+ * Lexical analyzer.
+ */
+#include <string.h>
+#include <machine/db_machdep.h>
+#include <ddb/db_command.h>
+#include <ddb/db_examine.h>
+#include <ddb/db_input.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+
+char db_line[DB_LEX_LINE_SIZE];
+char db_last_line[DB_LEX_LINE_SIZE];
+char *db_lp, *db_endlp;
+char *db_last_lp;
+int db_look_char = 0;
+db_expr_t db_look_token = 0;
+
+int
+db_read_line(const char *repeat_last)
+{
+ int i;
+
+ i = db_readline(db_line, sizeof(db_line));
+ if (i == 0)
+ return (0); /* EOI */
+ if (repeat_last) {
+ if (strncmp(db_line, repeat_last, strlen(repeat_last)) == 0) {
+ db_strcpy(db_line, db_last_line);
+ db_printf("%s", db_line);
+ i = strlen(db_line);
+ } else if (db_line[0] != '\n' && db_line[0] != 0)
+ db_strcpy(db_last_line, db_line);
+ }
+ db_lp = db_line;
+ db_endlp = db_lp + i;
+ db_last_lp = db_lp;
+ db_look_char = 0;
+ db_look_token = 0;
+ return (i);
+}
+
+void
+db_flush_line(void)
+{
+ db_lp = db_line;
+ db_last_lp = db_lp;
+ db_endlp = db_line;
+}
+
+void
+db_switch_input(
+ char *buffer,
+ int size)
+{
+ db_lp = buffer;
+ db_last_lp = db_lp;
+ db_endlp = buffer + size;
+ db_look_char = 0;
+ db_look_token = 0;
+}
+
+void
+db_save_lex_context(struct db_lex_context *lp)
+{
+ lp->l_ptr = db_lp;
+ lp->l_eptr = db_endlp;
+ lp->l_char = db_look_char;
+ lp->l_token = db_look_token;
+}
+
+void
+db_restore_lex_context(const struct db_lex_context *lp)
+{
+ db_lp = lp->l_ptr;
+ db_last_lp = db_lp;
+ db_endlp = lp->l_eptr;
+ db_look_char = lp->l_char;
+ db_look_token = lp->l_token;
+}
+
+int
+db_read_char(void)
+{
+ 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(int c)
+{
+ db_look_char = c;
+}
+
+void
+db_unread_token(int t)
+{
+ db_look_token = t;
+}
+
+int
+db_read_token(void)
+{
+ int t;
+
+ if (db_look_token) {
+ t = db_look_token;
+ db_look_token = 0;
+ }
+ else {
+ db_last_lp = db_lp;
+ if (db_look_char)
+ db_last_lp--;
+ t = db_lex();
+ }
+ return (t);
+}
+
+db_expr_t db_tok_number;
+char db_tok_string[TOK_STRING_SIZE];
+db_expr_t db_radix = 16;
+
+void
+db_flush_lex(void)
+{
+ db_flush_line();
+ db_look_char = 0;
+ db_look_token = 0;
+}
+
+#define DB_DISP_SKIP 40 /* number of chars to display skip */
+
+void
+db_skip_to_eol(void)
+{
+ int skip;
+ int t;
+ int n;
+ char *p;
+
+ t = db_read_token();
+ p = db_last_lp;
+ for (skip = 0; t != tEOL && t != tSEMI_COLON && t != tEOF; skip++)
+ t = db_read_token();
+ if (t == tSEMI_COLON)
+ db_unread_token(t);
+ if (skip != 0) {
+ while (p < db_last_lp && (*p == ' ' || *p == '\t'))
+ p++;
+ db_printf("Warning: Skipped input data \"");
+ for (n = 0; n < DB_DISP_SKIP && p < db_last_lp; n++)
+ db_printf("%c", *p++);
+ if (n >= DB_DISP_SKIP)
+ db_printf("....");
+ db_printf("\"\n");
+ }
+}
+
+int
+db_lex(void)
+{
+ char *cp;
+ int c;
+
+ c = db_read_char();
+ while (c <= ' ' || c > '~') {
+ if (c == '\n' || c == -1)
+ return (tEOL);
+ c = db_read_char();
+ }
+
+ cp = db_tok_string;
+ *cp++ = c;
+
+ 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 {
+ cp--;
+ r = db_radix;
+ db_unread_char(c);
+ }
+ c = db_read_char();
+ *cp++ = c;
+ }
+ 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
+ digit = c - 'A' + 10;
+ }
+ else
+ break;
+ db_tok_number = db_tok_number * r + digit;
+ c = db_read_char();
+ if (cp < &db_tok_string[sizeof(db_tok_string)-1])
+ *cp++ = c;
+ }
+ cp[-1] = 0;
+ if ((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c == '_'))
+ {
+ db_printf("Bad character '%c' after number %s\n",
+ c, db_tok_string);
+ db_error(0);
+ db_flush_lex();
+ return (tEOF);
+ }
+ db_unread_char(c);
+ return (tNUMBER);
+ }
+ if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ c == '_' || c == '\\' || c == ':')
+ {
+ /* identifier */
+ if (c == '\\') {
+ c = db_read_char();
+ if (c == '\n' || c == -1)
+ db_error("Bad '\\' at the end of line\n");
+ cp[-1] = c;
+ }
+ while (1) {
+ c = db_read_char();
+ if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_' || c == '\\' || c == ':' || c == '.')
+ {
+ if (c == '\\') {
+ c = db_read_char();
+ if (c == '\n' || c == -1)
+ db_error("Bad '\\' at the end of line\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);
+ }
+
+ *cp = 0;
+ switch (c) {
+ case '+':
+ return (tPLUS);
+ case '-':
+ return (tMINUS);
+ case '.':
+ c = db_read_char();
+ if (c == '.') {
+ *cp++ = c;
+ *cp = 0;
+ return (tDOTDOT);
+ }
+ db_unread_char(c);
+ return (tDOT);
+ case '*':
+ return (tSTAR);
+ case '/':
+ return (tSLASH);
+ case '=':
+ c = db_read_char();
+ if (c == '=') {
+ *cp++ = c;
+ *cp = 0;
+ return(tLOG_EQ);
+ }
+ db_unread_char(c);
+ return (tEQ);
+ case '%':
+ return (tPCT);
+ case '#':
+ return (tHASH);
+ case '(':
+ return (tLPAREN);
+ case ')':
+ return (tRPAREN);
+ case ',':
+ return (tCOMMA);
+ case '\'':
+ return (tQUOTE);
+ case '"':
+ /* string */
+ cp = db_tok_string;
+ c = db_read_char();
+ while (c != '"' && c > 0 && c != '\n') {
+ if (cp >= &db_tok_string[sizeof(db_tok_string)-1]) {
+ db_error("Too long string\n");
+ db_flush_lex();
+ return (tEOF);
+ }
+ if (c == '\\') {
+ c = db_read_char();
+ switch(c) {
+ case 'n':
+ c = '\n'; break;
+ case 't':
+ c = '\t'; break;
+ case '\\':
+ case '"':
+ break;
+ default:
+ db_printf("Bad escape sequence '\\%c'\n", c);
+ db_error(0);
+ db_flush_lex();
+ return (tEOF);
+ }
+ }
+ *cp++ = c;
+ c = db_read_char();
+ }
+ *cp = 0;
+ if (c != '"') {
+ db_error("Non terminated string constant\n");
+ db_flush_lex();
+ return (tEOF);
+ }
+ return (tSTRING);
+ case '$':
+ return (tDOLLAR);
+ case '!':
+ c = db_read_char();
+ if (c == '=') {
+ *cp++ = c;
+ *cp = 0;
+ return(tLOG_NOT_EQ);
+ }
+ db_unread_char(c);
+ return (tEXCL);
+ case '&':
+ c = db_read_char();
+ if (c == '&') {
+ *cp++ = c;
+ *cp = 0;
+ return(tLOG_AND);
+ }
+ db_unread_char(c);
+ return(tBIT_AND);
+ case '|':
+ c = db_read_char();
+ if (c == '|') {
+ *cp++ = c;
+ *cp = 0;
+ return(tLOG_OR);
+ }
+ db_unread_char(c);
+ return(tBIT_OR);
+ case '<':
+ c = db_read_char();
+ *cp++ = c;
+ *cp = 0;
+ if (c == '<')
+ return (tSHIFT_L);
+ if (c == '=')
+ return (tLESS_EQ);
+ cp[-1] = 0;
+ db_unread_char(c);
+ return(tLESS);
+ break;
+ case '>':
+ c = db_read_char();
+ *cp++ = c;
+ *cp = 0;
+ if (c == '>')
+ return (tSHIFT_R);
+ if (c == '=')
+ return (tGREATER_EQ);
+ cp[-1] = 0;
+ db_unread_char(c);
+ return (tGREATER);
+ break;
+ case ';':
+ return (tSEMI_COLON);
+ case '?':
+ return (tQUESTION);
+ case -1:
+ db_strcpy(db_tok_string, "<EOL>");
+ return (tEOF);
+ }
+ db_printf("Bad character '%c'\n", c);
+ db_flush_lex();
+ return (tEOF);
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_lex.h b/ddb/db_lex.h
new file mode 100644
index 0000000..f7677df
--- /dev/null
+++ b/ddb/db_lex.h
@@ -0,0 +1,99 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Lexical analyzer.
+ */
+
+#ifndef _DDB_DB_LEX_H_
+#define _DDB_DB_LEX_H_
+
+#define TOK_STRING_SIZE 64
+#define DB_LEX_LINE_SIZE 256
+
+struct db_lex_context {
+ int l_char; /* peek char */
+ int l_token; /* peek token */
+ char *l_ptr; /* line pointer */
+ char *l_eptr; /* line end pointer */
+};
+
+extern int db_lex(void);
+extern int db_read_line(const char *rep_str);
+extern void db_flush_line(void);
+extern int db_read_char(void);
+extern void db_unread_char(int c);
+extern int db_read_token(void);
+extern void db_unread_token(int t);
+extern void db_flush_lex(void);
+extern void db_switch_input(char *, int);
+extern void db_save_lex_context(struct db_lex_context *);
+extern void db_restore_lex_context(const struct db_lex_context *);
+extern void db_skip_to_eol(void);
+
+extern db_expr_t db_tok_number;
+extern char db_tok_string[TOK_STRING_SIZE];
+extern db_expr_t 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 tQUOTE 15
+#define tDOLLAR 16
+#define tEXCL 17
+#define tSHIFT_L 18
+#define tSHIFT_R 19
+#define tDOTDOT 20
+#define tSEMI_COLON 21
+#define tLOG_EQ 22
+#define tLOG_NOT_EQ 23
+#define tLESS 24
+#define tLESS_EQ 25
+#define tGREATER 26
+#define tGREATER_EQ 27
+#define tBIT_AND 28
+#define tBIT_OR 29
+#define tLOG_AND 30
+#define tLOG_OR 31
+#define tSTRING 32
+#define tQUESTION 33
+
+#endif /* _DDB_DB_LEX_H_ */
diff --git a/ddb/db_macro.c b/ddb/db_macro.c
new file mode 100644
index 0000000..63159d7
--- /dev/null
+++ b/ddb/db_macro.c
@@ -0,0 +1,197 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+
+#if MACH_KDB
+
+#include <string.h>
+#include <kern/thread.h>
+
+#include <machine/db_machdep.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_command.h>
+#include <ddb/db_examine.h>
+#include <ddb/db_expr.h>
+#include <ddb/db_macro.h>
+#include <ddb/db_output.h>
+
+
+/*
+ * debugger macro support
+ */
+
+#define DB_MACRO_LEVEL 5 /* max macro nesting */
+#define DB_NARGS 10 /* max args */
+#define DB_NUSER_MACRO 10 /* max user macros */
+
+int db_macro_free = DB_NUSER_MACRO;
+struct db_user_macro {
+ char m_name[TOK_STRING_SIZE];
+ char m_lbuf[DB_LEX_LINE_SIZE];
+ int m_size;
+} db_user_macro[DB_NUSER_MACRO];
+
+int db_macro_level = 0;
+db_expr_t db_macro_args[DB_MACRO_LEVEL][DB_NARGS];
+
+static struct db_user_macro *
+db_lookup_macro(const char *name)
+{
+ struct db_user_macro *mp;
+
+ for (mp = db_user_macro; mp < &db_user_macro[DB_NUSER_MACRO]; mp++) {
+ if (mp->m_name[0] == 0)
+ continue;
+ if (strcmp(mp->m_name, name) == 0)
+ return(mp);
+ }
+ return(0);
+}
+
+void
+db_def_macro_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ char *p;
+ int c;
+ struct db_user_macro *mp, *ep;
+
+ if (db_read_token() != tIDENT) {
+ db_printf("Bad macro name \"%s\"\n", db_tok_string);
+ db_error(0);
+ /* NOTREACHED */
+ }
+ if ((mp = db_lookup_macro(db_tok_string)) == 0) {
+ if (db_macro_free <= 0)
+ db_error("Too many macros\n");
+ /* NOTREACHED */
+ ep = &db_user_macro[DB_NUSER_MACRO];
+ for (mp = db_user_macro; mp < ep && mp->m_name[0]; mp++);
+ if (mp >= ep)
+ db_error("ddb: internal error(macro)\n");
+ /* NOTREACHED */
+ db_macro_free--;
+ db_strcpy(mp->m_name, db_tok_string);
+ }
+ for (c = db_read_char(); c == ' ' || c == '\t'; c = db_read_char());
+ for (p = mp->m_lbuf; c > 0; c = db_read_char())
+ *p++ = c;
+ *p = 0;
+ mp->m_size = p - mp->m_lbuf;
+}
+
+void
+db_del_macro_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ struct db_user_macro *mp;
+
+ if (db_read_token() != tIDENT
+ || (mp = db_lookup_macro(db_tok_string)) == 0) {
+ db_printf("No such macro \"%s\"\n", db_tok_string);
+ db_error(0);
+ /* NOTREACHED */
+ } else {
+ mp->m_name[0] = 0;
+ db_macro_free++;
+ }
+}
+
+void
+db_show_macro(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ struct db_user_macro *mp;
+ int t;
+ char *name = 0;
+
+ if ((t = db_read_token()) == tIDENT)
+ name = db_tok_string;
+ else
+ db_unread_token(t);
+ for (mp = db_user_macro; mp < &db_user_macro[DB_NUSER_MACRO]; mp++) {
+ if (mp->m_name[0] == 0)
+ continue;
+ if (name && strcmp(mp->m_name, name))
+ continue;
+ db_printf("%s: %s", mp->m_name, mp->m_lbuf);
+ }
+}
+
+int
+db_exec_macro(const char *name)
+{
+ struct db_user_macro *mp;
+ int n;
+
+ if ((mp = db_lookup_macro(name)) == 0)
+ return(-1);
+ if (db_macro_level+1 >= DB_MACRO_LEVEL) {
+ db_macro_level = 0;
+ db_error("Too many macro nest\n");
+ /* NOTREACHED */
+ }
+ for (n = 0;
+ n < DB_NARGS &&
+ db_expression(&db_macro_args[db_macro_level+1][n]);
+ n++);
+ while (n < DB_NARGS)
+ db_macro_args[db_macro_level+1][n++] = 0;
+ db_macro_level++;
+ db_exec_cmd_nest(mp->m_lbuf, mp->m_size);
+ db_macro_level--;
+ return(0);
+}
+
+void
+/* ARGSUSED */
+db_arg_variable(
+ struct db_variable *vp,
+ db_expr_t *valuep,
+ int flag,
+ db_var_aux_param_t ap)
+{
+ if (ap->level != 1 || ap->suffix[0] < 1 || ap->suffix[0] > DB_NARGS) {
+ db_error("Bad $arg variable\n");
+ /* NOTREACHED */
+ }
+ if (flag == DB_VAR_GET)
+ *valuep = db_macro_args[db_macro_level][ap->suffix[0]-1];
+ else
+ db_macro_args[db_macro_level][ap->suffix[0]-1] = *valuep;
+ return;
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_macro.h b/ddb/db_macro.h
new file mode 100644
index 0000000..9188247
--- /dev/null
+++ b/ddb/db_macro.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Barry deFreese.
+ */
+
+#ifndef _DDB_DB_MACRO_H_
+#define _DDB_DB_MACRO_H_
+
+#include <sys/types.h>
+#include <ddb/db_variables.h>
+
+extern void db_def_macro_cmd (
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif);
+
+extern void db_del_macro_cmd (
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif);
+
+extern void db_show_macro (
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif);
+
+extern int db_exec_macro (const char *name);
+
+extern void db_arg_variable (
+ struct db_variable *vp,
+ db_expr_t *valuep,
+ int flag,
+ db_var_aux_param_t ap);
+
+#endif /* _DDB_DB_MACRO_H_ */
diff --git a/ddb/db_mp.c b/ddb/db_mp.c
new file mode 100644
index 0000000..5cf800c
--- /dev/null
+++ b/ddb/db_mp.c
@@ -0,0 +1,339 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+
+#if MACH_KDB
+
+#if NCPUS > 1
+
+#include <mach/boolean.h>
+#include <mach/machine.h>
+
+#include <kern/cpu_number.h>
+#include <kern/lock.h>
+
+#include <machine/db_machdep.h>
+#include <machine/db_interface.h>
+
+#include <ddb/db_command.h>
+#include <ddb/db_input.h>
+#include <ddb/db_run.h>
+#include <ddb/db_mp.h>
+#include <ddb/db_output.h>
+
+/*
+ * Routines to interlock access to the kernel debugger on
+ * multiprocessors.
+ */
+
+int db_spl;
+def_simple_lock_irq_data(static,db_lock) /* lock to enter debugger */
+volatile int db_cpu = -1; /* CPU currently in debugger */
+ /* -1 if none */
+int db_active[NCPUS] = { 0 }; /* count recursive entries
+ into debugger */
+int db_slave[NCPUS] = { 0 }; /* nonzero if cpu interrupted
+ by another cpu in debugger */
+
+boolean_t db_enter_debug = FALSE;
+
+/*
+ * Called when entering kernel debugger.
+ * Takes db lock. If we were called remotely (slave state) we just
+ * wait for db_cpu to be equal to cpu_number(). Otherwise enter debugger
+ * if not active on another cpu
+ */
+
+boolean_t
+db_enter(void)
+{
+ int mycpu = cpu_number();
+
+ /*
+ * Count recursive entries to debugger.
+ */
+ db_active[mycpu]++;
+
+ /*
+ * Wait for other CPUS to leave debugger.
+ */
+ db_spl = lock_db();
+
+ if (db_enter_debug)
+ db_printf(
+ "db_enter: cpu %d[%d], master %d, db_cpu %d, run mode %d\n",
+ mycpu, db_slave[mycpu], master_cpu, db_cpu, db_run_mode);
+
+ /*
+ * If no CPU in debugger, and I am not being stopped,
+ * enter the debugger.
+ */
+ if (db_cpu == -1 && !db_slave[mycpu]) {
+ remote_db(); /* stop other cpus */
+ db_cpu = mycpu;
+ return TRUE;
+ }
+ /*
+ * If I am already in the debugger (recursive entry
+ * or returning from single step), enter debugger.
+ */
+ else if (db_cpu == mycpu)
+ return TRUE;
+ /*
+ * Otherwise, cannot enter debugger.
+ */
+ else
+ return FALSE;
+}
+
+/*
+ * Leave debugger.
+ */
+void
+db_leave(void)
+{
+ int mycpu = cpu_number();
+
+ /*
+ * If continuing, give up debugger
+ */
+ if (db_run_mode == STEP_CONTINUE)
+ db_cpu = -1;
+
+ /*
+ * If I am a slave, drop my slave count.
+ */
+ if (db_slave[mycpu])
+ db_slave[mycpu]--;
+ if (db_enter_debug)
+ db_printf("db_leave: cpu %d[%d], db_cpu %d, run_mode %d\n",
+ mycpu, db_slave[mycpu], db_cpu, db_run_mode);
+ /*
+ * Unlock debugger.
+ */
+ unlock_db(db_spl);
+
+ /*
+ * Drop recursive entry count.
+ */
+ db_active[mycpu]--;
+}
+
+
+/*
+ * invoke kernel debugger on slave processors
+ */
+
+void
+remote_db(void) {
+ int my_cpu = cpu_number();
+ int i;
+
+ for (i = 0; i < NCPUS; i++) {
+ if (i != my_cpu &&
+ machine_slot[i].is_cpu &&
+ machine_slot[i].running)
+ {
+ cpu_interrupt_to_db(i);
+ }
+ }
+}
+
+/*
+ * Save and restore DB global registers.
+ *
+ * DB_SAVE_CTXT must be at the start of a block, and
+ * DB_RESTORE_CTXT must be in the same block.
+ */
+
+#ifdef __STDC__
+#define DB_SAVE(type, name) extern type name; type name##_save = name
+#define DB_RESTORE(name) name = name##_save
+#else /* __STDC__ */
+#define DB_SAVE(type, name) extern type name; type name/**/_save = name
+#define DB_RESTORE(name) name = name/**/_save
+#endif /* __STDC__ */
+
+#define DB_SAVE_CTXT() \
+ DB_SAVE(int, db_run_mode); \
+ DB_SAVE(boolean_t, db_sstep_print); \
+ DB_SAVE(int, db_loop_count); \
+ DB_SAVE(int, db_call_depth); \
+ DB_SAVE(int, db_inst_count); \
+ DB_SAVE(int, db_last_inst_count); \
+ DB_SAVE(int, db_load_count); \
+ DB_SAVE(int, db_store_count); \
+ DB_SAVE(boolean_t, db_cmd_loop_done); \
+ DB_SAVE(jmp_buf_t *, db_recover); \
+ DB_SAVE(db_addr_t, db_dot); \
+ DB_SAVE(db_addr_t, db_last_addr); \
+ DB_SAVE(db_addr_t, db_prev); \
+ DB_SAVE(db_addr_t, db_next); \
+ SAVE_DDB_REGS
+
+#define DB_RESTORE_CTXT() \
+ DB_RESTORE(db_run_mode); \
+ DB_RESTORE(db_sstep_print); \
+ DB_RESTORE(db_loop_count); \
+ DB_RESTORE(db_call_depth); \
+ DB_RESTORE(db_inst_count); \
+ DB_RESTORE(db_last_inst_count); \
+ DB_RESTORE(db_load_count); \
+ DB_RESTORE(db_store_count); \
+ DB_RESTORE(db_cmd_loop_done); \
+ DB_RESTORE(db_recover); \
+ DB_RESTORE(db_dot); \
+ DB_RESTORE(db_last_addr); \
+ DB_RESTORE(db_prev); \
+ DB_RESTORE(db_next); \
+ RESTORE_DDB_REGS
+
+/*
+ * switch to another cpu
+ */
+void
+db_on(int cpu)
+{
+ /*
+ * Save ddb global variables
+ */
+ DB_SAVE_CTXT();
+
+ /*
+ * Don`t do if bad CPU number.
+ * CPU must also be spinning in db_entry.
+ */
+ if (cpu < 0 || cpu >= NCPUS || !db_active[cpu])
+ return;
+
+ /*
+ * Give debugger to that CPU
+ */
+ db_cpu = cpu;
+ unlock_db(db_spl);
+
+ /*
+ * Wait for it to come back again
+ */
+ db_spl = lock_db();
+
+ /*
+ * Restore ddb globals
+ */
+ DB_RESTORE_CTXT();
+
+ if (db_cpu == -1) /* someone continued */
+ db_continue_cmd(0, 0, 0, "");
+}
+
+/*
+ * Called by interprocessor interrupt when one CPU is
+ * in kernel debugger and wants to stop other CPUs
+ */
+void
+remote_db_enter(void)
+{
+ db_slave[cpu_number()]++;
+ kdb_kintr();
+}
+
+/*
+ * Acquire kernel debugger.
+ * Conditional code for forwarding characters from slave to console
+ * if console on master only.
+ */
+
+/*
+ * As long as db_cpu is not -1 or cpu_number(), we know that debugger
+ * is active on another cpu.
+ */
+int
+lock_db(void)
+{
+ int my_cpu = cpu_number();
+ int s;
+
+ for (;;) {
+#if CONSOLE_ON_MASTER
+ if (my_cpu == master_cpu) {
+ db_console();
+ }
+#endif /* CONSOLE_ON_MASTER */
+ if (db_cpu != -1 && db_cpu != my_cpu)
+ continue;
+
+#if CONSOLE_ON_MASTER
+ if (my_cpu == master_cpu) {
+ if (!(s = simple_lock_try_irq(&db_lock)))
+ continue;
+ }
+ else {
+ s = simple_lock_irq(&db_lock);
+ }
+#else /* CONSOLE_ON_MASTER */
+ s = simple_lock_irq(&db_lock);
+#endif /* CONSOLE_ON_MASTER */
+ if (db_cpu == -1 || db_cpu == my_cpu)
+ break;
+ unlock_db(s);
+ }
+
+ return s;
+}
+
+void
+unlock_db(int s)
+{
+ simple_unlock_irq(s, &db_lock);
+}
+
+#if CONSOLE_ON_MASTER
+void
+db_console(void)
+{
+ if (i_bit(CBUS_PUT_CHAR, my_word)) {
+ volatile u_char c = cbus_ochar;
+ i_bit_clear(CBUS_PUT_CHAR, my_word);
+ cnputc(c);
+ } else if (i_bit(CBUS_GET_CHAR, my_word)) {
+ if (cbus_wait_char)
+ cbus_ichar = cngetc();
+ else
+ cbus_ichar = cnmaygetc();
+ i_bit_clear(CBUS_GET_CHAR, my_word);
+#ifndef notdef
+ } else if (!cnmaygetc()) {
+#else /* notdef */
+ } else if (com_is_char() && !com_getc(TRUE)) {
+#endif /* notdef */
+ simple_unlock(&db_lock);
+ db_cpu = my_cpu;
+ }
+}
+#endif /* CONSOLE_ON_MASTER */
+
+#endif /* NCPUS > 1 */
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_mp.h b/ddb/db_mp.h
new file mode 100644
index 0000000..8a0a9e1
--- /dev/null
+++ b/ddb/db_mp.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _DDB_DB_MP_H_
+#define _DDB_DB_MP_H_
+
+void remote_db(void);
+int lock_db(void);
+void unlock_db(int);
+void db_on(int i);
+
+#if CONSOLE_ON_MASTER
+void db_console(void);
+#endif /* CONSOLE_ON_MASTER */
+
+boolean_t db_enter(void);
+void remote_db_enter(void);
+void db_leave(void);
+
+#endif /* _DDB_DB_MP_H_ */
diff --git a/ddb/db_output.c b/ddb/db_output.c
new file mode 100644
index 0000000..9a76f54
--- /dev/null
+++ b/ddb/db_output.c
@@ -0,0 +1,217 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+/*
+ * Printf and character output for debugger.
+ */
+
+#include <kern/printf.h>
+#include <stdarg.h>
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+#include <device/cons.h>
+#include <ddb/db_command.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+#include <ddb/db_input.h>
+
+/*
+ * Character output - tracks position in line.
+ * To do this correctly, we should know how wide
+ * the output device is - then we could zero
+ * the line position when the output device wraps
+ * around to the start of the next line.
+ *
+ * Instead, we count the number of spaces printed
+ * since the last printing character so that we
+ * don't print trailing spaces. This avoids most
+ * of the wraparounds.
+ */
+
+#ifndef DB_MAX_LINE
+#define DB_MAX_LINE 24 /* maximum line */
+#define DB_MAX_WIDTH 80 /* maximum width */
+#endif /* DB_MAX_LINE */
+
+#define DB_MIN_MAX_WIDTH 20 /* minimum max width */
+#define DB_MIN_MAX_LINE 3 /* minimum max line */
+#define CTRL(c) ((c) & 0xff)
+
+int db_output_position = 0; /* output column */
+int db_output_line = 0; /* output line number */
+int db_last_non_space = 0; /* last non-space character */
+int db_tab_stop_width = 8; /* how wide are tab stops? */
+#define NEXT_TAB(i) \
+ ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
+int db_max_line = DB_MAX_LINE; /* output max lines */
+int db_max_width = DB_MAX_WIDTH; /* output line width */
+
+/*
+ * Force pending whitespace.
+ */
+void
+db_force_whitespace(void)
+{
+ 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;
+}
+
+static void
+db_more(void)
+{
+ char *p;
+ boolean_t quit_output = FALSE;
+
+ for (p = "--db_more--"; *p; p++)
+ cnputc(*p);
+ switch(cngetc()) {
+ case ' ':
+ db_output_line = 0;
+ break;
+ case 'q':
+ case CTRL('c'):
+ db_output_line = 0;
+ quit_output = TRUE;
+ break;
+ default:
+ db_output_line--;
+ break;
+ }
+ p = "\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b";
+ while (*p)
+ cnputc(*p++);
+ if (quit_output) {
+ db_error(0);
+ /* NOTREACHED */
+ }
+}
+
+/*
+ * Output character. Buffer whitespace.
+ */
+void
+db_putchar(int c) /* character to output */
+{
+ if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1)
+ db_more();
+ if (c > ' ' && c <= '~') {
+ /*
+ * Printing character.
+ * If we have spaces to print, print them first.
+ * Use tabs if possible.
+ */
+ db_force_whitespace();
+ cnputc(c);
+ db_output_position++;
+ if (db_max_width >= DB_MIN_MAX_WIDTH
+ && db_output_position >= db_max_width) {
+ /* auto new line */
+ cnputc('\n');
+ db_output_position = 0;
+ db_last_non_space = 0;
+ db_output_line++;
+ }
+ db_last_non_space = db_output_position;
+ }
+ else if (c == '\n') {
+ /* Return */
+ cnputc(c);
+ db_output_position = 0;
+ db_last_non_space = 0;
+ db_output_line++;
+ db_check_interrupt();
+ }
+ else if (c == '\t') {
+ /* assume tabs every 8 positions */
+ db_output_position = NEXT_TAB(db_output_position);
+ }
+ else if (c == ' ') {
+ /* space */
+ db_output_position++;
+ }
+ else if (c == '\007') {
+ /* bell */
+ cnputc(c);
+ }
+ /* other characters are assumed non-printing */
+}
+
+static void
+db_id_putc(char c, vm_offset_t dummy)
+{
+ db_putchar(c);
+}
+
+/*
+ * Return output position
+ */
+int __attribute__ ((pure))
+db_print_position(void)
+{
+ return (db_output_position);
+}
+
+/*
+ * End line if too long.
+ */
+void db_end_line(void)
+{
+ if (db_output_position >= db_max_width-1)
+ db_printf("\n");
+}
+
+/*VARARGS1*/
+int
+db_printf(const char *fmt, ...)
+{
+ va_list listp;
+
+ va_start(listp, fmt);
+ _doprnt(fmt, listp, db_id_putc, db_radix, 0);
+ va_end(listp);
+ return 0;
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_output.h b/ddb/db_output.h
new file mode 100644
index 0000000..7920179
--- /dev/null
+++ b/ddb/db_output.h
@@ -0,0 +1,46 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 8/90
+ */
+
+/*
+ * Printing routines for kernel debugger.
+ */
+
+#ifndef _DDB_DB_OUTPUT_H_
+#define _DDB_DB_OUTPUT_H_
+
+extern void db_force_whitespace(void);
+extern int db_print_position(void) __attribute__ ((pure));
+extern void db_end_line(void);
+extern int db_printf(const char *fmt, ...);
+/* alternate name */
+#define kdbprintf db_printf
+extern void db_putchar(int c);
+
+#endif /* _DDB_DB_OUTPUT_H_ */
diff --git a/ddb/db_print.c b/ddb/db_print.c
new file mode 100644
index 0000000..f08dd6c
--- /dev/null
+++ b/ddb/db_print.c
@@ -0,0 +1,573 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+/*
+ * Miscellaneous printing.
+ */
+#include <string.h>
+#include <mach/policy.h>
+#include <mach/port.h>
+#include <kern/task.h>
+#include <kern/thread.h>
+#include <kern/queue.h>
+#include <kern/sched.h>
+#include <kern/processor.h>
+#include <kern/smp.h>
+#include <ipc/ipc_port.h>
+#include <ipc/ipc_space.h>
+
+#include <machine/db_interface.h>
+#include <machine/db_machdep.h>
+#include <machine/thread.h>
+
+#include <ddb/db_command.h>
+#include <ddb/db_output.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_print.h>
+
+extern unsigned long db_maxoff;
+
+/* ARGSUSED */
+void
+db_show_regs(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ char *modif)
+{
+ struct db_variable *regp;
+ db_expr_t value;
+ db_addr_t offset;
+ char * name;
+ int i;
+ struct db_var_aux_param aux_param;
+ task_t task = TASK_NULL;
+
+ aux_param.modif = modif;
+ aux_param.thread = THREAD_NULL;
+ if (db_option(modif, 't')) {
+ if (have_addr) {
+ if (!db_check_thread_address_valid((thread_t)addr))
+ return;
+ aux_param.thread = (thread_t)addr;
+ } else
+ aux_param.thread = db_default_thread;
+ if (aux_param.thread != THREAD_NULL)
+ task = aux_param.thread->task;
+ }
+ for (regp = db_regs; regp < db_eregs; regp++) {
+ if (regp->max_level > 1) {
+ db_printf("bad multi-suffixed register %s\n", regp->name);
+ continue;
+ }
+ aux_param.level = regp->max_level;
+ for (i = regp->low; i <= regp->high; i++) {
+ aux_param.suffix[0] = i;
+ db_read_write_variable(regp, &value, DB_VAR_GET, &aux_param);
+ if (regp->max_level > 0)
+ db_printf("%s%d%*s", regp->name, i,
+ 12-strlen(regp->name)-((i<10)?1:2), "");
+ else
+ db_printf("%-12s", regp->name);
+ db_printf("%#*N", 2+2*sizeof(vm_offset_t), value);
+ db_find_xtrn_task_sym_and_offset((db_addr_t)value, &name,
+ &offset, task);
+ if (name != 0 && offset <= db_maxoff && offset != value) {
+ db_printf("\t%s", name);
+ if (offset != 0)
+ db_printf("+%#r", offset);
+ }
+ db_printf("\n");
+ }
+ }
+}
+
+#define OPTION_LONG 0x001 /* long print option */
+#define OPTION_USER 0x002 /* print ps-like stuff */
+#define OPTION_SCHED 0x004 /* print scheduling info */
+#define OPTION_INDENT 0x100 /* print with indent */
+#define OPTION_THREAD_TITLE 0x200 /* print thread title */
+#define OPTION_TASK_TITLE 0x400 /* print thread title */
+
+#ifndef DB_TASK_NAME
+#define DB_TASK_NAME(task) /* no task name */
+#define DB_TASK_NAME_TITLE "" /* no task name */
+#endif /* DB_TASK_NAME */
+
+#ifndef db_thread_fp_used
+#define db_thread_fp_used(thread) FALSE
+#endif
+
+static char *
+db_thread_stat(
+ const thread_t thread,
+ char *status)
+{
+ char *p = status;
+
+ *p++ = (thread->state & TH_RUN) ? 'R' : '.';
+ *p++ = (thread->state & TH_WAIT) ? 'W' : '.';
+ *p++ = (thread->state & TH_SUSP) ? 'S' : '.';
+ *p++ = (thread->state & TH_SWAPPED) ? 'O' : '.';
+ *p++ = (thread->state & TH_UNINT) ? 'N' : '.';
+ /* show if the FPU has been used */
+ *p++ = db_thread_fp_used(thread) ? 'F' : '.';
+ *p++ = 0;
+ return(status);
+}
+
+void
+db_print_thread(
+ thread_t thread,
+ int thread_id,
+ int flag)
+{
+ if (flag & OPTION_USER) {
+ char status[8];
+ char *indent = "";
+ if (flag & OPTION_INDENT)
+ indent = " ";
+
+ if (flag & OPTION_LONG) {
+ if (flag & OPTION_THREAD_TITLE) {
+ db_printf("%s ID: THREAD STAT STACK PCB", indent);
+ db_printf(" SUS PRI CONTINUE,WAIT_FUNC\n");
+ }
+ db_printf("%s%3d%c %0*X %s %0*X %0*X %3d %3d ",
+ indent, thread_id,
+ (thread == current_thread())? '#': ':',
+ 2*sizeof(vm_offset_t), thread,
+ db_thread_stat(thread, status),
+ 2*sizeof(vm_offset_t), thread->kernel_stack,
+ 2*sizeof(vm_offset_t), thread->pcb,
+ thread->suspend_count, thread->sched_pri);
+ if ((thread->state & TH_SWAPPED) && thread->swap_func) {
+ db_task_printsym((db_addr_t)thread->swap_func,
+ DB_STGY_ANY, kernel_task);
+ db_printf(", ");
+ }
+ if (thread->state & TH_WAIT)
+ db_task_printsym((db_addr_t)thread->wait_event,
+ DB_STGY_ANY, kernel_task);
+ db_printf("\n");
+ } else if (flag & OPTION_SCHED) {
+ if (flag & OPTION_THREAD_TITLE) {
+ db_printf("%s "
+ "STAT PRIORITY POLICY USAGE LAST\n",
+ indent);
+ db_printf("%s ID: "
+ "RWSONF SET MAX COMP DEPR P DATA CPU SCHED UPDATED\n",
+ indent);
+ db_printf(" \n");
+ }
+ db_printf("%s%3d%c %s %4d %4d %4d %4d %c %4d %10d %10d %10d\n",
+ indent, thread_id,
+ (thread == current_thread())? '#': ':',
+ db_thread_stat(thread, status),
+ thread->priority,
+ thread->max_priority,
+ thread->sched_pri,
+ thread->depress_priority,
+#if MACH_FIXPRI
+ thread->policy == POLICY_TIMESHARE ? 'T' : 'F',
+ thread->sched_data,
+#else /* MACH_FIXPRI */
+ 'T', 0,
+#endif /* MACH_FIXPRI */
+ thread->cpu_usage,
+ thread->sched_usage,
+ thread->sched_stamp);
+ } else {
+ if (thread_id % 3 == 0) {
+ if (flag & OPTION_INDENT)
+ db_printf("\n ");
+ } else
+ db_printf(" ");
+ db_printf("%3d%c(%0*X,%s)", thread_id,
+ (thread == current_thread())? '#': ':',
+ 2*sizeof(vm_offset_t), thread,
+ db_thread_stat(thread, status));
+ }
+ } else {
+ if (flag & OPTION_INDENT)
+ db_printf(" %3d ", thread_id);
+ if (thread->name[0] &&
+ strncmp (thread->name, thread->task->name, THREAD_NAME_SIZE))
+ db_printf("%s ", thread->name);
+ db_printf("(%0*X) ", 2*sizeof(vm_offset_t), thread);
+ char status[8];
+ db_printf("%s", db_thread_stat(thread, status));
+ if (thread->state & TH_SWAPPED) {
+ if (thread->swap_func) {
+ db_printf("(");
+ db_task_printsym((db_addr_t)thread->swap_func,
+ DB_STGY_ANY, kernel_task);
+ db_printf(")");
+ } else {
+ db_printf("(swapped)");
+ }
+ }
+ if (thread->state & TH_WAIT) {
+ db_printf(" ");
+ db_task_printsym((db_addr_t)thread->wait_event,
+ DB_STGY_ANY, kernel_task);
+ }
+ db_printf("\n");
+ }
+}
+
+static void
+db_print_task(
+ task_t task,
+ int task_id,
+ int flag)
+{
+ thread_t thread;
+ int thread_id;
+
+ if (flag & OPTION_USER) {
+ if (flag & OPTION_TASK_TITLE) {
+ db_printf(" ID: TASK MAP THD SUS PR %s",
+ DB_TASK_NAME_TITLE);
+ if ((flag & (OPTION_LONG|OPTION_SCHED)) == 0)
+ db_printf(" THREADS");
+ db_printf("\n");
+ }
+ db_printf("%3d: %0*X %0*X %3d %3d %2d ",
+ task_id, 2*sizeof(vm_offset_t), task,
+ 2*sizeof(vm_offset_t), task->map, task->thread_count,
+ task->suspend_count, task->priority);
+ DB_TASK_NAME(task);
+ if (flag & (OPTION_LONG|OPTION_SCHED)) {
+ if (flag & OPTION_TASK_TITLE)
+ flag |= OPTION_THREAD_TITLE;
+ db_printf("\n");
+ } else if (task->thread_count <= 1)
+ flag &= ~OPTION_INDENT;
+ thread_id = 0;
+ queue_iterate(&task->thread_list, thread, thread_t, thread_list) {
+ db_print_thread(thread, thread_id, flag);
+ flag &= ~OPTION_THREAD_TITLE;
+ thread_id++;
+ }
+ if ((flag & (OPTION_LONG|OPTION_SCHED)) == 0)
+ db_printf("\n");
+ } else {
+ if (flag & OPTION_TASK_TITLE)
+ db_printf(" TASK THREADS\n");
+ if (task->name[0])
+ db_printf("%3d %s (%0*X): ", task_id, task->name,
+ 2*sizeof(vm_offset_t), task);
+ else
+ db_printf("%3d (%0*X): ", task_id,
+ 2*sizeof(vm_offset_t), task);
+ if (task->thread_count == 0) {
+ db_printf("no threads\n");
+ } else {
+ if (task->thread_count > 1) {
+ db_printf("%d threads: \n", task->thread_count);
+ flag |= OPTION_INDENT;
+ } else
+ flag &= ~OPTION_INDENT;
+ thread_id = 0;
+ queue_iterate(&task->thread_list, thread,
+ thread_t, thread_list)
+ db_print_thread(thread, thread_id++, flag);
+ }
+ }
+}
+
+void
+db_show_all_tasks(db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char *modif)
+{
+ task_t task;
+ int task_id = 0;
+ processor_set_t pset;
+
+ db_printf(" ID %-*s NAME [THREADS]\n", 2*sizeof(vm_offset_t), "TASK");
+
+ queue_iterate(&all_psets, pset, processor_set_t, all_psets)
+ queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
+ db_printf("%3d %0*X %s [%d]\n",
+ task_id,
+ 2*sizeof(vm_offset_t),
+ task,
+ task->name,
+ task->thread_count);
+ task_id++;
+ }
+}
+
+static void showrq(run_queue_t rq)
+{
+ db_printf("count(%d) low(%d)\n", rq->count, rq->low);
+}
+
+/*ARGSUSED*/
+void
+db_show_all_runqs(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ int i = 0;
+ processor_set_t pset;
+
+ queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
+ db_printf("Processor set #%d runq:\t", i);
+ showrq(&pset->runq);
+ i++;
+ }
+ for (i = 0; i < smp_get_numcpus(); i++) {
+ db_printf("Processor #%d runq:\t", i);
+ showrq(&cpu_to_processor(i)->runq);
+ }
+ db_printf("Stuck threads:\t%d", stuck_count);
+}
+
+/*ARGSUSED*/
+void
+db_show_all_threads(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ task_t task;
+ int task_id;
+ int flag;
+ processor_set_t pset;
+
+ flag = OPTION_TASK_TITLE|OPTION_INDENT;
+ if (db_option(modif, 'u'))
+ flag |= OPTION_USER;
+ if (db_option(modif, 'l'))
+ flag |= OPTION_LONG;
+ if (db_option(modif, 's'))
+ flag |= OPTION_SCHED;
+
+ task_id = 0;
+ queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
+ queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
+ db_print_task(task, task_id, flag);
+ flag &= ~OPTION_TASK_TITLE;
+ task_id++;
+ }
+ }
+}
+
+db_addr_t
+db_task_from_space(
+ ipc_space_t space,
+ int *task_id)
+{
+ task_t task;
+ int tid = 0;
+ processor_set_t pset;
+
+ queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
+ queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
+ if (task->itk_space == space) {
+ *task_id = tid;
+ return (db_addr_t)task;
+ }
+ tid++;
+ }
+ }
+ *task_id = 0;
+ return (0);
+}
+
+/*ARGSUSED*/
+void
+db_show_one_thread(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ int flag;
+ int thread_id;
+ thread_t thread;
+
+ flag = OPTION_THREAD_TITLE;
+ if (db_option(modif, 'u'))
+ flag |= OPTION_USER;
+ if (db_option(modif, 'l'))
+ flag |= OPTION_LONG;
+ if (db_option(modif, 's'))
+ flag |= OPTION_SCHED;
+
+ if (!have_addr) {
+ thread = current_thread();
+ if (thread == THREAD_NULL) {
+ db_error("No thread\n");
+ /*NOTREACHED*/
+ }
+ } else
+ thread = (thread_t) addr;
+
+ if ((thread_id = db_lookup_thread(thread)) < 0) {
+ db_printf("bad thread address %#X\n", addr);
+ db_error(0);
+ /*NOTREACHED*/
+ }
+
+ if (flag & OPTION_USER) {
+ db_printf("TASK%d(%0*X):\n",
+ db_lookup_task(thread->task),
+ 2*sizeof(vm_offset_t), thread->task);
+ db_print_thread(thread, thread_id, flag);
+ } else {
+ db_printf("task %d(%0*X): thread %d",
+ db_lookup_task(thread->task),
+ 2*sizeof(vm_offset_t), thread->task, thread_id);
+ db_print_thread(thread, thread_id, flag);
+ }
+}
+
+/*ARGSUSED*/
+void
+db_show_one_task(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ int flag;
+ int task_id;
+ task_t task;
+
+ flag = OPTION_TASK_TITLE;
+ if (db_option(modif, 'u'))
+ flag |= OPTION_USER;
+ if (db_option(modif, 'l'))
+ flag |= OPTION_LONG;
+
+ if (!have_addr) {
+ task = db_current_task();
+ if (task == TASK_NULL) {
+ db_error("No task\n");
+ /*NOTREACHED*/
+ }
+ } else
+ task = (task_t) addr;
+
+ if ((task_id = db_lookup_task(task)) < 0) {
+ db_printf("bad task address %#X\n", addr);
+ db_error(0);
+ /*NOTREACHED*/
+ }
+
+ db_print_task(task, task_id, flag);
+}
+
+static int
+db_port_iterate(const thread_t thread, void (*func)(int, const ipc_port_t, unsigned, int))
+{
+ ipc_entry_t entry;
+ int n = 0;
+ struct rdxtree_iter iter;
+ rdxtree_for_each(&thread->task->itk_space->is_map, &iter, entry) {
+ if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS)
+ (*func)(entry->ie_name, (ipc_port_t) entry->ie_object,
+ entry->ie_bits, n++);
+ }
+ return(n);
+}
+
+static void
+db_print_port_id(int id, const ipc_port_t port, unsigned bits, int n)
+{
+ if (n != 0 && n % 3 == 0)
+ db_printf("\n");
+ db_printf("\tport%d(%s,%x)", id,
+ (bits & MACH_PORT_TYPE_RECEIVE)? "r":
+ (bits & MACH_PORT_TYPE_SEND)? "s": "S", port);
+}
+
+static void
+db_print_port_id_long(
+ int id,
+ const ipc_port_t port,
+ unsigned bits,
+ int n)
+{
+ if (n != 0)
+ db_printf("\n");
+ db_printf("\tport%d(%s, port=0x%x", id,
+ (bits & MACH_PORT_TYPE_RECEIVE)? "r":
+ (bits & MACH_PORT_TYPE_SEND)? "s": "S", port);
+ db_printf(", receiver_name=0x%x)", port->ip_receiver_name);
+}
+
+/* ARGSUSED */
+void
+db_show_port_id(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ thread_t thread;
+
+ if (!have_addr) {
+ thread = current_thread();
+ if (thread == THREAD_NULL) {
+ db_error("No thread\n");
+ /*NOTREACHED*/
+ }
+ } else
+ thread = (thread_t) addr;
+ if (db_lookup_thread(thread) < 0) {
+ db_printf("Bad thread address %#X\n", addr);
+ db_error(0);
+ /*NOTREACHED*/
+ }
+ if (db_option(modif, 'l'))
+ {
+ if (db_port_iterate(thread, db_print_port_id_long))
+ db_printf("\n");
+ return;
+ }
+ if (db_port_iterate(thread, db_print_port_id))
+ db_printf("\n");
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_print.h b/ddb/db_print.h
new file mode 100644
index 0000000..b86c696
--- /dev/null
+++ b/ddb/db_print.h
@@ -0,0 +1,68 @@
+/*
+ * (c) Copyright 1992, 1993, 1994, 1995 OPEN SOFTWARE FOUNDATION, INC.
+ * ALL RIGHTS RESERVED
+ */
+/*
+ * OSF RI nmk19b2 5/2/95
+ */
+
+#ifndef _DDB_DB_PRINT_H_
+#define _DDB_DB_PRINT_H_
+
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+
+/* Prototypes for functions exported by this module.
+ */
+void db_show_regs(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ char *modif);
+
+void db_show_one_task(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_show_port_id(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_show_one_thread(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_show_all_tasks(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_show_all_threads(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_show_all_runqs(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+db_addr_t db_task_from_space(
+ ipc_space_t space,
+ int *task_id);
+
+void db_print_thread(
+ thread_t thread,
+ int thread_id,
+ int flag);
+
+#endif /* !_DDB_DB_PRINT_H_ */
diff --git a/ddb/db_run.c b/ddb/db_run.c
new file mode 100644
index 0000000..0c8c12f
--- /dev/null
+++ b/ddb/db_run.c
@@ -0,0 +1,430 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+/*
+ * Commands to run process.
+ */
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_break.h>
+#include <ddb/db_access.h>
+#include <ddb/db_run.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_command.h>
+#include <ddb/db_examine.h>
+#include <ddb/db_output.h>
+#include <ddb/db_watch.h>
+#include <ddb/db_cond.h>
+
+
+int db_run_mode;
+
+boolean_t db_sstep_print;
+int db_loop_count;
+int db_call_depth;
+
+int db_inst_count;
+int db_last_inst_count;
+int db_load_count;
+int db_store_count;
+
+boolean_t
+db_stop_at_pc(
+ boolean_t *is_breakpoint,
+ task_t task)
+{
+ db_addr_t pc;
+ db_thread_breakpoint_t bkpt;
+
+ db_clear_task_single_step(DDB_REGS, task);
+ db_clear_breakpoints();
+ db_clear_watchpoints();
+ pc = PC_REGS(DDB_REGS);
+
+#ifdef FIXUP_PC_AFTER_BREAK
+ if (*is_breakpoint) {
+ /*
+ * Breakpoint trap. Fix up the PC if the
+ * machine requires it.
+ */
+ FIXUP_PC_AFTER_BREAK
+ pc = PC_REGS(DDB_REGS);
+ }
+#endif /* FIXUP_PC_AFTER_BREAK */
+
+ /*
+ * Now check for a breakpoint at this address.
+ */
+ bkpt = db_find_thread_breakpoint_here(task, pc);
+ if (bkpt) {
+ if (db_cond_check(bkpt)) {
+ *is_breakpoint = TRUE;
+ return (TRUE); /* stop here */
+ }
+ }
+ *is_breakpoint = FALSE;
+
+ if (db_run_mode == STEP_INVISIBLE) {
+ db_run_mode = STEP_CONTINUE;
+ return (FALSE); /* continue */
+ }
+ if (db_run_mode == STEP_COUNT) {
+ return (FALSE); /* continue */
+ }
+ if (db_run_mode == STEP_ONCE) {
+ if (--db_loop_count > 0) {
+ if (db_sstep_print) {
+ db_print_loc_and_inst(pc, task);
+ }
+ return (FALSE); /* continue */
+ }
+ }
+ if (db_run_mode == STEP_RETURN) {
+ /* WARNING: the following assumes an instruction fits an int */
+ db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, task);
+
+ /* continue until matching return */
+
+ if (!inst_trap_return(ins) &&
+ (!inst_return(ins) || --db_call_depth != 0)) {
+ if (db_sstep_print) {
+ if (inst_call(ins) || inst_return(ins)) {
+ int i;
+
+ db_printf("[after %6d /%4d] ",
+ db_inst_count,
+ db_inst_count - db_last_inst_count);
+ db_last_inst_count = db_inst_count;
+ for (i = db_call_depth; --i > 0; )
+ db_printf(" ");
+ db_print_loc_and_inst(pc, task);
+ db_printf("\n");
+ }
+ }
+ if (inst_call(ins))
+ db_call_depth++;
+ return (FALSE); /* continue */
+ }
+ }
+ if (db_run_mode == STEP_CALLT) {
+ /* WARNING: the following assumes an instruction fits an int */
+ db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, task);
+
+ /* continue until call or return */
+
+ if (!inst_call(ins) &&
+ !inst_return(ins) &&
+ !inst_trap_return(ins)) {
+ return (FALSE); /* continue */
+ }
+ }
+ if (db_find_breakpoint_here(task, pc))
+ return(FALSE);
+ db_run_mode = STEP_NONE;
+ return (TRUE);
+}
+
+void
+db_restart_at_pc(
+ boolean_t watchpt,
+ task_t task)
+{
+ db_addr_t pc = PC_REGS(DDB_REGS);
+
+ if ((db_run_mode == STEP_COUNT) ||
+ (db_run_mode == STEP_RETURN) ||
+ (db_run_mode == STEP_CALLT)) {
+
+ /*
+ * We are about to execute this instruction,
+ * so count it now.
+ */
+
+ db_get_task_value(pc, sizeof(int), FALSE, task);
+ db_inst_count++;
+ db_load_count += inst_load(ins);
+ db_store_count += inst_store(ins);
+#ifdef SOFTWARE_SSTEP
+ db_addr_t brpc;
+ /* Account for instructions in delay slots */
+ brpc = next_instr_address(pc, 1, task);
+ if ((brpc != pc) && (inst_branch(ins) || inst_call(ins))) {
+ /* Note: this ~assumes an instruction <= sizeof(int) */
+ db_get_task_value(brpc, sizeof(int), FALSE, task);
+ db_inst_count++;
+ db_load_count += inst_load(ins);
+ db_store_count += inst_store(ins);
+ }
+#endif /* SOFTWARE_SSTEP */
+ }
+
+ if (db_run_mode == STEP_CONTINUE) {
+ if (watchpt || db_find_breakpoint_here(task, pc)) {
+ /*
+ * Step over breakpoint/watchpoint.
+ */
+ db_run_mode = STEP_INVISIBLE;
+ db_set_task_single_step(DDB_REGS, task);
+ } else {
+ db_set_breakpoints();
+ db_set_watchpoints();
+ }
+ } else {
+ db_set_task_single_step(DDB_REGS, task);
+ }
+}
+
+void
+db_single_step(
+ db_regs_t *regs,
+ task_t task)
+{
+ if (db_run_mode == STEP_CONTINUE) {
+ db_run_mode = STEP_INVISIBLE;
+ db_set_task_single_step(regs, task);
+ }
+}
+
+#ifdef SOFTWARE_SSTEP
+/*
+ * Software implementation of single-stepping.
+ * If your machine does not have a trace mode
+ * similar to the vax or sun ones you can use
+ * this implementation, done for the mips.
+ * Just define the above conditional and provide
+ * the functions/macros defined below.
+ *
+ * extern boolean_t
+ * inst_branch(), returns true if the instruction might branch
+ * extern unsigned
+ * branch_taken(), return the address the instruction might
+ * branch to
+ * db_getreg_val(); return the value of a user register,
+ * as indicated in the hardware instruction
+ * encoding, e.g. 8 for r8
+ *
+ * next_instr_address(pc,bd,task) returns the address of the first
+ * instruction following the one at "pc",
+ * which is either in the taken path of
+ * the branch (bd==1) or not. This is
+ * for machines (mips) with branch delays.
+ *
+ * A single-step may involve at most 2 breakpoints -
+ * one for branch-not-taken and one for branch taken.
+ * If one of these addresses does not already have a breakpoint,
+ * we allocate a breakpoint and save it here.
+ * These breakpoints are deleted on return.
+ */
+db_breakpoint_t db_not_taken_bkpt = 0;
+db_breakpoint_t db_taken_bkpt = 0;
+
+db_breakpoint_t __attribute__ ((pure))
+db_find_temp_breakpoint(const task_t task, db_addr_t addr)
+{
+ if (db_taken_bkpt && (db_taken_bkpt->address == addr) &&
+ db_taken_bkpt->task == task)
+ return db_taken_bkpt;
+ if (db_not_taken_bkpt && (db_not_taken_bkpt->address == addr) &&
+ db_not_taken_bkpt->task == task)
+ return db_not_taken_bkpt;
+ return 0;
+}
+
+void
+db_set_task_single_step(
+ db_regs_t *regs,
+ task_t task)
+{
+ db_addr_t pc = PC_REGS(regs), brpc;
+ unsigned int inst;
+ boolean_t unconditional;
+
+ /*
+ * User was stopped at pc, e.g. the instruction
+ * at pc was not executed.
+ */
+ inst = db_get_task_value(pc, sizeof(int), FALSE, task);
+ if (inst_branch(inst) || inst_call(inst)) {
+ extern db_expr_t getreg_val();
+
+ brpc = branch_taken(inst, pc, getreg_val, regs);
+ if (brpc != pc) { /* self-branches are hopeless */
+ db_taken_bkpt = db_set_temp_breakpoint(task, brpc);
+ } else
+ db_taken_bkpt = 0;
+ pc = next_instr_address(pc,1,task);
+ }
+
+ /* check if this control flow instruction is an unconditional transfer */
+ unconditional = inst_unconditional_flow_transfer(inst);
+
+ pc = next_instr_address(pc,0,task);
+ /*
+ We only set the sequential breakpoint if previous instruction was not
+ an unconditional change of flow of control. If the previous instruction
+ is an unconditional change of flow of control, setting a breakpoint in the
+ next sequential location may set a breakpoint in data or in another routine,
+ which could screw up either the program or the debugger.
+ (Consider, for instance, that the next sequential instruction is the
+ start of a routine needed by the debugger.)
+ */
+ if (!unconditional && db_find_breakpoint_here(task, pc) == 0) {
+ db_not_taken_bkpt = db_set_temp_breakpoint(task, pc);
+ }
+ else
+ db_not_taken_bkpt = 0;
+}
+
+void
+db_clear_task_single_step(const db_regs_t *regs, task_t task)
+{
+ if (db_taken_bkpt != 0) {
+ db_delete_temp_breakpoint(task, db_taken_bkpt);
+ db_taken_bkpt = 0;
+ }
+ if (db_not_taken_bkpt != 0) {
+ db_delete_temp_breakpoint(task, db_not_taken_bkpt);
+ db_not_taken_bkpt = 0;
+ }
+}
+
+#endif /* SOFTWARE_SSTEP */
+
+
+extern int db_cmd_loop_done;
+
+/* single-step */
+/*ARGSUSED*/
+void
+db_single_step_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ boolean_t print = FALSE;
+
+ if (count == -1)
+ count = 1;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_ONCE;
+ db_loop_count = count;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_last_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/* trace and print until call/return */
+/*ARGSUSED*/
+void
+db_trace_until_call_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ boolean_t print = FALSE;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_CALLT;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_last_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/*ARGSUSED*/
+void
+db_trace_until_matching_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ boolean_t print = FALSE;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_RETURN;
+ db_call_depth = 1;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_last_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/* continue */
+/*ARGSUSED*/
+void
+db_continue_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ if (modif[0] == 'c')
+ db_run_mode = STEP_COUNT;
+ else
+ db_run_mode = STEP_CONTINUE;
+ db_inst_count = 0;
+ db_last_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+boolean_t
+db_in_single_step(void)
+{
+ return(db_run_mode != STEP_NONE && db_run_mode != STEP_CONTINUE);
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_run.h b/ddb/db_run.h
new file mode 100644
index 0000000..c042d4c
--- /dev/null
+++ b/ddb/db_run.h
@@ -0,0 +1,94 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _DDB_DB_RUN_H_
+#define _DDB_DB_RUN_H_
+
+#include <kern/task.h>
+#include <machine/db_machdep.h>
+
+extern int db_run_mode;
+
+/* modes the system may be running in */
+
+#define STEP_NONE 0
+#define STEP_ONCE 1
+#define STEP_RETURN 2
+#define STEP_CALLT 3
+#define STEP_CONTINUE 4
+#define STEP_INVISIBLE 5
+#define STEP_COUNT 6
+
+extern void db_single_step(db_regs_t *regs, task_t task);
+
+extern void db_single_step_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char *modif);
+
+void db_trace_until_call_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_trace_until_matching_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_continue_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+#ifndef db_set_single_step
+void db_set_task_single_step(db_regs_t *, task_t);
+#else
+#define db_set_task_single_step(regs, task) db_set_single_step(regs)
+#endif
+#ifndef db_clear_single_step
+void db_clear_task_single_step(const db_regs_t *, task_t);
+#else
+#define db_clear_task_single_step(regs, task) db_clear_single_step(regs)
+#endif
+
+extern boolean_t db_in_single_step(void);
+
+extern void
+db_restart_at_pc(
+ boolean_t watchpt,
+ task_t task);
+
+extern boolean_t
+db_stop_at_pc(
+ boolean_t *is_breakpoint,
+ task_t task);
+
+#endif /* _DDB_DB_RUN_H_ */
diff --git a/ddb/db_sym.c b/ddb/db_sym.c
new file mode 100644
index 0000000..f0adb0c
--- /dev/null
+++ b/ddb/db_sym.c
@@ -0,0 +1,532 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992,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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+#include <string.h>
+#include <mach/std_types.h>
+#include <machine/db_machdep.h>
+#include <ddb/db_command.h>
+#include <ddb/db_output.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_elf.h>
+
+#include <vm/vm_map.h> /* vm_map_t */
+
+/*
+ * Multiple symbol tables
+ */
+#define MAXNOSYMTABS 5 /* mach, bootstrap, ux, emulator, 1 spare */
+
+db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},};
+int db_nsymtab = 0;
+
+db_symtab_t *db_last_symtab;
+
+/*
+ * Add symbol table, with given name, to list of symbol tables.
+ */
+boolean_t
+db_add_symbol_table(
+ int type,
+ char *start,
+ char *end,
+ const char *name,
+ char *ref,
+ char *map_pointer)
+{
+ db_symtab_t *st;
+ extern vm_map_t kernel_map;
+
+ if (db_nsymtab >= MAXNOSYMTABS)
+ return (FALSE);
+
+ st = &db_symtabs[db_nsymtab];
+ st->type = type;
+ st->start = start;
+ st->end = end;
+ st->private = ref;
+ st->map_pointer = (map_pointer == (char *)kernel_map)? 0: map_pointer;
+ strncpy(st->name, name, sizeof st->name - 1);
+ st->name[sizeof st->name - 1] = '\0';
+
+ db_nsymtab++;
+
+ return (TRUE);
+}
+
+/*
+ * db_qualify("vm_map", "ux") returns "ux::vm_map".
+ *
+ * Note: return value points to static data whose content is
+ * overwritten by each call... but in practice this seems okay.
+ */
+static char * __attribute__ ((pure))
+db_qualify(const char *symname, const char *symtabname)
+{
+ static char tmp[256];
+ char *s;
+
+ s = tmp;
+ while ((*s++ = *symtabname++)) {
+ }
+ s[-1] = ':';
+ *s++ = ':';
+ while ((*s++ = *symname++)) {
+ }
+ return tmp;
+}
+
+
+boolean_t
+db_eqname( const char* src, const 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(
+ char *name,
+ db_expr_t *valuep)
+{
+ db_sym_t sym;
+
+ sym = db_lookup(name);
+ if (sym == DB_SYM_NULL)
+ return (FALSE);
+ db_symbol_values(0, sym, &name, valuep);
+
+ db_free_symbol(sym);
+ 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(char *symstr)
+{
+ db_sym_t sp;
+ int i;
+ int symtab_start = 0;
+ int symtab_end = db_nsymtab;
+ char *cp;
+
+ /*
+ * Look for, remove, and remember any symbol table specifier.
+ */
+ for (cp = symstr; *cp; cp++) {
+ if (*cp == ':' && cp[1] == ':') {
+ *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\n");
+ symstr = cp+2;
+ }
+ }
+
+ /*
+ * 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;
+ }
+ db_free_symbol(sp);
+ }
+ return 0;
+}
+
+/*
+ * Common utility routine to parse a symbol string into a file
+ * name, a symbol name and line number.
+ * This routine is called from X_db_lookup if the object dependent
+ * handler supports qualified search with a file name or a line number.
+ * It parses the symbol string, and call an object dependent routine
+ * with parsed file name, symbol name and line number.
+ */
+db_sym_t
+db_sym_parse_and_lookup(
+ db_sym_t (*func) (db_symtab_t *, const char*, const char*, int),
+ db_symtab_t *symtab,
+ char *symstr)
+{
+ char *p;
+ int n;
+ int n_name;
+ int line_number;
+ char *file_name = 0;
+ char *sym_name = 0;
+ char *component[3];
+ db_sym_t found = DB_SYM_NULL;
+
+ /*
+ * disassemble the symbol into components:
+ * [file_name:]symbol[:line_nubmer]
+ */
+ component[0] = symstr;
+ component[1] = component[2] = 0;
+ for (p = symstr, n = 1; *p; p++) {
+ if (*p == ':') {
+ if (n >= 3)
+ break;
+ *p = 0;
+ component[n++] = p+1;
+ }
+ }
+ if (*p != 0)
+ goto out;
+ line_number = 0;
+ n_name = n;
+ p = component[n-1];
+ if (*p >= '0' && *p <= '9') {
+ if (n == 1)
+ goto out;
+ for (line_number = 0; *p; p++) {
+ if (*p < '0' || *p > '9')
+ goto out;
+ line_number = line_number*10 + *p - '0';
+ }
+ n_name--;
+ } else if (n >= 3)
+ goto out;
+ if (n_name == 1) {
+ for (p = component[0]; *p && *p != '.'; p++);
+ if (*p == '.') {
+ file_name = component[0];
+ sym_name = 0;
+ } else {
+ file_name = 0;
+ sym_name = component[0];
+ }
+ } else {
+ file_name = component[0];
+ sym_name = component[1];
+ }
+ found = func(symtab, file_name, sym_name, line_number);
+
+out:
+ while (--n >= 1)
+ component[n][-1] = ':';
+ return(found);
+}
+
+/*
+ * 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;
+
+static boolean_t
+db_name_is_ambiguous(char *sym_name)
+{
+ int i;
+ boolean_t found_once = FALSE;
+
+ if (!db_qualify_ambiguous_names)
+ return FALSE;
+
+ for (i = 0; i < db_nsymtab; i++) {
+ db_sym_t sp = X_db_lookup(&db_symtabs[i], sym_name);
+ if (sp) {
+ if (found_once)
+ {
+ db_free_symbol(sp);
+ return TRUE;
+ }
+ found_once = TRUE;
+ }
+ db_free_symbol(sp);
+ }
+ return FALSE;
+}
+
+/*
+ * Find the closest symbol to val, and return its name
+ * and the difference between val and the symbol found.
+ *
+ * Logic change. If the task argument is non NULL and a
+ * matching symbol is found in a symbol table which explicitly
+ * specifies its map to be task->map, that symbol will have
+ * precedence over any symbol from a symbol table will a null
+ * map. This allows overlapping kernel/user maps to work correctly.
+ *
+ */
+db_sym_t
+db_search_task_symbol(
+ db_addr_t val,
+ db_strategy_t strategy,
+ db_addr_t *offp, /* better be unsigned */
+ task_t task)
+{
+ db_sym_t ret;
+
+ if (task != TASK_NULL)
+ ret = db_search_in_task_symbol(val, strategy, offp, task);
+ else
+ {
+ ret = db_search_in_task_symbol(val, strategy, offp, task);
+ /*
+ db_search_in_task_symbol will return success with
+ a very large offset when it should have failed.
+ */
+ if (ret == DB_SYM_NULL || (*offp) > 0x1000000)
+ {
+ db_free_symbol(ret);
+ task = db_current_task();
+ ret = db_search_in_task_symbol(val, strategy, offp, task);
+ }
+ }
+
+ return ret;
+}
+
+db_sym_t
+db_search_in_task_symbol(
+ db_addr_t val,
+ db_strategy_t strategy,
+ db_addr_t *offp,
+ task_t task)
+{
+ vm_size_t diff;
+ vm_size_t newdiff;
+ int i;
+ db_symtab_t *sp;
+ db_sym_t ret = DB_SYM_NULL, sym;
+ vm_map_t map_for_val;
+
+ map_for_val = (task == TASK_NULL)? VM_MAP_NULL: task->map;
+ newdiff = diff = ~0;
+ db_last_symtab = (db_symtab_t *) 0;
+ for (sp = &db_symtabs[0], i = 0; i < db_nsymtab; sp++, i++)
+ {
+ newdiff = ~0;
+ if ((vm_map_t)sp->map_pointer == VM_MAP_NULL ||
+ (vm_map_t)sp->map_pointer == map_for_val)
+ {
+ sym = X_db_search_symbol(sp, val, strategy, (db_expr_t*)&newdiff);
+ if (sym == DB_SYM_NULL)
+ continue;
+ if (db_last_symtab == (db_symtab_t *) 0)
+ { /* first hit */
+ db_last_symtab = sp;
+ diff = newdiff;
+ db_free_symbol(ret);
+ ret = sym;
+ continue;
+ }
+ if ((vm_map_t) sp->map_pointer == VM_MAP_NULL &&
+ (vm_map_t) db_last_symtab->map_pointer == VM_MAP_NULL &&
+ newdiff < diff )
+ { /* closer null map match */
+ db_last_symtab = sp;
+ diff = newdiff;
+ db_free_symbol(ret);
+ ret = sym;
+ continue;
+ }
+ if ((vm_map_t) sp->map_pointer != VM_MAP_NULL &&
+ (newdiff < 0x100000) &&
+ ((vm_map_t) db_last_symtab->map_pointer == VM_MAP_NULL ||
+ newdiff < diff ))
+ { /* update if new is in matching map and symbol is "close",
+ and
+ old is VM_MAP_NULL or old in is matching map but is further away
+ */
+ db_last_symtab = sp;
+ diff = newdiff;
+ db_free_symbol(ret);
+ ret = sym;
+ continue;
+ }
+ }
+ }
+
+ *offp = diff;
+ return ret;
+}
+
+/*
+ * Return name and value of a symbol
+ */
+void
+db_symbol_values(
+ db_symtab_t *stab,
+ db_sym_t sym,
+ char **namep,
+ db_expr_t *valuep)
+{
+ db_expr_t value;
+ char *name;
+
+ if (sym == DB_SYM_NULL) {
+ *namep = 0;
+ return;
+ }
+ if (stab == 0)
+ stab = db_last_symtab;
+
+ X_db_symbol_values(stab, sym, &name, &value);
+
+ if (db_name_is_ambiguous(name))
+ *namep = db_qualify(name, db_last_symtab->name);
+ else
+ *namep = name;
+ if (valuep)
+ *valuep = value;
+}
+
+
+/*
+ * Print 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 long db_maxoff = 0x4000;
+
+void
+db_task_printsym(
+ db_addr_t off,
+ db_strategy_t strategy,
+ task_t task)
+{
+ db_addr_t d;
+ char *filename;
+ char *name;
+ db_expr_t value;
+ int linenum;
+ db_sym_t cursym;
+
+ cursym = db_search_task_symbol(off, strategy, &d, task);
+ db_symbol_values(0, cursym, &name, &value);
+ if (name == 0 || d >= db_maxoff || value == 0 || *name == 0) {
+ db_printf("%#n", off);
+ db_free_symbol(cursym);
+ return;
+ }
+ db_printf("%s", name);
+ if (d)
+ db_printf("+0x%x", d);
+ if (strategy == DB_STGY_PROC) {
+ if (db_line_at_pc(cursym, &filename, &linenum, off)) {
+ db_printf(" [%s", filename);
+ if (linenum > 0)
+ db_printf(":%d", linenum);
+ db_printf("]");
+ }
+ }
+ db_free_symbol(cursym);
+}
+
+void
+db_printsym(
+ db_expr_t off,
+ db_strategy_t strategy)
+{
+ db_task_printsym(off, strategy, TASK_NULL);
+}
+
+boolean_t
+db_line_at_pc(
+ db_sym_t sym,
+ char **filename,
+ int *linenum,
+ db_addr_t pc)
+{
+ return (db_last_symtab) ?
+ X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc) :
+ FALSE;
+}
+
+void db_free_symbol(db_sym_t s)
+{
+ return (db_last_symtab) ?
+ X_db_free_symbol( db_last_symtab, s) :
+ FALSE;
+}
+
+/*
+ * Switch into symbol-table specific routines
+ */
+
+static void dummy_db_free_symbol(db_sym_t symbol) { }
+static boolean_t dummy_db_sym_init(char *a, char *b, const char *c, char *d) {
+ return FALSE;
+}
+
+
+struct db_sym_switch x_db[] = {
+
+ /* BSD a.out format (really, sdb/dbx(1) symtabs) not supported */
+ { 0,},
+
+ { 0,},
+
+ /* Machdep, not inited here */
+ { 0,},
+
+#ifdef DB_NO_ELF
+ { 0,},
+#else /* DB_NO_ELF */
+ { dummy_db_sym_init, elf_db_lookup, elf_db_search_symbol,
+ elf_db_line_at_pc, elf_db_symbol_values, dummy_db_free_symbol },
+#endif /* DB_NO_ELF */
+
+};
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_sym.h b/ddb/db_sym.h
new file mode 100644
index 0000000..f4fb528
--- /dev/null
+++ b/ddb/db_sym.h
@@ -0,0 +1,264 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: Alessandro Forin, Carnegie Mellon University
+ * Date: 8/90
+ */
+
+#ifndef _DDB_DB_SYM_H_
+#define _DDB_DB_SYM_H_
+
+#include <mach/boolean.h>
+#include <mach/machine/vm_types.h>
+#include <machine/db_machdep.h>
+
+/*
+ * This module can handle multiple symbol tables,
+ * of multiple types, at the same time
+ */
+#define SYMTAB_NAME_LEN 32
+
+typedef struct {
+ int type;
+#define SYMTAB_AOUT 0
+#define SYMTAB_COFF 1
+#define SYMTAB_MACHDEP 2
+#define SYMTAB_ELF 3
+ char *start; /* symtab location */
+ char *end;
+ char *private; /* optional machdep pointer */
+ char *map_pointer; /* symbols are for this map only,
+ if not null */
+ char name[SYMTAB_NAME_LEN];
+ /* symtab name */
+} 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 concerned 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
+ * ..but the machine has nothing
+ * else to do, now does it ? */
+
+/*
+ * Functions exported by the symtable module
+ */
+
+/* extend the list of symbol tables */
+
+extern boolean_t db_add_symbol_table( int type,
+ char * start,
+ char * end,
+ const char *name,
+ char *ref,
+ char *map_pointer );
+
+/* find symbol value given name */
+
+extern int db_value_of_name( char* name, db_expr_t* valuep);
+
+/* find symbol given value */
+
+extern db_sym_t db_search_task_symbol( db_addr_t val,
+ db_strategy_t strategy,
+ db_addr_t *offp,
+ task_t task );
+
+/* return name and value of symbol */
+
+extern void db_symbol_values( db_symtab_t *stab,
+ db_sym_t sym,
+ char** namep,
+ db_expr_t* valuep);
+
+/* find symbol in current task */
+#define db_search_symbol(val,strgy,offp) \
+ db_search_task_symbol(val,strgy,offp,0)
+
+/* find name&value given approx val */
+
+#define db_find_sym_and_offset(val,namep,offp) \
+ do { \
+ db_sym_t s; \
+ db_symbol_values(0, s = db_search_symbol(val,DB_STGY_ANY,offp) \
+ ,namep,0); \
+ db_free_symbol(s); \
+ } while(0);
+
+
+/* ditto, but no locals */
+#define db_find_xtrn_sym_and_offset(val,namep,offp) \
+ do { \
+ db_sym_t s; \
+ db_symbol_values(0, s = db_search_symbol(val,DB_STGY_XTRN,offp) \
+ ,namep,0); \
+ db_free_symbol(s); \
+ } while(0);
+
+/* find name&value given approx val */
+
+#define db_find_task_sym_and_offset(val,namep,offp,task) \
+ do { \
+ db_sym_t s; \
+ db_symbol_values(0, s = db_search_task_symbol(val,DB_STGY_ANY \
+ ,offp,task), \
+ namep, 0); \
+ db_free_symbol(s); \
+ } while(0);
+
+/* ditto, but no locals */
+#define db_find_xtrn_task_sym_and_offset(val,namep,offp,task) \
+ do { \
+ db_sym_t s; \
+ db_symbol_values(0, s = db_search_task_symbol(val,DB_STGY_XTRN \
+ ,offp,task), \
+ namep,0); \
+ db_free_symbol(s); \
+ } while(0);
+
+/* strcmp, modulo leading char */
+extern boolean_t db_eqname( const char* src, const char* dst, char c );
+
+/* print closest symbol to a value */
+extern void db_task_printsym( db_addr_t off,
+ db_strategy_t strategy,
+ task_t task);
+
+/* print closest symbol to a value */
+extern void db_printsym( db_expr_t off, db_strategy_t strategy);
+
+/* free a symbol */
+extern void db_free_symbol(db_sym_t s);
+
+
+/*
+ * Symbol table switch, defines the interface
+ * to symbol-table specific routines.
+ */
+
+extern struct db_sym_switch {
+
+ boolean_t (*init)(
+ char *start,
+ char *end,
+ const char *name,
+ char *task_addr
+ );
+
+ db_sym_t (*lookup)(
+ db_symtab_t *stab,
+ char *symstr
+ );
+ db_sym_t (*search_symbol)(
+ db_symtab_t *stab,
+ db_addr_t off,
+ db_strategy_t strategy,
+ db_expr_t *diffp
+ );
+
+ boolean_t (*line_at_pc)(
+ db_symtab_t *stab,
+ db_sym_t sym,
+ char **file,
+ int *line,
+ db_addr_t pc
+ );
+
+ void (*symbol_values)(
+ db_symtab_t *stab,
+ db_sym_t sym,
+ char **namep,
+ db_expr_t *valuep
+ );
+
+ void (*free_symbol)(
+ db_sym_t sym
+ );
+} x_db[];
+
+#ifndef symtab_type
+#define symtab_type(s) SYMTAB_ELF
+#endif
+
+#define X_db_sym_init(s,e,n,t) x_db[symtab_type(s)].init(s,e,n,t)
+#define X_db_lookup(s,n) x_db[(s)->type].lookup(s,n)
+#define X_db_search_symbol(s,o,t,d) x_db[(s)->type].search_symbol(s,o,t,d)
+#define X_db_line_at_pc(s,p,f,l,a) x_db[(s)->type].line_at_pc(s,p,f,l,a)
+#define X_db_symbol_values(s,p,n,v) x_db[(s)->type].symbol_values(s,p,n,v)
+#define X_db_free_symbol(s,m) x_db[(s)->type].free_symbol(m)
+
+extern boolean_t db_line_at_pc(
+ db_sym_t sym,
+ char **filename,
+ int *linenum,
+ db_addr_t pc);
+
+extern boolean_t elf_db_sym_init (
+ unsigned shdr_num,
+ vm_size_t shdr_size,
+ vm_offset_t shdr_addr,
+ unsigned shdr_shndx,
+ char *name,
+ char *task_addr);
+
+db_sym_t db_lookup(char *);
+
+db_sym_t
+db_search_in_task_symbol(
+ db_addr_t val,
+ db_strategy_t strategy,
+ db_addr_t *offp,
+ task_t task);
+
+extern db_sym_t
+db_sym_parse_and_lookup(
+ db_sym_t (*func) (db_symtab_t *, const char*, const char*, int),
+ db_symtab_t *symtab,
+ char *symstr);
+
+#endif /* _DDB_DB_SYM_H_ */
diff --git a/ddb/db_task_thread.c b/ddb/db_task_thread.c
new file mode 100644
index 0000000..fe742c2
--- /dev/null
+++ b/ddb/db_task_thread.c
@@ -0,0 +1,326 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+
+#if MACH_KDB
+
+#include <machine/db_machdep.h>
+#include <ddb/db_command.h>
+#include <ddb/db_expr.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_variables.h>
+
+
+
+/*
+ * Following constants are used to prevent infinite loop of task
+ * or thread search due to the incorrect list.
+ */
+#define DB_MAX_TASKID 0x10000 /* max # of tasks */
+#define DB_MAX_THREADID 0x10000 /* max # of threads in a task */
+#define DB_MAX_PSETS 0x10000 /* max # of processor sets */
+
+task_t db_default_task; /* default target task */
+thread_t db_default_thread; /* default target thread */
+
+/*
+ * search valid task queue, and return the queue position as the task id
+ */
+int
+db_lookup_task(const task_t target_task)
+{
+ task_t task;
+ int task_id;
+ processor_set_t pset;
+ int npset = 0;
+
+ task_id = 0;
+ if (queue_first(&all_psets) == 0)
+ return(-1);
+ queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
+ if (npset++ >= DB_MAX_PSETS)
+ return(-1);
+ if (queue_first(&pset->tasks) == 0)
+ continue;
+ queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
+ if (target_task == task)
+ return(task_id);
+ if (task_id++ >= DB_MAX_TASKID)
+ return(-1);
+ }
+ }
+ return(-1);
+}
+
+/*
+ * search thread queue of the task, and return the queue position
+ */
+int
+db_lookup_task_thread(const task_t task, const thread_t target_thread)
+{
+ thread_t thread;
+ int thread_id;
+
+ thread_id = 0;
+ if (queue_first(&task->thread_list) == 0)
+ return(-1);
+ queue_iterate(&task->thread_list, thread, thread_t, thread_list) {
+ if (target_thread == thread)
+ return(thread_id);
+ if (thread_id++ >= DB_MAX_THREADID)
+ return(-1);
+ }
+ return(-1);
+}
+
+/*
+ * search thread queue of every valid task, and return the queue position
+ * as the thread id.
+ */
+int
+db_lookup_thread(const thread_t target_thread)
+{
+ int thread_id;
+ task_t task;
+ processor_set_t pset;
+ int ntask = 0;
+ int npset = 0;
+
+ if (queue_first(&all_psets) == 0)
+ return(-1);
+ queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
+ if (npset++ >= DB_MAX_PSETS)
+ return(-1);
+ if (queue_first(&pset->tasks) == 0)
+ continue;
+ queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
+ if (ntask++ > DB_MAX_TASKID)
+ return(-1);
+ if (task->thread_count == 0)
+ continue;
+ thread_id = db_lookup_task_thread(task, target_thread);
+ if (thread_id >= 0)
+ return(thread_id);
+ }
+ }
+ return(-1);
+}
+
+/*
+ * check the address is a valid thread address
+ */
+boolean_t
+db_check_thread_address_valid(const thread_t thread)
+{
+ if (db_lookup_thread(thread) < 0) {
+ db_printf("Bad thread address 0x%x\n", thread);
+ db_flush_lex();
+ return(FALSE);
+ } else
+ return(TRUE);
+}
+
+/*
+ * convert task_id(queue position) to task address
+ */
+static task_t
+db_lookup_task_id(int task_id)
+{
+ task_t task;
+ processor_set_t pset;
+ int npset = 0;
+
+ if (task_id > DB_MAX_TASKID)
+ return(TASK_NULL);
+ if (queue_first(&all_psets) == 0)
+ return(TASK_NULL);
+ queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
+ if (npset++ >= DB_MAX_PSETS)
+ return(TASK_NULL);
+ if (queue_first(&pset->tasks) == 0)
+ continue;
+ queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
+ if (task_id-- <= 0)
+ return(task);
+ }
+ }
+ return(TASK_NULL);
+}
+
+/*
+ * convert (task_id, thread_id) pair to thread address
+ */
+static thread_t
+db_lookup_thread_id(
+ task_t task,
+ int thread_id)
+{
+ thread_t thread;
+
+
+ if (thread_id > DB_MAX_THREADID)
+ return(THREAD_NULL);
+ if (queue_first(&task->thread_list) == 0)
+ return(THREAD_NULL);
+ queue_iterate(&task->thread_list, thread, thread_t, thread_list) {
+ if (thread_id-- <= 0)
+ return(thread);
+ }
+ return(THREAD_NULL);
+}
+
+/*
+ * get next parameter from a command line, and check it as a valid
+ * thread address
+ */
+boolean_t
+db_get_next_thread(
+ thread_t *threadp,
+ int position)
+{
+ db_expr_t value;
+ thread_t thread;
+
+ *threadp = THREAD_NULL;
+ if (db_expression(&value)) {
+ thread = (thread_t) value;
+ if (!db_check_thread_address_valid(thread)) {
+ db_flush_lex();
+ return(FALSE);
+ }
+ } else if (position <= 0) {
+ thread = db_default_thread;
+ } else
+ return(FALSE);
+ *threadp = thread;
+ return(TRUE);
+}
+
+/*
+ * check the default thread is still valid
+ * ( it is called in entering DDB session )
+ */
+void
+db_init_default_thread(void)
+{
+ if (db_lookup_thread(db_default_thread) < 0) {
+ db_default_thread = THREAD_NULL;
+ db_default_task = TASK_NULL;
+ } else
+ db_default_task = db_default_thread->task;
+}
+
+/*
+ * set or get default thread which is used when /t or :t option is specified
+ * in the command line
+ */
+/* ARGSUSED */
+void
+db_set_default_thread(
+ struct db_variable *vp,
+ db_expr_t *valuep,
+ int flag,
+ db_var_aux_param_t ap)
+{
+ thread_t thread;
+
+ if (flag != DB_VAR_SET) {
+ *valuep = (db_expr_t) db_default_thread;
+ return;
+ }
+ thread = (thread_t) *valuep;
+ if (thread != THREAD_NULL && !db_check_thread_address_valid(thread))
+ db_error(0);
+ /* NOTREACHED */
+ db_default_thread = thread;
+ if (thread)
+ db_default_task = thread->task;
+ return;
+}
+
+/*
+ * convert $taskXXX[.YYY] type DDB variable to task or thread address
+ */
+void
+db_get_task_thread(
+ struct db_variable *vp,
+ db_expr_t *valuep,
+ int flag,
+ db_var_aux_param_t ap)
+{
+ task_t task;
+ thread_t thread;
+
+ if (flag != DB_VAR_GET) {
+ db_error("Cannot set to $task variable\n");
+ /* NOTREACHED */
+ }
+ if ((task = db_lookup_task_id(ap->suffix[0])) == TASK_NULL) {
+ db_printf("no such task($task%d)\n", ap->suffix[0]);
+ db_error(0);
+ /* NOTREACHED */
+ }
+ if (ap->level <= 1) {
+ *valuep = (db_expr_t) task;
+ return;
+ }
+ if ((thread = db_lookup_thread_id(task, ap->suffix[1])) == THREAD_NULL){
+ db_printf("no such thread($task%d.%d)\n",
+ ap->suffix[0], ap->suffix[1]);
+ db_error(0);
+ /* NOTREACHED */
+ }
+ *valuep = (db_expr_t) thread;
+ return;
+}
+
+/*
+ * convert $mapXXX type DDB variable to map address
+ */
+void
+db_get_map(struct db_variable *vp,
+ db_expr_t *valuep,
+ int flag,
+ db_var_aux_param_t ap)
+{
+ task_t task;
+
+ if (flag != DB_VAR_GET) {
+ db_error("Cannot set to $map variable\n");
+ /* NOTREACHED */
+ }
+
+ if ((task = db_lookup_task_id(ap->suffix[0])) == TASK_NULL) {
+ db_printf("no such map($map%d)\n", ap->suffix[0]);
+ db_error(0);
+ /* NOTREACHED */
+ }
+
+ *valuep = (db_expr_t) task->map;
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_task_thread.h b/ddb/db_task_thread.h
new file mode 100644
index 0000000..55ab4f5
--- /dev/null
+++ b/ddb/db_task_thread.h
@@ -0,0 +1,73 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _DDB_DB_TASK_THREAD_H_
+#define _DDB_DB_TASK_THREAD_H_
+
+#include <ddb/db_variables.h>
+
+#include <kern/task.h>
+#include <kern/thread.h>
+
+#define db_current_task() \
+ ((current_thread())? current_thread()->task: TASK_NULL)
+#define db_target_space(thread, user_space) \
+ ((!(user_space))? TASK_NULL: \
+ (thread)? (thread)->task: db_current_task())
+#define db_is_current_task(task) \
+ ((task) == TASK_NULL || (task) == db_current_task())
+
+extern task_t db_default_task; /* default target task */
+extern thread_t db_default_thread; /* default target thread */
+
+extern int db_lookup_task(const task_t);
+extern int db_lookup_thread(const thread_t);
+extern int db_lookup_task_thread(const task_t, const thread_t);
+extern boolean_t db_check_thread_address_valid(const thread_t);
+extern boolean_t db_get_next_thread(thread_t *, int);
+extern void db_init_default_thread(void);
+
+extern void
+db_set_default_thread(
+ struct db_variable *vp,
+ db_expr_t *valuep,
+ int flag,
+ db_var_aux_param_t ap);
+
+extern void
+db_get_task_thread(
+ struct db_variable *vp,
+ db_expr_t *valuep,
+ int flag,
+ db_var_aux_param_t ap);
+
+extern void
+db_get_map(struct db_variable *vp,
+ db_expr_t *valuep,
+ int flag,
+ db_var_aux_param_t ap);
+
+#endif /* _DDB_DB_TASK_THREAD_H_ */
diff --git a/ddb/db_trap.c b/ddb/db_trap.c
new file mode 100644
index 0000000..cbb6bde
--- /dev/null
+++ b/ddb/db_trap.c
@@ -0,0 +1,115 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+/*
+ * Trap entry point to kernel debugger.
+ */
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+#include <machine/setjmp.h>
+#include <ddb/db_command.h>
+#include <ddb/db_access.h>
+#include <ddb/db_break.h>
+#include <ddb/db_examine.h>
+#include <ddb/db_output.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_trap.h>
+#include <ddb/db_run.h>
+#include <machine/db_interface.h>
+#include <kern/lock.h>
+
+
+extern jmp_buf_t *db_recover;
+
+extern int db_inst_count;
+extern int db_load_count;
+extern int db_store_count;
+
+void
+db_task_trap(
+ int type,
+ int code,
+ boolean_t user_space)
+{
+ jmp_buf_t db_jmpbuf;
+ jmp_buf_t *prev;
+ boolean_t bkpt;
+ boolean_t watchpt;
+ task_t task_space;
+
+ check_simple_locks_disable();
+
+ task_space = db_target_space(current_thread(), user_space);
+ bkpt = IS_BREAKPOINT_TRAP(type, code);
+ watchpt = IS_WATCHPOINT_TRAP(type, code);
+
+ db_init_default_thread();
+ db_check_breakpoint_valid();
+ if (db_stop_at_pc(&bkpt, task_space)) {
+ 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 ");
+ else if (watchpt)
+ db_printf("Watchpoint at ");
+ else
+ db_printf("Stopped at ");
+ db_dot = PC_REGS(DDB_REGS);
+
+ prev = db_recover;
+ if (_setjmp(db_recover = &db_jmpbuf) == 0)
+ db_print_loc_and_inst(db_dot, task_space);
+ else
+ db_printf("Trouble printing location %#X.\n", db_dot);
+
+ if (!bkpt && !watchpt && _setjmp(db_recover = &db_jmpbuf) == 0)
+ db_stack_trace_cmd(0, 0, -1, "");
+ db_recover = prev;
+
+ db_command_loop();
+ }
+
+ check_simple_locks_enable();
+ db_restart_at_pc(watchpt, task_space);
+}
+
+void
+db_trap(
+ int type,
+ int code)
+{
+ db_task_trap(type, code, !DB_VALID_KERN_ADDR(PC_REGS(DDB_REGS)));
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_trap.h b/ddb/db_trap.h
new file mode 100644
index 0000000..933fcd3
--- /dev/null
+++ b/ddb/db_trap.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Barry deFreese.
+ */
+
+#ifndef _DDB_DB_TRAP_H_
+#define _DDB_DB_TRAP_H_
+
+#include <sys/types.h>
+#include <machine/db_machdep.h>
+
+extern void db_task_trap (
+ int type,
+ int code,
+ boolean_t user_space);
+
+extern void db_trap (int type, int code);
+
+#endif /* _DDB_DB_TRAP_H_ */
diff --git a/ddb/db_variables.c b/ddb/db_variables.c
new file mode 100644
index 0000000..40f2d4d
--- /dev/null
+++ b/ddb/db_variables.c
@@ -0,0 +1,224 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_command.h>
+#include <ddb/db_examine.h>
+#include <ddb/db_expr.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_macro.h>
+
+extern unsigned long db_maxoff;
+
+extern db_expr_t db_radix;
+extern db_expr_t db_max_width;
+extern db_expr_t db_tab_stop_width;
+extern db_expr_t db_max_line;
+
+#define DB_NWORK 32 /* number of work variable */
+
+db_expr_t db_work[DB_NWORK]; /* work variable */
+
+struct db_variable db_vars[] = {
+ { "radix", &db_radix, FCN_NULL },
+ { "maxoff", (db_expr_t*)&db_maxoff, FCN_NULL },
+ { "maxwidth", &db_max_width, FCN_NULL },
+ { "tabstops", &db_tab_stop_width, FCN_NULL },
+ { "lines", &db_max_line, FCN_NULL },
+ { "thread", 0, db_set_default_thread },
+ { "task", 0, db_get_task_thread,
+ 1, 2, -1, -1 },
+ { "map", 0, db_get_map,
+ 1, 1, -1, -1 },
+ { "work", &db_work[0], FCN_NULL,
+ 1, 1, 0, DB_NWORK-1 },
+ { "arg", 0, db_arg_variable,
+ 1, 1, -1, -1 },
+};
+struct db_variable *db_evars = db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
+
+static const char *
+db_get_suffix(
+ const char *suffix,
+ short *suffix_value)
+{
+ int value;
+
+ for (value = 0; *suffix && *suffix != '.' && *suffix != ':'; suffix++) {
+ if (*suffix < '0' || *suffix > '9')
+ return(0);
+ value = value*10 + *suffix - '0';
+ }
+ *suffix_value = value;
+ if (*suffix == '.')
+ suffix++;
+ return(suffix);
+}
+
+static boolean_t
+db_cmp_variable_name(
+ struct db_variable *vp,
+ char *name,
+ const db_var_aux_param_t ap)
+{
+ char *var_np;
+ const char *np;
+ int level;
+
+ for (np = name, var_np = vp->name; *var_np; ) {
+ if (*np++ != *var_np++)
+ return(FALSE);
+ }
+ for (level = 0; *np && *np != ':' && level < vp->max_level; level++){
+ if ((np = db_get_suffix(np, &ap->suffix[level])) == 0)
+ return(FALSE);
+ }
+ if ((*np && *np != ':') || level < vp->min_level
+ || (level > 0 && (ap->suffix[0] < vp->low
+ || (vp->high >= 0 && ap->suffix[0] > vp->high))))
+ return(FALSE);
+ db_strcpy(ap->modif, (*np)? np+1: "");
+ ap->thread = (db_option(ap->modif, 't')?db_default_thread: THREAD_NULL);
+ ap->level = level;
+ return(TRUE);
+}
+
+static int
+db_find_variable(
+ struct db_variable **varp,
+ db_var_aux_param_t ap)
+{
+ int t;
+ struct db_variable *vp;
+
+ t = db_read_token();
+ if (t == tIDENT) {
+ for (vp = db_vars; vp < db_evars; vp++) {
+ if (db_cmp_variable_name(vp, db_tok_string, ap)) {
+ *varp = vp;
+ return (1);
+ }
+ }
+ for (vp = db_regs; vp < db_eregs; vp++) {
+ if (db_cmp_variable_name(vp, db_tok_string, ap)) {
+ *varp = vp;
+ return (1);
+ }
+ }
+ }
+ db_printf("Unknown variable \"$%s\"\n", db_tok_string);
+ db_error(0);
+ return (0);
+}
+
+int
+db_get_variable(db_expr_t *valuep)
+{
+ struct db_variable *vp;
+ struct db_var_aux_param aux_param;
+ char modif[TOK_STRING_SIZE];
+
+ aux_param.modif = modif;
+ if (!db_find_variable(&vp, &aux_param))
+ return (0);
+
+ db_read_write_variable(vp, valuep, DB_VAR_GET, &aux_param);
+
+ return (1);
+}
+
+void
+db_read_write_variable(
+ struct db_variable *vp,
+ db_expr_t *valuep,
+ int rw_flag,
+ db_var_aux_param_t ap)
+{
+ void (*func)(struct db_variable *, db_expr_t *, int, db_var_aux_param_t) = vp->fcn;
+ struct db_var_aux_param aux_param;
+
+ if (ap == 0) {
+ ap = &aux_param;
+ ap->modif = "";
+ ap->level = 0;
+ ap->thread = THREAD_NULL;
+ }
+ if (func == FCN_NULL) {
+ if (rw_flag == DB_VAR_SET)
+ vp->valuep[(ap->level)? (ap->suffix[0] - vp->low): 0] = *valuep;
+ else
+ *valuep = vp->valuep[(ap->level)? (ap->suffix[0] - vp->low): 0];
+ } else
+ (*func)(vp, valuep, rw_flag, ap);
+}
+
+void
+db_set_cmd(void)
+{
+ db_expr_t value;
+ int t;
+ struct db_variable *vp;
+ struct db_var_aux_param aux_param;
+ char modif[TOK_STRING_SIZE];
+
+ aux_param.modif = modif;
+ t = db_read_token();
+ if (t != tDOLLAR) {
+ db_error("Variable name should be prefixed with $\n");
+ return;
+ }
+ if (!db_find_variable(&vp, &aux_param)) {
+ 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 ((t = db_read_token()) == tSEMI_COLON)
+ db_unread_token(t);
+ else if (t != tEOL)
+ db_error("?\n");
+
+ db_read_write_variable(vp, &value, DB_VAR_SET, &aux_param);
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_variables.h b/ddb/db_variables.h
new file mode 100644
index 0000000..9880d50
--- /dev/null
+++ b/ddb/db_variables.h
@@ -0,0 +1,88 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#ifndef _DB_VARIABLES_H_
+#define _DB_VARIABLES_H_
+
+#include <kern/thread.h>
+#include <machine/db_machdep.h>
+
+/*
+ * Debugger variables.
+ */
+struct db_var_aux_param; /* forward */
+typedef struct db_var_aux_param *db_var_aux_param_t; /* forward */
+struct db_variable {
+ char *name; /* Name of variable */
+ db_expr_t *valuep; /* pointer to value of variable */
+ /* function to call when reading/writing */
+ void (*fcn)(struct db_variable *, db_expr_t *, int, db_var_aux_param_t);
+ short min_level; /* number of minimum suffix levels */
+ short max_level; /* number of maximum suffix levels */
+ short low; /* low value of level 1 suffix */
+ short high; /* high value of level 1 suffix */
+#define DB_VAR_GET 0
+#define DB_VAR_SET 1
+};
+#define FCN_NULL ((void (*)())0)
+
+#define DB_VAR_LEVEL 3 /* maximum number of suffix level */
+
+#define db_read_variable(vp, valuep) \
+ db_read_write_variable(vp, valuep, DB_VAR_GET, 0)
+#define db_write_variable(vp, valuep) \
+ db_read_write_variable(vp, valuep, DB_VAR_SET, 0)
+
+/*
+ * auxiliary parameters passed to a variable handler
+ */
+struct db_var_aux_param {
+ char *modif; /* option strings */
+ short level; /* number of levels */
+ short suffix[DB_VAR_LEVEL]; /* suffix */
+ thread_t thread; /* target task */
+};
+
+/* Already defined above. */
+/* typedef struct db_var_aux_param *db_var_aux_param_t; */
+
+
+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;
+
+extern int db_get_variable(db_expr_t *valuep);
+
+void db_set_cmd(void);
+
+void db_read_write_variable(struct db_variable *, db_expr_t *, int, struct db_var_aux_param *);
+
+#endif /* _DB_VARIABLES_H_ */
diff --git a/ddb/db_watch.c b/ddb/db_watch.c
new file mode 100644
index 0000000..c3d2835
--- /dev/null
+++ b/ddb/db_watch.c
@@ -0,0 +1,329 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: Richard P. Draves, Carnegie Mellon University
+ * Date: 10/90
+ */
+
+#if MACH_KDB
+
+#include <mach/boolean.h>
+#include <mach/vm_param.h>
+#include <mach/machine/vm_types.h>
+#include <mach/machine/vm_param.h>
+#include <vm/vm_map.h>
+
+#include <machine/db_machdep.h>
+#include <machine/db_interface.h>
+#include <ddb/db_command.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_watch.h>
+#include <ddb/db_access.h>
+#include <ddb/db_expr.h>
+#include <ddb/db_output.h>
+#include <ddb/db_run.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_task_thread.h>
+
+
+
+/*
+ * Watchpoints.
+ */
+
+boolean_t db_watchpoints_inserted = TRUE;
+
+#define NWATCHPOINTS 100
+struct db_watchpoint db_watch_table[NWATCHPOINTS];
+db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0];
+db_watchpoint_t db_free_watchpoints = 0;
+db_watchpoint_t db_watchpoint_list = 0;
+
+extern vm_map_t kernel_map;
+
+static db_watchpoint_t
+db_watchpoint_alloc(void)
+{
+ 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);
+}
+
+static void
+db_watchpoint_free(db_watchpoint_t watch)
+{
+ watch->link = db_free_watchpoints;
+ db_free_watchpoints = watch;
+}
+
+void
+db_set_watchpoint(
+ const task_t task,
+ db_addr_t addr,
+ vm_size_t size)
+{
+ db_watchpoint_t watch;
+
+ /*
+ * Should we do anything fancy with overlapping regions?
+ */
+
+ for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
+ if (watch->task == task &&
+ (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->task = task;
+ watch->loaddr = addr;
+ watch->hiaddr = addr+size;
+
+ watch->link = db_watchpoint_list;
+ db_watchpoint_list = watch;
+
+ db_watchpoints_inserted = FALSE;
+}
+
+void
+db_delete_watchpoint(const task_t task, db_addr_t addr)
+{
+ db_watchpoint_t watch;
+ db_watchpoint_t *prev;
+
+ for (prev = &db_watchpoint_list; (watch = *prev) != 0;
+ prev = &watch->link) {
+ if (watch->task == task &&
+ (watch->loaddr <= addr) &&
+ (addr < watch->hiaddr)) {
+ *prev = watch->link;
+ db_watchpoint_free(watch);
+ return;
+ }
+ }
+
+ db_printf("Not set.\n");
+}
+
+void
+db_list_watchpoints(void)
+{
+ db_watchpoint_t watch;
+ int task_id;
+
+ if (db_watchpoint_list == 0) {
+ db_printf("No watchpoints set\n");
+ return;
+ }
+
+ db_printf("Space Address Size\n");
+ for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
+ if (watch->task == TASK_NULL)
+ db_printf("kernel ");
+ else {
+ task_id = db_lookup_task(watch->task);
+ if (task_id < 0)
+ db_printf("%*X", 2*sizeof(vm_offset_t), watch->task);
+ else
+ db_printf("task%-3d ", task_id);
+ }
+ db_printf(" %*X %X\n", 2*sizeof(vm_offset_t), watch->loaddr,
+ watch->hiaddr - watch->loaddr);
+ }
+}
+
+static int
+db_get_task(const char *modif, task_t *taskp, db_addr_t addr)
+{
+ task_t task = TASK_NULL;
+ db_expr_t value;
+ boolean_t user_space;
+
+ user_space = db_option(modif, 'T');
+ if (user_space) {
+ if (db_expression(&value)) {
+ task = (task_t)value;
+ if (db_lookup_task(task) < 0) {
+ db_printf("bad task address %X\n", task);
+ return(-1);
+ }
+ } else {
+ task = db_default_task;
+ if (task == TASK_NULL) {
+ if ((task = db_current_task()) == TASK_NULL) {
+ db_printf("no task\n");
+ return(-1);
+ }
+ }
+ }
+ }
+ if (!DB_VALID_ADDRESS(addr, user_space)) {
+ db_printf("Address %#X is not in %s space\n", addr,
+ (user_space)? "user": "kernel");
+ return(-1);
+ }
+ *taskp = task;
+ return(0);
+}
+
+/* Delete watchpoint */
+/*ARGSUSED*/
+void
+db_deletewatch_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ task_t task;
+
+ if (db_get_task(modif, &task, addr) < 0)
+ return;
+ db_delete_watchpoint(task, addr);
+}
+
+/* Set watchpoint */
+/*ARGSUSED*/
+void
+db_watchpoint_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ vm_size_t size;
+ db_expr_t value;
+ task_t task;
+
+ if (db_get_task(modif, &task, addr) < 0)
+ return;
+ if (db_expression(&value))
+ size = (vm_size_t) value;
+ else
+ size = sizeof(int);
+ db_set_watchpoint(task, addr, size);
+}
+
+/* list watchpoints */
+void
+db_listwatch_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ db_list_watchpoints();
+}
+
+void
+db_set_watchpoints(void)
+{
+ db_watchpoint_t watch;
+ vm_map_t map;
+ unsigned hw_idx = 0;
+
+ if (!db_watchpoints_inserted) {
+ for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
+ if (db_set_hw_watchpoint(watch, hw_idx)) {
+ hw_idx++;
+ continue;
+ }
+ map = (watch->task)? watch->task->map: kernel_map;
+ pmap_protect(map->pmap,
+ trunc_page(watch->loaddr),
+ round_page(watch->hiaddr),
+ VM_PROT_READ);
+ }
+ db_watchpoints_inserted = TRUE;
+ }
+}
+
+void
+db_clear_watchpoints(void)
+{
+ unsigned hw_idx = 0;
+
+ while (db_clear_hw_watchpoint(hw_idx))
+ hw_idx++;
+
+ db_watchpoints_inserted = FALSE;
+}
+
+boolean_t
+db_find_watchpoint(
+ vm_map_t map,
+ db_addr_t addr,
+ db_regs_t *regs)
+{
+ db_watchpoint_t watch;
+ db_watchpoint_t found = 0;
+ task_t task_space;
+
+ task_space = (map == kernel_map)? TASK_NULL: db_current_task();
+ for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
+ if (watch->task == task_space) {
+ 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, task_space);
+ }
+
+ return (FALSE);
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_watch.h b/ddb/db_watch.h
new file mode 100644
index 0000000..86f07fb
--- /dev/null
+++ b/ddb/db_watch.h
@@ -0,0 +1,80 @@
+/*
+ * 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 10/90
+ */
+
+#if MACH_KDB
+
+#ifndef _DDB_DB_WATCH_
+#define _DDB_DB_WATCH_
+
+#include <mach/machine/vm_types.h>
+#include <kern/task.h>
+#include <machine/db_machdep.h>
+
+/*
+ * Watchpoint.
+ */
+
+typedef struct db_watchpoint {
+ task_t task; /* 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(void);
+extern void db_clear_watchpoints(void);
+
+extern void db_set_watchpoint(const task_t task, db_addr_t addr, vm_size_t size);
+extern void db_delete_watchpoint(const task_t task, db_addr_t addr);
+extern void db_list_watchpoints(void);
+
+void db_listwatch_cmd(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_deletewatch_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+void db_watchpoint_cmd(
+ db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ const char * modif);
+
+#endif /* _DDB_DB_WATCH_ */
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_write_cmd.c b/ddb/db_write_cmd.c
new file mode 100644
index 0000000..cfc2b70
--- /dev/null
+++ b/ddb/db_write_cmd.c
@@ -0,0 +1,111 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992,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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#if MACH_KDB
+
+#include <mach/boolean.h>
+#include <kern/task.h>
+#include <kern/thread.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+#include <ddb/db_expr.h>
+#include <ddb/db_output.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_write_cmd.h>
+
+
+
+/*
+ * Write to file.
+ */
+/*ARGSUSED*/
+void
+db_write_cmd(
+ db_expr_t address,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif)
+{
+ db_addr_t addr;
+ db_expr_t old_value;
+ db_expr_t new_value;
+ int size;
+ boolean_t wrote_one = FALSE;
+ boolean_t t_opt, u_opt;
+ thread_t thread;
+ task_t task;
+
+ addr = (db_addr_t) address;
+
+ size = db_size_option(modif, &u_opt, &t_opt);
+ if (t_opt)
+ {
+ if (!db_get_next_thread(&thread, 0))
+ return;
+ task = thread->task;
+ }
+ else
+ task = db_current_task();
+
+ /* if user space is not explicitly specified,
+ look in the kernel */
+ if (!u_opt)
+ task = TASK_NULL;
+
+ if (!DB_VALID_ADDRESS(addr, u_opt)) {
+ db_printf("Bad address %#*X\n", 2*sizeof(vm_offset_t), addr);
+ return;
+ }
+
+ while (db_expression(&new_value)) {
+ old_value = db_get_task_value(addr, size, FALSE, task);
+ db_task_printsym(addr, DB_STGY_ANY, task);
+ db_printf("\t\t%#*N\t=\t%#*N\n",
+ 2*sizeof(db_expr_t), old_value,
+ 2*sizeof(db_expr_t), new_value);
+ db_put_task_value(addr, size, new_value, task);
+ addr += size;
+
+ wrote_one = TRUE;
+ }
+
+ if (!wrote_one)
+ db_error("Nothing written.\n");
+
+ db_next = addr;
+ db_prev = addr - size;
+}
+
+#endif /* MACH_KDB */
diff --git a/ddb/db_write_cmd.h b/ddb/db_write_cmd.h
new file mode 100644
index 0000000..3a1d057
--- /dev/null
+++ b/ddb/db_write_cmd.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Free Software Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _DDB_DB_WRITE_CMD_H_
+#define _DDB_DB_WRITE_CMD_H_
+
+#include <mach/boolean.h>
+#include <machine/db_machdep.h>
+
+/* Prototypes for functions exported by this module.
+ */
+
+void db_write_cmd(
+ db_expr_t address,
+ boolean_t have_addr,
+ db_expr_t count,
+ const char * modif);
+
+#endif /* !_DDB_DB_WRITE_CMD_H_ */
diff --git a/ddb/nlist.h b/ddb/nlist.h
new file mode 100644
index 0000000..b948dfd
--- /dev/null
+++ b/ddb/nlist.h
@@ -0,0 +1,63 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 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 "AS IS"
+ * 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 Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * nlist.h - symbol table entry structure for an a.out file
+ * derived from FSF's a.out.gnu.h
+ *
+ */
+
+#ifndef _DDB_NLIST_H_
+#define _DDB_NLIST_H_
+
+struct nlist {
+ union n_un {
+ char *n_name; /* symbol name */
+ long n_strx; /* index into file string table */
+ } n_un;
+ unsigned char n_type; /* type flag, i.e. N_TEXT etc; see below */
+ unsigned char n_other; /* machdep uses */
+ short n_desc; /* see <stab.h> */
+#if alpha
+ int n_pad; /* alignment, used to carry framesize info */
+#endif
+ vm_offset_t n_value; /* value of this symbol (or sdb offset) */
+};
+
+/*
+ * Simple values for n_type.
+ */
+#define N_UNDF 0 /* undefined */
+#define N_ABS 2 /* absolute */
+#define N_TEXT 4 /* text */
+#define N_DATA 6 /* data */
+#define N_BSS 8 /* bss */
+#define N_FN 0x1f /* file name symbol */
+#define N_EXT 1 /* external bit, or'ed in */
+#define N_TYPE 0x1e /* mask for all the type bits */
+#define N_STAB 0xe0 /* if any of these bits set, a SDB entry */
+
+
+#endif /* _DDB_NLIST_H_ */
diff --git a/ddb/stab.h b/ddb/stab.h
new file mode 100644
index 0000000..55e9d45
--- /dev/null
+++ b/ddb/stab.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)stab.h 5.2 (Berkeley) 4/4/91
+ */
+
+#ifndef _DDB_STAB_H_
+#define _DDB_STAB_H_
+
+/*
+ * The following are symbols used by various debuggers and by the Pascal
+ * compiler. Each of them must have one (or more) of the bits defined by
+ * the N_STAB mask set.
+ */
+
+#define N_GSYM 0x20 /* global symbol */
+#define N_FNAME 0x22 /* F77 function name */
+#define N_FUN 0x24 /* procedure name */
+#define N_STSYM 0x26 /* data segment variable */
+#define N_LCSYM 0x28 /* bss segment variable */
+#define N_MAIN 0x2a /* main function name */
+#define N_PC 0x30 /* global Pascal symbol */
+#define N_FRAME 0x34 /* stack frame descriptor */
+#define N_RSYM 0x40 /* register variable */
+#define N_SLINE 0x44 /* text segment line number */
+#define N_DSLINE 0x46 /* data segment line number */
+#define N_BSLINE 0x48 /* bss segment line number */
+#define N_SSYM 0x60 /* structure/union element */
+#define N_SO 0x64 /* main source file name */
+#define N_LSYM 0x80 /* stack variable */
+#define N_BINCL 0x82 /* include file beginning */
+#define N_SOL 0x84 /* included source file name */
+#define N_PSYM 0xa0 /* parameter variable */
+#define N_EINCL 0xa2 /* include file end */
+#define N_ENTRY 0xa4 /* alternate entry point */
+#define N_LBRAC 0xc0 /* left bracket */
+#define N_EXCL 0xc2 /* deleted include file */
+#define N_RBRAC 0xe0 /* right bracket */
+#define N_BCOMM 0xe2 /* begin common */
+#define N_ECOMM 0xe4 /* end common */
+#define N_ECOML 0xe8 /* end common (local name) */
+#define N_LENG 0xfe /* length of preceding entry */
+
+#endif /* _DDB_STAB_H_ */
diff --git a/ddb/tr.h b/ddb/tr.h
new file mode 100644
index 0000000..2d058ca
--- /dev/null
+++ b/ddb/tr.h
@@ -0,0 +1,117 @@
+/*
+ * (c) Copyright 1992, 1993, 1994, 1995 OPEN SOFTWARE FOUNDATION, INC.
+ * ALL RIGHTS RESERVED
+ */
+/*
+ * OSF RI nmk19b2 5/2/95
+ */
+
+/*
+ * File: ddb/tr.h
+ * Author: Alan Langerman, Jeffrey Heller
+ * Date: 1992
+ *
+ * Internal trace routines. Like old-style XPRs but
+ * less formatting.
+ */
+
+#ifndef NDEBUG
+#define MACH_ASSERT 1
+#else
+#define MACH_ASSERT 0
+#endif
+
+#include <mach_tr.h>
+
+/*
+ * Originally, we only wanted tracing when
+ * MACH_TR and MACH_ASSERT were turned on
+ * together. Now, there's no reason why
+ * MACH_TR and MACH_ASSERT can't be completely
+ * orthogonal.
+ */
+#define TRACE_BUFFER (MACH_TR)
+
+/*
+ * Log events in a circular trace buffer for future debugging.
+ * Events are unsigned integers. Each event has a descriptive
+ * message.
+ *
+ * TR_DECL must be used at the beginning of a routine using
+ * one of the tr calls. The macro should be passed the name
+ * of the function surrounded by quotation marks, e.g.,
+ * TR_DECL("netipc_recv_intr");
+ * and should be terminated with a semi-colon. The TR_DECL
+ * must be the *last* declaration in the variable declaration
+ * list, or syntax errors will be introduced when TRACE_BUFFER
+ * is turned off.
+ */
+#ifndef _DDB_TR_H_
+#define _DDB_TR_H_
+
+#if TRACE_BUFFER
+
+#include <machine/db_machdep.h>
+
+#define __ui__ (unsigned int)
+#define TR_INIT() tr_init()
+#define TR_SHOW(a,b,c) show_tr((a),(b),(c))
+#define TR_DECL(funcname) char *__ntr_func_name__ = funcname
+#define tr1(msg) \
+ tr(__ntr_func_name__, __FILE__, __LINE__, (msg), \
+ 0,0,0,0)
+#define tr2(msg,tag1) \
+ tr(__ntr_func_name__, __FILE__, __LINE__, (msg), \
+ __ui__(tag1),0,0,0)
+#define tr3(msg,tag1,tag2) \
+ tr(__ntr_func_name__, __FILE__, __LINE__, (msg), \
+ __ui__(tag1),__ui__(tag2),0,0)
+#define tr4(msg,tag1,tag2,tag3) \
+ tr(__ntr_func_name__, __FILE__, __LINE__, (msg), \
+ __ui__(tag1),__ui__(tag2),__ui__(tag3),0)
+#define tr5(msg,tag1,tag2,tag3,tag4) \
+ tr(__ntr_func_name__, __FILE__, __LINE__, (msg), \
+ __ui__(tag1),__ui__(tag2),__ui__(tag3),__ui__(tag4))
+
+/*
+ * Adjust tr log indentation based on function
+ * call graph; this method is quick-and-dirty
+ * and only works safely on a uniprocessor.
+ */
+extern int tr_indent;
+#define tr_start() tr_indent++
+#define tr_stop() tr_indent--
+
+extern void tr_init(void);
+extern void tr(
+ char *funcname,
+ char *file,
+ unsigned int lineno,
+ char *fmt,
+ unsigned int tag1,
+ unsigned int tag2,
+ unsigned int tag3,
+ unsigned int tag4);
+
+extern void db_show_tr(
+ db_expr_t addr,
+ boolean_t have_addr,
+ db_expr_t count,
+ char * modif);
+
+#else /* TRACE_BUFFER */
+
+#define TR_INIT()
+#define TR_SHOW(a,b,c)
+#define TR_DECL(funcname)
+#define tr1(msg)
+#define tr2(msg, tag1)
+#define tr3(msg, tag1, tag2)
+#define tr4(msg, tag1, tag2, tag3)
+#define tr5(msg, tag1, tag2, tag3, tag4)
+#define tr_start()
+#define tr_stop()
+
+#endif /* TRACE_BUFFER */
+
+#endif /* _DDB_TR_H_ */