summaryrefslogtreecommitdiffstats
path: root/sys/ddb
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2004-07-10 23:47:20 +0000
committermarcel <marcel@FreeBSD.org>2004-07-10 23:47:20 +0000
commitaae5483213805c645aad67985fa4f638d6e34915 (patch)
tree533bc344dcaf70d30b9a52c0dc5327488516647b /sys/ddb
parent1dca995d693b9df1e65a294b6385cc1d442233b1 (diff)
downloadFreeBSD-src-aae5483213805c645aad67985fa4f638d6e34915.zip
FreeBSD-src-aae5483213805c645aad67985fa4f638d6e34915.tar.gz
Mega update for the KDB framework: turn DDB into a KDB backend.
Most of the changes are a direct result of adding thread awareness. Typically, DDB_REGS is gone. All registers are taken from the trapframe and backtraces use the PCB based contexts. DDB_REGS was defined to be a trapframe on all platforms anyway. Thread awareness introduces the following new commands: thread X switch to thread X (where X is the TID), show threads list all threads. The backtrace code has been made more flexible so that one can create backtraces for any thread by giving the thread ID as an argument to trace. With this change, ia64 has support for breakpoints.
Diffstat (limited to 'sys/ddb')
-rw-r--r--sys/ddb/db_access.c14
-rw-r--r--sys/ddb/db_break.c43
-rw-r--r--sys/ddb/db_command.c57
-rw-r--r--sys/ddb/db_main.c226
-rw-r--r--sys/ddb/db_output.c5
-rw-r--r--sys/ddb/db_print.c38
-rw-r--r--sys/ddb/db_ps.c26
-rw-r--r--sys/ddb/db_run.c66
-rw-r--r--sys/ddb/db_thread.c105
-rw-r--r--sys/ddb/db_variables.c121
-rw-r--r--sys/ddb/db_variables.h3
-rw-r--r--sys/ddb/ddb.h42
12 files changed, 455 insertions, 291 deletions
diff --git a/sys/ddb/db_access.c b/sys/ddb/db_access.c
index 15545de..d8224ad 100644
--- a/sys/ddb/db_access.c
+++ b/sys/ddb/db_access.c
@@ -32,6 +32,7 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/kdb.h>
#include <ddb/ddb.h>
#include <ddb/db_access.h>
@@ -58,7 +59,11 @@ db_get_value(addr, size, is_signed)
register db_expr_t value;
register int i;
- db_read_bytes(addr, size, data);
+ if (db_read_bytes(addr, size, data) != 0) {
+ db_printf("*** error reading from address %llx ***\n",
+ (long long)addr);
+ kdb_reenter();
+ }
value = 0;
#if BYTE_MSF
@@ -96,6 +101,9 @@ db_put_value(addr, size, value)
value >>= 8;
}
- db_write_bytes(addr, size, data);
+ if (db_write_bytes(addr, size, data) != 0) {
+ db_printf("*** error writing to address %llx ***\n",
+ (long long)addr);
+ kdb_reenter();
+ }
}
-
diff --git a/sys/ddb/db_break.c b/sys/ddb/db_break.c
index 577e338..78f4f4f 100644
--- a/sys/ddb/db_break.c
+++ b/sys/ddb/db_break.c
@@ -367,46 +367,3 @@ db_map_addr(addr)
#endif
return kernel_map;
}
-
-#ifdef ALT_BREAK_TO_DEBUGGER
-/*
- * Solaris implements a new BREAK which is initiated by a character sequence
- * CR ~ ^b which is similar to a familiar pattern used on Sun servers by the
- * Remote Console.
- *
- * Note that this function may be called from almost anywhere, with interrupts
- * disabled and with unknown locks held, so it must not access data other than
- * its arguments. Its up to the caller to ensure that the state variable is
- * consistent.
- */
-
-#define KEY_CR 13 /* CR '\r' */
-#define KEY_TILDE 126 /* ~ */
-#define KEY_CRTLB 2 /* ^B */
-
-int
-db_alt_break(int data, int *state)
-{
- int brk = 0;
-
- switch (data) {
- case KEY_CR:
- *state = KEY_TILDE;
- break;
- case KEY_TILDE:
- if (*state == KEY_TILDE)
- *state = KEY_CRTLB;
- else
- *state = 0;
- break;
- case KEY_CRTLB:
- if (*state == KEY_CRTLB)
- brk = 1;
- /* FALLTHROUGH */
- default:
- *state = 0;
- break;
- }
- return (brk);
-}
-#endif
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c
index 70b3556..954a0d3 100644
--- a/sys/ddb/db_command.c
+++ b/sys/ddb/db_command.c
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/linker_set.h>
#include <sys/lock.h>
+#include <sys/kdb.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/reboot.h>
@@ -58,7 +59,6 @@ __FBSDID("$FreeBSD$");
*/
boolean_t db_cmd_loop_done;
db_addr_t db_dot;
-jmp_buf db_jmpbuf;
db_addr_t db_last_addr;
db_addr_t db_prev;
db_addr_t db_next;
@@ -67,7 +67,6 @@ SET_DECLARE(db_cmd_set, struct command);
SET_DECLARE(db_show_cmd_set, struct command);
static db_cmdfcn_t db_fncall;
-static db_cmdfcn_t db_gdb;
static db_cmdfcn_t db_kill;
static db_cmdfcn_t db_reset;
static db_cmdfcn_t db_watchdog;
@@ -375,9 +374,6 @@ db_command(last_cmdp, cmd_table, aux_cmd_tablep, aux_cmd_tablep_end)
*/
static struct command db_show_all_cmds[] = {
-#if 0
- { "threads", db_show_all_threads, 0, 0 },
-#endif
{ "procs", db_ps, 0, 0 },
{ (char *)0 }
};
@@ -386,10 +382,7 @@ static struct command db_show_cmds[] = {
{ "all", 0, 0, db_show_all_cmds },
{ "registers", db_show_regs, 0, 0 },
{ "breaks", db_listbreak_cmd, 0, 0 },
- { "thread", db_show_one_thread, 0, 0 },
-#if 0
- { "port", ipc_port_print, 0, 0 },
-#endif
+ { "threads", db_show_threads, 0, 0 },
{ (char *)0, }
};
@@ -421,29 +414,15 @@ static struct command db_command_table[] = {
{ "call", db_fncall, CS_OWN, 0 },
{ "show", 0, 0, db_show_cmds },
{ "ps", db_ps, 0, 0 },
- { "gdb", db_gdb, 0, 0 },
{ "reset", db_reset, 0, 0 },
{ "kill", db_kill, CS_OWN, 0 },
{ "watchdog", db_watchdog, 0, 0 },
+ { "thread", db_set_thread, CS_OWN, 0 },
{ (char *)0, }
};
static struct command *db_last_command = 0;
-#if 0
-void
-db_help_cmd()
-{
- struct command *cmd = db_command_table;
-
- while (cmd->name != 0) {
- db_printf("%-12s", cmd->name);
- db_end_line();
- cmd++;
- }
-}
-#endif
-
/*
* At least one non-optional command must be implemented using
* DB_COMMAND() so that db_cmd_set gets created. Here is one.
@@ -464,8 +443,6 @@ db_command_loop()
db_cmd_loop_done = 0;
while (!db_cmd_loop_done) {
-
- (void) setjmp(db_jmpbuf);
if (db_print_position() != 0)
db_printf("\n");
@@ -484,7 +461,7 @@ db_error(s)
if (s)
db_printf("%s", s);
db_flush_lex();
- longjmp(db_jmpbuf, 1);
+ kdb_reenter();
}
@@ -553,32 +530,6 @@ db_fncall(dummy1, dummy2, dummy3, dummy4)
db_printf("%#lr\n", (long)retval);
}
-/* Enter GDB remote protocol debugger on the next trap. */
-
-void *gdb_arg = NULL;
-cn_getc_t *gdb_getc;
-cn_putc_t *gdb_putc;
-
-static void
-db_gdb (dummy1, dummy2, dummy3, dummy4)
- db_expr_t dummy1;
- boolean_t dummy2;
- db_expr_t dummy3;
- char * dummy4;
-{
-
- if (gdb_arg == NULL) {
- db_printf("No gdb port enabled. Set flag 0x80 on desired port\n");
- db_printf("in your configuration file (currently sio only).\n");
- return;
- }
- boothowto ^= RB_GDB;
-
- db_printf("Next trap will enter %s\n",
- boothowto & RB_GDB ? "GDB remote protocol mode"
- : "DDB debugger");
-}
-
static void
db_kill(dummy1, dummy2, dummy3, dummy4)
db_expr_t dummy1;
diff --git a/sys/ddb/db_main.c b/sys/ddb/db_main.c
new file mode 100644
index 0000000..32dd347
--- /dev/null
+++ b/sys/ddb/db_main.c
@@ -0,0 +1,226 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/cons.h>
+#include <sys/linker.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/reboot.h>
+
+#include <machine/kdb.h>
+#include <machine/pcb.h>
+#include <machine/setjmp.h>
+
+#include <ddb/ddb.h>
+#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
+
+static dbbe_init_f db_init;
+static dbbe_trap_f db_trap;
+
+KDB_BACKEND(ddb, db_init, db_trace_self, db_trap);
+
+vm_offset_t ksym_start, ksym_end;
+
+boolean_t
+X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line,
+ db_expr_t off)
+{
+ return (FALSE);
+}
+
+c_db_sym_t
+X_db_lookup(db_symtab_t *symtab, const char *symbol)
+{
+ c_linker_sym_t lsym;
+ Elf_Sym *sym;
+
+ if (symtab->private == NULL) {
+ return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym))
+ ? lsym : NULL));
+ } else {
+ sym = (Elf_Sym *)symtab->start;
+ while ((char *)sym < symtab->end) {
+ if (sym->st_name != 0 &&
+ !strcmp(symtab->private + sym->st_name, symbol))
+ return ((c_db_sym_t)sym);
+ sym++;
+ }
+ }
+ return (NULL);
+}
+
+c_db_sym_t
+X_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat,
+ db_expr_t *diffp)
+{
+ c_linker_sym_t lsym;
+ Elf_Sym *sym, *match;
+ unsigned long diff;
+
+ if (symtab->private == NULL) {
+ if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) {
+ *diffp = (db_expr_t)diff;
+ return ((c_db_sym_t)lsym);
+ }
+ return (NULL);
+ }
+
+ diff = ~0UL;
+ match = NULL;
+ for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) {
+ if (sym->st_name == 0)
+ continue;
+ if (off < sym->st_value)
+ continue;
+ if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT &&
+ ELF_ST_TYPE(sym->st_info) != STT_FUNC &&
+ ELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
+ continue;
+ if ((off - sym->st_value) > diff)
+ continue;
+ if ((off - sym->st_value) < diff) {
+ diff = off - sym->st_value;
+ match = sym;
+ } else {
+ if (match == NULL)
+ match = sym;
+ else if (ELF_ST_BIND(match->st_info) == STB_LOCAL &&
+ ELF_ST_BIND(sym->st_info) != STB_LOCAL)
+ match = sym;
+ }
+ if (diff == 0) {
+ if (strat == DB_STGY_PROC &&
+ ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
+ ELF_ST_BIND(sym->st_info) != STB_LOCAL)
+ break;
+ if (strat == DB_STGY_ANY &&
+ ELF_ST_BIND(sym->st_info) != STB_LOCAL)
+ break;
+ }
+ }
+
+ *diffp = (match == NULL) ? off : diff;
+ return ((c_db_sym_t)match);
+}
+
+boolean_t
+X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp,
+ char **argp)
+{
+ return (FALSE);
+}
+
+void
+X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep,
+ db_expr_t *valp)
+{
+ linker_symval_t lval;
+
+ if (symtab->private == NULL) {
+ linker_ddb_symbol_values((c_linker_sym_t)sym, &lval);
+ if (namep != NULL)
+ *namep = (const char*)lval.name;
+ if (valp != NULL)
+ *valp = (db_expr_t)lval.value;
+ } else {
+ if (namep != NULL)
+ *namep = (const char *)symtab->private +
+ ((const Elf_Sym *)sym)->st_name;
+ if (valp != NULL)
+ *valp = (db_expr_t)((const Elf_Sym *)sym)->st_value;
+ }
+}
+
+static int
+db_init(void)
+{
+ uintptr_t symtab, strtab;
+ Elf_Size tabsz, strsz;
+
+ if (ksym_end > ksym_start && ksym_start != 0) {
+ symtab = ksym_start;
+ tabsz = *((Elf_Size*)symtab)++;
+ strtab = symtab + tabsz;
+ strsz = *((Elf_Size*)strtab)++;
+ if (strtab + strsz <= ksym_end) {
+ db_add_symbol_table((char *)symtab,
+ (char *)(symtab + tabsz), "elf", (char *)strtab);
+ }
+ }
+ db_add_symbol_table(NULL, NULL, "kld", NULL);
+ return (1); /* We're the default debugger. */
+}
+
+static int
+db_trap(int type, int code)
+{
+ jmp_buf jb;
+ void *prev_jb;
+ boolean_t bkpt, watchpt;
+
+ /*
+ * Don't handle the trap if the console is unavailable (i.e. it
+ * is in graphics mode).
+ */
+ if (cnunavailable())
+ return (0);
+
+ bkpt = IS_BREAKPOINT_TRAP(type, code);
+ watchpt = IS_WATCHPOINT_TRAP(type, code);
+
+ if (db_stop_at_pc(&bkpt)) {
+ if (db_inst_count) {
+ db_printf("After %d instructions (%d loads, %d stores),\n",
+ db_inst_count, db_load_count, db_store_count);
+ }
+ prev_jb = kdb_jmpbuf(jb);
+ if (setjmp(jb) == 0) {
+ db_dot = PC_REGS();
+ db_print_thread();
+ if (bkpt)
+ db_printf("Breakpoint at\t");
+ else if (watchpt)
+ db_printf("Watchpoint at\t");
+ else
+ db_printf("Stopped at\t");
+ db_print_loc_and_inst(db_dot);
+ }
+ db_command_loop();
+ (void)kdb_jmpbuf(prev_jb);
+ }
+
+ db_restart_at_pc(watchpt);
+
+ return (1);
+}
diff --git a/sys/ddb/db_output.c b/sys/ddb/db_output.c
index 464d9162..ff2734c 100644
--- a/sys/ddb/db_output.c
+++ b/sys/ddb/db_output.c
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cons.h>
+#include <sys/kdb.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
@@ -112,9 +113,9 @@ db_putchar(c, arg)
* If not in the debugger or the user requests it, output data to
* both the console and the message buffer.
*/
- if (!db_active || ddb_use_printf) {
+ if (!kdb_active || ddb_use_printf) {
printf("%c", c);
- if (!db_active)
+ if (!kdb_active)
return;
if (c == '\r' || c == '\n')
db_check_interrupt();
diff --git a/sys/ddb/db_print.c b/sys/ddb/db_print.c
index 60282ad..b173c8c 100644
--- a/sys/ddb/db_print.c
+++ b/sys/ddb/db_print.c
@@ -37,33 +37,33 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/kdb.h>
+
+#include <machine/pcb.h>
#include <ddb/ddb.h>
#include <ddb/db_variables.h>
#include <ddb/db_sym.h>
void
-db_show_regs(dummy1, dummy2, dummy3, dummy4)
- db_expr_t dummy1;
- boolean_t dummy2;
- db_expr_t dummy3;
- char * dummy4;
+db_show_regs(db_expr_t _1, boolean_t _2, db_expr_t _3, char *_4)
{
- register struct db_variable *regp;
- db_expr_t value, offset;
- const char * name;
+ struct db_variable *regp;
+ db_expr_t value, offset;
+ const char *name;
for (regp = db_regs; regp < db_eregs; regp++) {
- db_read_variable(regp, &value);
- db_printf("%-12s%#10lr", regp->name, (unsigned long)value);
- db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset);
- if (name != NULL && offset <= (unsigned long)db_maxoff &&
- offset != value) {
- db_printf("\t%s", name);
- if (offset != 0)
- db_printf("+%+#lr", (long)offset);
- }
- db_printf("\n");
+ if (!db_read_variable(regp, &value))
+ continue;
+ db_printf("%-12s%#10lr", regp->name, (unsigned long)value);
+ db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset);
+ if (name != NULL && offset <= (unsigned long)db_maxoff &&
+ offset != value) {
+ db_printf("\t%s", name);
+ if (offset != 0)
+ db_printf("+%+#lr", (long)offset);
+ }
+ db_printf("\n");
}
- db_print_loc_and_inst(PC_REGS(DDB_REGS));
+ db_print_loc_and_inst(PC_REGS());
}
diff --git a/sys/ddb/db_ps.c b/sys/ddb/db_ps.c
index f146cb3..47d4c7d 100644
--- a/sys/ddb/db_ps.c
+++ b/sys/ddb/db_ps.c
@@ -166,29 +166,3 @@ dumpthread(volatile struct proc *p, volatile struct thread *td)
} else
db_printf(" %s\n", p->p_comm);
}
-
-
-#define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK)
-void
-db_show_one_thread(db_expr_t addr, boolean_t have_addr,
- db_expr_t count, char *modif)
-{
- struct proc *p;
- struct thread *td;
-
- if (!have_addr)
- td = curthread;
- else if (!INKERNEL(addr)) {
- printf("bad thread address");
- return;
- } else
- td = (struct thread *)addr;
- /* quick sanity check */
- if ((p = td->td_proc) != td->td_ksegrp->kg_proc)
- return;
- printf("Proc %p ",p);
- dumpthread(p, td);
-#ifdef __i386__
- db_stack_thread((db_expr_t)td, 1, count, modif);
-#endif
-}
diff --git a/sys/ddb/db_run.c b/sys/ddb/db_run.c
index 79b148a..ab589d3 100644
--- a/sys/ddb/db_run.c
+++ b/sys/ddb/db_run.c
@@ -36,6 +36,10 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/kdb.h>
+
+#include <machine/kdb.h>
+#include <machine/pcb.h>
#include <vm/vm.h>
@@ -61,14 +65,10 @@ int db_load_count;
int db_store_count;
#ifndef db_set_single_step
-extern void db_set_single_step(db_regs_t *regs);
+void db_set_single_step(void);
#endif
#ifndef db_clear_single_step
-extern void db_clear_single_step(db_regs_t *regs);
-#endif
-
-#ifdef notused
-static void db_single_step(db_regs_t *regs);
+void db_clear_single_step(void);
#endif
boolean_t
@@ -78,10 +78,10 @@ db_stop_at_pc(is_breakpoint)
register db_addr_t pc;
register db_breakpoint_t bkpt;
- db_clear_single_step(DDB_REGS);
+ db_clear_single_step();
db_clear_breakpoints();
db_clear_watchpoints();
- pc = PC_REGS(DDB_REGS);
+ pc = PC_REGS();
#ifdef FIXUP_PC_AFTER_BREAK
if (*is_breakpoint) {
@@ -90,7 +90,7 @@ db_stop_at_pc(is_breakpoint)
* machine requires it.
*/
FIXUP_PC_AFTER_BREAK
- pc = PC_REGS(DDB_REGS);
+ pc = PC_REGS();
}
#endif
@@ -171,7 +171,7 @@ void
db_restart_at_pc(watchpt)
boolean_t watchpt;
{
- register db_addr_t pc = PC_REGS(DDB_REGS);
+ register db_addr_t pc = PC_REGS();
if ((db_run_mode == STEP_COUNT) ||
(db_run_mode == STEP_RETURN) ||
@@ -205,28 +205,16 @@ db_restart_at_pc(watchpt)
* Step over breakpoint/watchpoint.
*/
db_run_mode = STEP_INVISIBLE;
- db_set_single_step(DDB_REGS);
+ db_set_single_step();
} else {
db_set_breakpoints();
db_set_watchpoints();
}
} else {
- db_set_single_step(DDB_REGS);
+ db_set_single_step();
}
}
-#ifdef notused
-static void
-db_single_step(regs)
- db_regs_t *regs;
-{
- if (db_run_mode == STEP_CONTINUE) {
- db_run_mode = STEP_INVISIBLE;
- db_set_single_step(regs);
- }
-}
-#endif
-
#ifdef SOFTWARE_SSTEP
/*
* Software implementation of single-stepping.
@@ -261,11 +249,10 @@ db_breakpoint_t db_not_taken_bkpt = 0;
db_breakpoint_t db_taken_bkpt = 0;
void
-db_set_single_step(regs)
- register db_regs_t *regs;
+db_set_single_step(void)
{
- db_addr_t pc = PC_REGS(regs), brpc;
- unsigned inst;
+ db_addr_t pc = PC_REGS(), brpc;
+ unsigned inst;
/*
* User was stopped at pc, e.g. the instruction
@@ -273,28 +260,27 @@ db_set_single_step(regs)
*/
inst = db_get_value(pc, sizeof(int), FALSE);
if (inst_branch(inst) || inst_call(inst)) {
- brpc = branch_taken(inst, pc, regs);
- if (brpc != pc) { /* self-branches are hopeless */
- db_taken_bkpt = db_set_temp_breakpoint(brpc);
- }
- pc = next_instr_address(pc,1);
+ brpc = branch_taken(inst, pc);
+ if (brpc != pc) { /* self-branches are hopeless */
+ db_taken_bkpt = db_set_temp_breakpoint(brpc);
+ }
+ pc = next_instr_address(pc, 1);
}
- pc = next_instr_address(pc,0);
+ pc = next_instr_address(pc, 0);
db_not_taken_bkpt = db_set_temp_breakpoint(pc);
}
void
-db_clear_single_step(regs)
- db_regs_t *regs;
+db_clear_single_step(void)
{
if (db_not_taken_bkpt != 0) {
- db_delete_temp_breakpoint(db_not_taken_bkpt);
- db_not_taken_bkpt = 0;
+ db_delete_temp_breakpoint(db_not_taken_bkpt);
+ db_not_taken_bkpt = 0;
}
if (db_taken_bkpt != 0) {
- db_delete_temp_breakpoint(db_taken_bkpt);
- db_taken_bkpt = 0;
+ db_delete_temp_breakpoint(db_taken_bkpt);
+ db_taken_bkpt = 0;
}
}
diff --git a/sys/ddb/db_thread.c b/sys/ddb/db_thread.c
new file mode 100644
index 0000000..b58f0b0
--- /dev/null
+++ b/sys/ddb/db_thread.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kdb.h>
+#include <sys/proc.h>
+
+#include <machine/pcb.h>
+
+#include <ddb/ddb.h>
+#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
+
+void
+db_print_thread(void)
+{
+ db_printf("[thread %ld]\n", (long)kdb_thread->td_tid);
+}
+
+void
+db_set_thread(db_expr_t tid, boolean_t hastid, db_expr_t cnt, char *mod)
+{
+ struct thread *thr;
+ db_expr_t radix;
+ int err;
+
+ /*
+ * We parse our own arguments. We don't like the default radix.
+ */
+ radix = db_radix;
+ db_radix = 10;
+ hastid = db_expression(&tid);
+ db_radix = radix;
+ db_skip_to_eol();
+
+ if (hastid) {
+ thr = kdb_thr_lookup(tid);
+ if (thr != NULL) {
+ err = kdb_thr_select(thr);
+ if (err != 0) {
+ db_printf("unable to switch to thread %ld\n",
+ (long)thr->td_tid);
+ return;
+ }
+ db_dot = PC_REGS();
+ } else {
+ db_printf("%d: invalid thread\n", (int)tid);
+ return;
+ }
+ }
+
+ db_print_thread();
+ db_print_loc_and_inst(PC_REGS());
+}
+
+void
+db_show_threads(db_expr_t addr, boolean_t hasaddr, db_expr_t cnt, char *mod)
+{
+ jmp_buf jb;
+ void *prev_jb;
+ struct thread *thr;
+ int pager_quit;
+
+ db_setup_paging(db_simple_pager, &pager_quit, DB_LINES_PER_PAGE);
+
+ pager_quit = 0;
+ thr = kdb_thr_first();
+ while (!pager_quit && thr != NULL) {
+ db_printf(" %6ld (%p) ", (long)thr->td_tid, thr);
+ prev_jb = kdb_jmpbuf(jb);
+ if (setjmp(jb) == 0) {
+ if (db_trace_thread(thr, 1) != 0)
+ db_printf("***\n");
+ }
+ kdb_jmpbuf(prev_jb);
+ thr = kdb_thr_next(thr);
+ }
+}
diff --git a/sys/ddb/db_variables.c b/sys/ddb/db_variables.c
index 1b28376..cf8e2e7 100644
--- a/sys/ddb/db_variables.c
+++ b/sys/ddb/db_variables.c
@@ -39,11 +39,6 @@ __FBSDID("$FreeBSD$");
#include <ddb/db_variables.h>
static int db_find_variable(struct db_variable **varp);
-static void db_write_variable(struct db_variable *, db_expr_t *);
-
-#ifdef notused
-static int db_set_variable(db_expr_t value);
-#endif
static struct db_variable db_vars[] = {
{ "radix", &db_radix, FCN_NULL },
@@ -51,123 +46,107 @@ static struct db_variable db_vars[] = {
{ "maxwidth", &db_max_width, FCN_NULL },
{ "tabstops", &db_tab_stop_width, FCN_NULL },
};
-static struct db_variable *db_evars =
- db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
+static struct db_variable *db_evars =
+ db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
static int
-db_find_variable(varp)
- struct db_variable **varp;
+db_find_variable(struct db_variable **varp)
{
- int t;
struct db_variable *vp;
+ int t;
t = db_read_token();
if (t == tIDENT) {
- for (vp = db_vars; vp < db_evars; vp++) {
- if (!strcmp(db_tok_string, vp->name)) {
- *varp = vp;
- return (1);
+ for (vp = db_vars; vp < db_evars; vp++) {
+ if (!strcmp(db_tok_string, vp->name)) {
+ *varp = vp;
+ return (1);
+ }
}
- }
- for (vp = db_regs; vp < db_eregs; vp++) {
- if (!strcmp(db_tok_string, vp->name)) {
- *varp = vp;
- return (1);
+ for (vp = db_regs; vp < db_eregs; vp++) {
+ if (!strcmp(db_tok_string, vp->name)) {
+ *varp = vp;
+ return (1);
+ }
}
- }
}
db_error("Unknown variable\n");
return (0);
}
int
-db_get_variable(valuep)
- db_expr_t *valuep;
+db_get_variable(db_expr_t *valuep)
{
struct db_variable *vp;
if (!db_find_variable(&vp))
- return (0);
-
- db_read_variable(vp, valuep);
+ return (0);
- return (1);
+ return (db_read_variable(vp, valuep));
}
-#ifdef notused
-static int
-db_set_variable(value)
- db_expr_t value;
+int
+db_set_variable(db_expr_t value)
{
struct db_variable *vp;
if (!db_find_variable(&vp))
- return (0);
+ return (0);
- db_write_variable(vp, &value);
-
- return (1);
+ return (db_write_variable(vp, value));
}
-#endif
-void
-db_read_variable(vp, valuep)
- struct db_variable *vp;
- db_expr_t *valuep;
+int
+db_read_variable(struct db_variable *vp, db_expr_t *valuep)
{
- db_varfcn_t *func = vp->fcn;
+ db_varfcn_t *func = vp->fcn;
- if (func == FCN_NULL)
- *valuep = *(vp->valuep);
- else
- (*func)(vp, valuep, DB_VAR_GET);
+ if (func == FCN_NULL) {
+ *valuep = *(vp->valuep);
+ return (1);
+ }
+ return ((*func)(vp, valuep, DB_VAR_GET));
}
-static void
-db_write_variable(vp, valuep)
- struct db_variable *vp;
- db_expr_t *valuep;
+int
+db_write_variable(struct db_variable *vp, db_expr_t value)
{
- db_varfcn_t *func = vp->fcn;
+ db_varfcn_t *func = vp->fcn;
- if (func == FCN_NULL)
- *(vp->valuep) = *valuep;
- else
- (*func)(vp, valuep, DB_VAR_SET);
+ if (func == FCN_NULL) {
+ *(vp->valuep) = value;
+ return (1);
+ }
+ return ((*func)(vp, &value, DB_VAR_SET));
}
void
-db_set_cmd(dummy1, dummy2, dummy3, dummy4)
- db_expr_t dummy1;
- boolean_t dummy2;
- db_expr_t dummy3;
- char * dummy4;
+db_set_cmd(db_expr_t dummy1, boolean_t dummy2, db_expr_t dummy3, char *dummy4)
{
- db_expr_t value;
struct db_variable *vp;
- int t;
+ db_expr_t value;
+ int t;
t = db_read_token();
if (t != tDOLLAR) {
- db_error("Unknown variable\n");
- return;
+ db_error("Unknown variable\n");
+ return;
}
if (!db_find_variable(&vp)) {
- db_error("Unknown variable\n");
- return;
+ db_error("Unknown variable\n");
+ return;
}
t = db_read_token();
if (t != tEQ)
- db_unread_token(t);
+ db_unread_token(t);
if (!db_expression(&value)) {
- db_error("No value\n");
- return;
- }
- if (db_read_token() != tEOL) {
- db_error("?\n");
+ db_error("No value\n");
+ return;
}
+ if (db_read_token() != tEOL)
+ db_error("?\n");
- db_write_variable(vp, &value);
+ db_write_variable(vp, value);
}
diff --git a/sys/ddb/db_variables.h b/sys/ddb/db_variables.h
index 6c05118..7f7a463 100644
--- a/sys/ddb/db_variables.h
+++ b/sys/ddb/db_variables.h
@@ -52,6 +52,7 @@ struct db_variable {
extern struct db_variable db_regs[]; /* machine registers */
extern struct db_variable *db_eregs;
-void db_read_variable(struct db_variable *, db_expr_t *);
+int db_read_variable(struct db_variable *, db_expr_t *);
+int db_write_variable(struct db_variable *, db_expr_t);
#endif /* _!DDB_DB_VARIABLES_H_ */
diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h
index 1ef452c..c1ffff9 100644
--- a/sys/ddb/ddb.h
+++ b/sys/ddb/ddb.h
@@ -69,9 +69,7 @@ func_name(addr, have_addr, count, modif) \
db_expr_t count; \
char *modif;
-extern char *esym;
extern db_expr_t db_maxoff;
-extern int db_active;
extern int db_indent;
extern int db_inst_count;
extern int db_load_count;
@@ -81,11 +79,9 @@ extern db_expr_t db_radix;
extern db_expr_t db_max_width;
extern db_expr_t db_tab_stop_width;
+struct thread;
struct vm_map;
-#ifdef ALT_BREAK_TO_DEBUGGER
-int db_alt_break(int, int *);
-#endif
void db_check_interrupt(void);
void db_clear_watchpoints(void);
db_addr_t db_disasm(db_addr_t loc, boolean_t altfmt);
@@ -98,24 +94,23 @@ struct vm_map *db_map_addr(vm_offset_t);
boolean_t db_map_current(struct vm_map *);
boolean_t db_map_equal(struct vm_map *, struct vm_map *);
void db_print_loc_and_inst(db_addr_t loc);
+void db_print_thread(void);
void db_printf(const char *fmt, ...) __printflike(1, 2);
-void db_read_bytes(vm_offset_t addr, size_t size, char *data);
+int db_read_bytes(vm_offset_t addr, size_t size, char *data);
/* machine-dependent */
int db_readline(char *lstart, int lsize);
void db_restart_at_pc(boolean_t watchpt);
+int db_set_variable(db_expr_t value);
void db_set_watchpoints(void);
void db_setup_paging(db_page_calloutfcn_t *callout, void *arg,
int maxlines);
void db_skip_to_eol(void);
boolean_t db_stop_at_pc(boolean_t *is_breakpoint);
#define db_strcpy strcpy
-void db_trap(int type, int code);
+void db_trace_self(void);
+int db_trace_thread(struct thread *, int);
int db_value_of_name(const char *name, db_expr_t *valuep);
-void db_write_bytes(vm_offset_t addr, size_t size, char *data);
- /* machine-dependent */
-void db_stack_thread(db_expr_t addr, boolean_t have_addr,
- db_expr_t count, char *modif);
-void kdb_init(void);
+int db_write_bytes(vm_offset_t addr, size_t size, char *data);
db_cmdfcn_t db_breakpoint_cmd;
db_cmdfcn_t db_continue_cmd;
@@ -129,27 +124,18 @@ db_cmdfcn_t db_print_cmd;
db_cmdfcn_t db_ps;
db_cmdfcn_t db_search_cmd;
db_cmdfcn_t db_set_cmd;
+db_cmdfcn_t db_set_thread;
db_cmdfcn_t db_show_regs;
+db_cmdfcn_t db_show_threads;
db_cmdfcn_t db_single_step_cmd;
db_cmdfcn_t db_stack_trace_cmd;
db_cmdfcn_t db_trace_until_call_cmd;
db_cmdfcn_t db_trace_until_matching_cmd;
db_cmdfcn_t db_watchpoint_cmd;
db_cmdfcn_t db_write_cmd;
-db_cmdfcn_t db_show_one_thread;
-
-#if 0
-db_cmdfcn_t db_help_cmd;
-db_cmdfcn_t db_show_all_threads;
-db_cmdfcn_t ipc_port_print;
-db_cmdfcn_t vm_page_print;
-#endif
db_page_calloutfcn_t db_simple_pager;
-/* Scare the user with backtrace of curthread to console. */
-void db_print_backtrace(void);
-
/*
* Command table.
*/
@@ -164,14 +150,4 @@ struct command {
struct command *more; /* another level of command */
};
-/* XXX: UGLY hack */
-#ifdef CN_DEAD
-/*
- * Routines to support GDB on an sio port.
- */
-extern void *gdb_arg;
-extern cn_getc_t *gdb_getc;
-extern cn_putc_t *gdb_putc;
-#endif
-
#endif /* !_DDB_DDB_H_ */
OpenPOWER on IntegriCloud