code:
/*	$OpenBSD: db_command.c,v 1.65 2015/03/14 03:38:46 jsg Exp $	*/
/*	$NetBSD: db_command.c,v 1.20 1996/03/30 22:30:05 christos Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993,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.
 */

/*
 * Command dispatcher.
 */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <sys/extent.h>
#include <sys/pool.h>
#include <sys/msgbuf.h>
#include <sys/malloc.h>
#include <sys/mount.h>

#include <uvm/uvm_extern.h>
#include <machine/db_machdep.h>		/* type definitions */

#include <ddb/db_lex.h>
#include <ddb/db_output.h>
#include <ddb/db_command.h>
#include <ddb/db_break.h>
#include <ddb/db_watch.h>
#include <ddb/db_run.h>
#include <ddb/db_variables.h>
#include <ddb/db_interface.h>
#include <ddb/db_extern.h>

#include <uvm/uvm_ddb.h>

/*
 * Exported global variables
 */
int		db_cmd_loop_done;
label_t		*db_recover;

/*
 * if 'ed' style: 'dot' is set at start of last item printed,
 * and '+' points to next line.
 * Otherwise: 'dot' points to next item, '..' points to last.
 */
boolean_t	db_ed_style = TRUE;

db_addr_t	db_dot;		/* current location */
db_addr_t	db_last_addr;	/* last explicit address typed */
db_addr_t	db_prev;	/* last address examined
				   or written */
db_addr_t	db_next;	/* next address to be examined
				   or written */

/*
 * Utility routine - discard tokens through end-of-line.
 */
void
db_skip_to_eol(void)
{
	int	t;
	do {
	    t = db_read_token();
	} while (t != tEOL);
}

/*
 * Results of command search.
 */
#define	CMD_UNIQUE	0
#define	CMD_FOUND	1
#define	CMD_NONE	2
#define	CMD_AMBIGUOUS	3

/*
 * Search for command prefix.
 */
int
db_cmd_search(char *name, struct db_command *table, struct db_command **cmdp)
{
	struct db_command	*cmd;
	int			result = CMD_NONE;

	for (cmd = table; cmd->name != 0; cmd++) {
	    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;
		}
	    }
	}
	return (result);
}

void
db_cmd_list(struct db_command *table)
{
	struct db_command *cmd;

	for (cmd = table; cmd->name != 0; cmd++) {
	    db_printf("%-12s", cmd->name);
	    db_end_line(12);
	}
}

void
db_command(struct db_command **last_cmdp, struct db_command *cmd_table)
{
	struct db_command	*cmd;
	int		t;
	char		modif[TOK_STRING_SIZE];
	db_expr_t	addr, count;
	boolean_t	have_addr = FALSE;
	int		result;

	t = db_read_token();
	if (t == tEOL) {
	    /* empty line repeats last command, at 'next' */
	    cmd = *last_cmdp;
	    addr = (db_expr_t)db_next;
	    have_addr = FALSE;
	    count = 1;
	    modif[0] = '\0';
	}
	else if (t == tEXCL) {
	    db_fncall(0, 0, 0, NULL);
	    return;
	}
	else if (t != tIDENT) {
	    db_printf("?\n");
	    db_flush_lex();
	    return;
	}
	else {
	    /*
	     * Search for command
	     */
	    while (cmd_table) {
		result = db_cmd_search(db_tok_string,
				       cmd_table,
				       &cmd);
		switch (result) {
		    case CMD_NONE:
			db_printf("No such command\n");
			db_flush_lex();
			return;
		    case CMD_AMBIGUOUS:
			db_printf("Ambiguous\n");
			db_flush_lex();
			return;
		    default:
			break;
		}
		if ((cmd_table = cmd->more) != 0) {
		    t = db_read_token();
		    if (t != tIDENT) {
			db_cmd_list(cmd_table);
			db_flush_lex();
			return;
		    }
		}
	    }

	    if ((cmd->flag & CS_OWN) == 0) {
		/*
		 * Standard syntax:
		 * command [/modifier] [addr] [,count]
		 */
		t = db_read_token();
		if (t == tSLASH) {
		    t = db_read_token();
		    if (t != tIDENT) {
			db_printf("Bad modifier\n");
			db_flush_lex();
			return;
		    }
		    db_strlcpy(modif, db_tok_string, sizeof(modif));
		}
		else {
		    db_unread_token(t);
		    modif[0] = '\0';
		}

		if (db_expression(&addr)) {
		    db_dot = (db_addr_t) addr;
		    db_last_addr = db_dot;
		    have_addr = TRUE;
		}
		else {
		    addr = (db_expr_t) db_dot;
		    have_addr = FALSE;
		}
		t = db_read_token();
		if (t == tCOMMA) {
		    if (!db_expression(&count)) {
			db_printf("Count missing\n");
			db_flush_lex();
			return;
		    }
		}
		else {
		    db_unread_token(t);
		    count = -1;
		}
		if ((cmd->flag & CS_MORE) == 0) {
		    db_skip_to_eol();
		}
	    }
	}
	*last_cmdp = cmd;
	if (cmd != 0) {
	    /*
	     * Execute the command.
	     */
	    (*cmd->fcn)(addr, have_addr, count, modif);

	    if (cmd->flag & CS_SET_DOT) {
		/*
		 * If command changes dot, set dot to
		 * previous address displayed (if 'ed' style).
		 */
		if (db_ed_style) {
		    db_dot = db_prev;
		}
		else {
		    db_dot = db_next;
		}
	    }
	    else {
		/*
		 * If command does not change dot,
		 * set 'next' location to be the same.
		 */
		db_next = db_dot;
	    }
	}
}

/*ARGSUSED*/
void
db_buf_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	boolean_t full = FALSE;

	if (modif[0] == 'f')
		full = TRUE;

	vfs_buf_print((void *) addr, full, db_printf);
}

/*ARGSUSED*/
void
db_map_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
        boolean_t full = FALSE;

        if (modif[0] == 'f')
                full = TRUE;

        uvm_map_printit((struct vm_map *) addr, full, db_printf);
}

/*ARGSUSED*/
void
db_malloc_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
#if defined(MALLOC_DEBUG)
	extern void debug_malloc_printit(int (*)(const char *, ...), vaddr_t);

	if (!have_addr)
		addr = 0;

	debug_malloc_printit(db_printf, (vaddr_t)addr);
#else
	malloc_printit(db_printf);
#endif
}

/*ARGSUSED*/
void
db_mbuf_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	m_print((void *)addr, db_printf);
}

/*ARGSUSED*/
void
db_mount_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	boolean_t full = FALSE;

	if (modif[0] == 'f')
		full = TRUE;

	vfs_mount_print((struct mount *) addr, full, db_printf);
}

void
db_show_all_mounts(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	boolean_t full = FALSE;
	struct mount *mp;

	if (modif[0] == 'f')
		full = TRUE;

	TAILQ_FOREACH(mp, &mountlist, mnt_list)
		vfs_mount_print(mp, full, db_printf);
}

extern struct pool vnode_pool;
void
db_show_all_vnodes(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	boolean_t full = FALSE;

	if (modif[0] == 'f')
		full = TRUE;

	pool_walk(&vnode_pool, full, db_printf, vfs_vnode_print);
}

extern struct pool bufpool;
void
db_show_all_bufs(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	boolean_t full = FALSE;

	if (modif[0] == 'f')
		full = TRUE;

	pool_walk(&bufpool, full, db_printf, vfs_buf_print);
}

/*ARGSUSED*/
void
db_object_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
        boolean_t full = FALSE;

        if (modif[0] == 'f')
                full = TRUE;

	uvm_object_printit((struct uvm_object *) addr, full, db_printf);
}

/*ARGSUSED*/
void
db_page_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
        boolean_t full = FALSE;

        if (modif[0] == 'f')
                full = TRUE;

	uvm_page_printit((struct vm_page *) addr, full, db_printf);
}

/*ARGSUSED*/
void
db_vnode_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	boolean_t full = FALSE;

	if (modif[0] == 'f')
		full = TRUE;

	vfs_vnode_print((void *)addr, full, db_printf);
}

#ifdef NFSCLIENT
/*ARGSUSED*/
void
db_nfsreq_print_cmd(db_expr_t addr, int have_addr, db_expr_t count,
    char *modif)
{
	boolean_t full = FALSE;

	if (modif[0] == 'f')
		full = TRUE;

	nfs_request_print((void *)addr, full, db_printf);
}

/*ARGSUSED*/
void
db_nfsnode_print_cmd(db_expr_t addr, int have_addr, db_expr_t count,
    char *modif)
{
	boolean_t full = FALSE;

	if (modif[0] == 'f')
		full = TRUE;

	nfs_node_print((void *)addr, full, db_printf);
}
#endif

/*ARGSUSED*/
void
db_show_panic_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	if (panicstr)
		db_printf("%s\n", panicstr);
	else
		db_printf("the kernel did not panic\n");	/* yet */
}

/*ARGSUSED*/
void
db_extent_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	extent_print_all();
}

/*ARGSUSED*/
void
db_pool_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	pool_printit((struct pool *)addr, modif, db_printf);
}

/*ARGSUSED*/
void
db_proc_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	if (!have_addr)
		addr = (db_expr_t)curproc;

	proc_printit((struct proc *)addr, modif, db_printf);
}

/*ARGSUSED*/
void
db_uvmexp_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	uvmexp_print(db_printf);
}

void	bcstats_print(int (*)(const char *, ...));

/*ARGSUSED*/
void
db_bcstats_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	bcstats_print(db_printf);
}

/*
 * 'show' commands
 */

struct db_command db_show_all_cmds[] = {
	{ "procs",	db_show_all_procs,	0, NULL },
	{ "callout",	db_show_callout,	0, NULL },
	{ "pools",	db_show_all_pools,	0, NULL },
	{ "mounts",	db_show_all_mounts,	0, NULL },
	{ "vnodes",	db_show_all_vnodes,	0, NULL },
	{ "bufs",	db_show_all_bufs,	0, NULL },
#ifdef NFSCLIENT
	{ "nfsreqs",	db_show_all_nfsreqs,	0, NULL },
	{ "nfsnodes",	db_show_all_nfsnodes,	0, NULL },
#endif
	{ NULL, 	NULL, 			0, NULL }
};

struct db_command db_show_cmds[] = {
	{ "all",	NULL,			0,	db_show_all_cmds },
	{ "bcstats",	db_bcstats_print_cmd,	0,	NULL },
	{ "breaks",	db_listbreak_cmd, 	0,	NULL },
	{ "buf",	db_buf_print_cmd,	0,	NULL },
	{ "extents",	db_extent_print_cmd,	0,	NULL },
	{ "malloc",	db_malloc_print_cmd,	0,	NULL },
	{ "map",	db_map_print_cmd,	0,	NULL },
	{ "mbuf",	db_mbuf_print_cmd,	0,	NULL },
	{ "mount",	db_mount_print_cmd,	0,	NULL },
#ifdef NFSCLIENT
	{ "nfsreq",	db_nfsreq_print_cmd,	0,	NULL },
	{ "nfsnode",	db_nfsnode_print_cmd,	0,	NULL },
#endif
	{ "object",	db_object_print_cmd,	0,	NULL },
#ifdef DDB_STRUCT
	{ "offset",	db_struct_offset_cmd,	CS_OWN,	NULL },
#endif
	{ "page",	db_page_print_cmd,	0,	NULL },
	{ "panic",	db_show_panic_cmd,	0,	NULL },
	{ "pool",	db_pool_print_cmd,	0,	NULL },
	{ "proc",	db_proc_print_cmd,	0,	NULL },
	{ "registers",	db_show_regs,		0,	NULL },
#ifdef DDB_STRUCT
	{ "struct",	db_struct_layout_cmd,	CS_OWN,	NULL },
#endif
	{ "uvmexp",	db_uvmexp_print_cmd,	0,	NULL },
	{ "vnode",	db_vnode_print_cmd,	0,	NULL },
	{ "watches",	db_listwatch_cmd, 	0,	NULL },
	{ NULL,		NULL,			0,	NULL }
};

struct db_command db_boot_cmds[] = {
	{ "sync",	db_boot_sync_cmd,	0,	0 },
	{ "crash",	db_boot_crash_cmd,	0,	0 },
	{ "dump",	db_boot_dump_cmd,	0,	0 },
	{ "halt",	db_boot_halt_cmd,	0,	0 },
	{ "reboot",	db_boot_reboot_cmd,	0,	0 },
	{ "poweroff",	db_boot_poweroff_cmd,	0,	0 },
	{ NULL, }
};

struct db_command db_command_table[] = {
#ifdef DB_MACHINE_COMMANDS
  /* this must be the first entry, if it exists */
	{ "machine",    NULL,                   0,     		NULL},
#endif
	{ "print",	db_print_cmd,		0,		NULL },
	{ "examine",	db_examine_cmd,		CS_SET_DOT, 	NULL },
	{ "x",		db_examine_cmd,		CS_SET_DOT, 	NULL },
	{ "search",	db_search_cmd,		CS_OWN|CS_SET_DOT, NULL },
	{ "set",	db_set_cmd,		CS_OWN,		NULL },
	{ "write",	db_write_cmd,		CS_MORE|CS_SET_DOT, NULL },
	{ "w",		db_write_cmd,		CS_MORE|CS_SET_DOT, NULL },
	{ "delete",	db_delete_cmd,		0,		NULL },
	{ "d",		db_delete_cmd,		0,		NULL },
	{ "break",	db_breakpoint_cmd,	0,		NULL },
	{ "dwatch",	db_deletewatch_cmd,	0,		NULL },
	{ "watch",	db_watchpoint_cmd,	CS_MORE,	NULL },
	{ "step",	db_single_step_cmd,	0,		NULL },
	{ "s",		db_single_step_cmd,	0,		NULL },
	{ "continue",	db_continue_cmd,	0,		NULL },
	{ "c",		db_continue_cmd,	0,		NULL },
	{ "until",	db_trace_until_call_cmd,0,		NULL },
	{ "next",	db_trace_until_matching_cmd,0,		NULL },
	{ "match",	db_trace_until_matching_cmd,0,		NULL },
	{ "trace",	db_stack_trace_cmd,	0,		NULL },
	{ "call",	db_fncall,		CS_OWN,		NULL },
	{ "ps",		db_show_all_procs,	0,		NULL },
	{ "callout",	db_show_callout,	0,		NULL },
	{ "show",	NULL,			0,		db_show_cmds },
	{ "boot",	NULL,			0,		db_boot_cmds },
	{ "help",	db_help_cmd,		0,		NULL },
	{ "hangman",	db_hangman,		0,		NULL },
	{ "dmesg",	db_dmesg_cmd,		0,		NULL },
	{ NULL, 	NULL,			0,		NULL }
};

#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

struct db_command	*db_last_command = 0;

void
db_help_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
{
	db_cmd_list(db_command_table);
}

void
db_command_loop(void)
{
	label_t		db_jmpbuf;
	label_t		*savejmp;
	extern int	db_output_line;

	/*
	 * Initialize 'prev' and 'next' to dot.
	 */
	db_prev = db_dot;
	db_next = db_dot;

	db_cmd_loop_done = 0;

	savejmp = db_recover;
	db_recover = &db_jmpbuf;
	(void) setjmp(&db_jmpbuf);

	while (!db_cmd_loop_done) {

		if (db_print_position() != 0)
			db_printf("\n");
		db_output_line = 0;

#ifdef MULTIPROCESSOR
		db_printf("ddb{%d}> ", CPU_INFO_UNIT(curcpu()));
#else
		db_printf("ddb> ");
#endif
		(void) db_read_line();

		db_command(&db_last_command, db_command_table);
	}

	db_recover = savejmp;
}

void
db_error(char *s)
{
	if (s)
		db_printf("%s", s);
	db_flush_lex();
	if (db_recover != NULL)
		longjmp(db_recover);
}

/*
 * Call random function:
 * !expr(arg,arg,arg)
 */
/*ARGSUSED*/
void
db_fncall(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	db_expr_t	fn_addr;
#define	MAXARGS		11
	db_expr_t	args[MAXARGS];
	int		nargs = 0;
	db_expr_t	retval;
	db_expr_t	(*func)(db_expr_t, ...);
	int		t;
	char		tmpfmt[28];

	if (!db_expression(&fn_addr)) {
	    db_printf("Bad function\n");
	    db_flush_lex();
	    return;
	}
	func = (db_expr_t (*)(db_expr_t, ...)) fn_addr;

	t = db_read_token();
	if (t == tLPAREN) {
	    if (db_expression(&args[0])) {
		nargs++;
		while ((t = db_read_token()) == tCOMMA) {
		    if (nargs == MAXARGS) {
			db_printf("Too many arguments\n");
			db_flush_lex();
			return;
		    }
		    if (!db_expression(&args[nargs])) {
			db_printf("Argument missing\n");
			db_flush_lex();
			return;
		    }
		    nargs++;
		}
		db_unread_token(t);
	    }
	    if (db_read_token() != tRPAREN) {
		db_printf("?\n");
		db_flush_lex();
		return;
	    }
	}
	db_skip_to_eol();

	while (nargs < MAXARGS) {
	    args[nargs++] = 0;
	}

	retval = (*func)(args[0], args[1], args[2], args[3], args[4],
			 args[5], args[6], args[7], args[8], args[9]);
	db_printf("%s\n", db_format(tmpfmt, sizeof tmpfmt, retval,
	    DB_FORMAT_N, 1, 0));
}

void
db_boot_sync_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
{
	reboot(RB_AUTOBOOT | RB_TIMEBAD | RB_USERREQ);
}

void
db_boot_crash_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
{
	reboot(RB_NOSYNC | RB_DUMP | RB_TIMEBAD | RB_USERREQ);
}

void
db_boot_dump_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
{
	reboot(RB_DUMP | RB_TIMEBAD | RB_USERREQ);
}

void
db_boot_halt_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
{
	reboot(RB_NOSYNC | RB_HALT | RB_TIMEBAD | RB_USERREQ);
}

void
db_boot_reboot_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
{
	reboot(RB_AUTOBOOT | RB_NOSYNC | RB_TIMEBAD | RB_USERREQ);
}

void
db_boot_poweroff_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
{
	reboot(RB_NOSYNC | RB_HALT | RB_POWERDOWN | RB_TIMEBAD | RB_USERREQ);
}

void
db_dmesg_cmd(db_expr_t addr, int haddr, db_expr_t count, char *modif)
{
	int i, off;
	char *p;

	if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC)
		return;
	off = msgbufp->msg_bufx;
	if (off > msgbufp->msg_bufs)
		off = 0;
	for (i = 0, p = msgbufp->msg_bufc + off;
	    i < msgbufp->msg_bufs; i++, p++) {
		if (p >= msgbufp->msg_bufc + msgbufp->msg_bufs)
			p = msgbufp->msg_bufc;
		if (*p != '\0')
			db_putchar(*p);
	}
	db_putchar('\n');
}

void
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
    char *modif)
{
	db_stack_trace_print(addr, have_addr, count, modif, db_printf);
}


code:
/*	$OpenBSD: db_command.h,v 1.30 2010/11/05 15:17:50 claudio Exp $	*/
/*	$NetBSD: db_command.h,v 1.8 1996/02/05 01:56:55 christos Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993,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
 */

/*
 * Command loop declarations.
 */
void db_skip_to_eol(void);
struct db_command;
int db_cmd_search(char *, struct db_command *, struct db_command **);
void db_cmd_list(struct db_command *);
void db_command(struct db_command **, struct db_command *);
void db_buf_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_map_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_malloc_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_mbuf_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_mount_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_show_all_mounts(db_expr_t, int, db_expr_t, char *);
void db_show_all_vnodes(db_expr_t, int, db_expr_t, char *);
void db_show_all_bufs(db_expr_t, int, db_expr_t, char *);
void db_object_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_page_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_extent_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_pool_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_proc_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_uvmexp_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_vnode_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_nfsreq_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_nfsnode_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_machine_commands_install(struct db_command *);
void db_help_cmd(db_expr_t, int, db_expr_t, char *);
void db_command_loop(void);
void db_error(char *);
void db_fncall(db_expr_t, int, db_expr_t, char *);
void db_boot_sync_cmd(db_expr_t, int, db_expr_t, char *);
void db_boot_crash_cmd(db_expr_t, int, db_expr_t, char *);
void db_boot_dump_cmd(db_expr_t, int, db_expr_t, char *);
void db_boot_halt_cmd(db_expr_t, int, db_expr_t, char *);
void db_boot_reboot_cmd(db_expr_t, int, db_expr_t, char *);
void db_boot_poweroff_cmd(db_expr_t, int, db_expr_t, char *);
void db_stack_trace_cmd(db_expr_t, int, db_expr_t, char *);
void db_dmesg_cmd(db_expr_t, int, db_expr_t, char *);
void db_show_panic_cmd(db_expr_t, int, db_expr_t, char *);
void db_bcstats_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_struct_offset_cmd(db_expr_t, int, db_expr_t, char *);
void db_struct_layout_cmd(db_expr_t, int, db_expr_t, char *);

extern	db_addr_t db_dot, db_last_addr, db_prev, db_next;

/*
 * Command table
 */
struct db_command {
	char		*name;		/* command name */
	/* function to call */
	void		(*fcn)(db_expr_t, int, db_expr_t, char *);
	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 */
};

license: unknown


code:
/*	$OpenBSD: db_dwarf.c,v 1.2 2015/07/07 19:31:02 matthew Exp $	 */
/*
 * Copyright (c) 2014 Matthew Dempsky <matthew@dempsky.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifdef _KERNEL
#include <sys/param.h>
#include <sys/stdint.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <ddb/db_dwarf.h>
#ifdef DIAGNOSTIC
#define DWARN(fmt, ...) printf("ddb: " fmt "\n", __VA_ARGS__)
#else
#define DWARN(fmt, ...) ((void)0)
#endif
#else /* _KERNEL */
#include <err.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#define DWARN warnx
#endif /* _KERNEL */

enum {
	DW_LNS_copy			= 1,
	DW_LNS_advance_pc		= 2,
	DW_LNS_advance_line		= 3,
	DW_LNS_set_file			= 4,
	DW_LNS_set_column		= 5,
	DW_LNS_negate_stmt		= 6,
	DW_LNS_set_basic_block		= 7,
	DW_LNS_const_add_pc		= 8,
	DW_LNS_fixed_advance_pc		= 9,
	DW_LNS_set_prologue_end		= 10,
	DW_LNS_set_epilogue_begin	= 11,
};

enum {
	DW_LNE_end_sequence		= 1,
	DW_LNE_set_address		= 2,
	DW_LNE_define_file		= 3,
};

struct dwbuf {
	const char *buf;
	size_t len;
};

static inline bool
read_bytes(struct dwbuf *d, void *v, size_t n)
{
	if (d->len < n)
		return (false);
	memcpy(v, d->buf, n);
	d->buf += n;
	d->len -= n;
	return (true);
}

static bool
read_s8(struct dwbuf *d, int8_t *v)
{
	return (read_bytes(d, v, sizeof(*v)));
}

static bool
read_u8(struct dwbuf *d, uint8_t *v)
{
	return (read_bytes(d, v, sizeof(*v)));
}

static bool
read_u16(struct dwbuf *d, uint16_t *v)
{
	return (read_bytes(d, v, sizeof(*v)));
}

static bool
read_u32(struct dwbuf *d, uint32_t *v)
{
	return (read_bytes(d, v, sizeof(*v)));
}

static bool
read_u64(struct dwbuf *d, uint64_t *v)
{
	return (read_bytes(d, v, sizeof(*v)));
}

/* Read a DWARF LEB128 (little-endian base-128) value. */
static bool
read_leb128(struct dwbuf *d, uint64_t *v, bool signextend)
{
	unsigned int shift = 0;
	uint64_t res = 0;
	uint8_t x;
	while (shift < 64 && read_u8(d, &x)) {
		res |= (uint64_t)(x & 0x7f) << shift;
		shift += 7;
		if ((x & 0x80) == 0) {
			if (signextend && shift < 64 && (x & 0x40) != 0)
				res |= ~(uint64_t)0 << shift;
			*v = res;
			return (true);
		}
	}
	return (false);
}

static bool
read_sleb128(struct dwbuf *d, int64_t *v)
{
	return (read_leb128(d, (uint64_t *)v, true));
}

static bool
read_uleb128(struct dwbuf *d, uint64_t *v)
{
	return (read_leb128(d, v, false));
}

/* Read a NUL terminated string. */
static bool
read_string(struct dwbuf *d, const char **s)
{
	const char *end = memchr(d->buf, '\0', d->len);
	if (end == NULL)
		return (false);
	size_t n = end - d->buf + 1;
	*s = d->buf;
	d->buf += n;
	d->len -= n;
	return (true);
}

static bool
read_buf(struct dwbuf *d, struct dwbuf *v, size_t n)
{
	if (d->len < n)
		return (false);
	v->buf = d->buf;
	v->len = n;
	d->buf += n;
	d->len -= n;
	return (true);
}

static bool
skip_bytes(struct dwbuf *d, size_t n)
{
	if (d->len < n)
		return (false);
	d->buf += n;
	d->len -= n;
	return (true);
}

static bool
read_filename(struct dwbuf *names, const char **outdirname,
    const char **outbasename, uint8_t opcode_base, uint64_t file)
{
	if (file == 0)
		return (false);

	/* Skip over opcode table. */
	size_t i;
	for (i = 1; i < opcode_base; i++) {
		uint64_t dummy;
		if (!read_uleb128(names, &dummy))
			return (false);
	}

	/* Skip over directory name table for now. */
	struct dwbuf dirnames = *names;
	for (;;) {
		const char *name;
		if (!read_string(names, &name))
			return (false);
		if (*name == '\0')
			break;
	}

	/* Locate file entry. */
	const char *basename = NULL;
	uint64_t dir = 0;
	for (i = 0; i < file; i++) {
		uint64_t mtime, size;
		if (!read_string(names, &basename) || *basename == '\0' ||
		    !read_uleb128(names, &dir) ||
		    !read_uleb128(names, &mtime) ||
		    !read_uleb128(names, &size))
			return (false);
	}

	const char *dirname = NULL;
	for (i = 0; i < dir; i++) {
		if (!read_string(&dirnames, &dirname) || *dirname == '\0')
			return (false);
	}

	*outdirname = dirname;
	*outbasename = basename;
	return (true);
}

bool
db_dwarf_line_at_pc(const char *linetab, size_t linetabsize, uintptr_t pc,
    const char **outdirname, const char **outbasename, int *outline)
{
	struct dwbuf table = { .buf = linetab, .len = linetabsize };

	/*
	 * For simplicity, we simply brute force search through the entire
	 * line table each time.
	 */
	uint32_t unitsize;
	struct dwbuf unit;
next:
	/* Line tables are a sequence of compilation unit entries. */
	if (!read_u32(&table, &unitsize) || unitsize >= 0xfffffff0 ||
	    !read_buf(&table, &unit, unitsize))
		return (false);

	uint16_t version;
	uint32_t header_size;
	if (!read_u16(&unit, &version) || version > 2 ||
	    !read_u32(&unit, &header_size))
		goto next;

	struct dwbuf headerstart = unit;
	uint8_t min_insn_length, default_is_stmt, line_range, opcode_base;
	int8_t line_base;
	if (!read_u8(&unit, &min_insn_length) ||
	    !read_u8(&unit, &default_is_stmt) ||
	    !read_s8(&unit, &line_base) ||
	    !read_u8(&unit, &line_range) ||
	    !read_u8(&unit, &opcode_base))
		goto next;

	/*
	 * Directory and file names are next in the header, but for now we
	 * skip directly to the line number program.
	 */
	struct dwbuf names = unit;
	unit = headerstart;
	if (!skip_bytes(&unit, header_size))
		return (false);

	/* VM registers. */
	uint64_t address = 0, file = 1, line = 1, column = 0;
	uint8_t is_stmt = default_is_stmt;
	bool basic_block = false, end_sequence = false;
	bool prologue_end = false, epilogue_begin = false;

	/* Last line table entry emitted, if any. */
	bool have_last = false;
	uint64_t last_line = 0, last_file = 0;

	/* Time to run the line program. */
	uint8_t opcode;
	while (read_u8(&unit, &opcode)) {
		bool emit = false, reset_basic_block = false;

		if (opcode >= opcode_base) {
			/* "Special" opcodes. */
			uint8_t diff = opcode - opcode_base;
			address += diff / line_range;
			line += line_base + diff % line_range;
			emit = true;
		} else if (opcode == 0) {
			/* "Extended" opcodes. */
			uint64_t extsize;
			struct dwbuf extra;
			if (!read_uleb128(&unit, &extsize) ||
			    !read_buf(&unit, &extra, extsize) ||
			    !read_u8(&extra, &opcode))
				goto next;
			switch (opcode) {
			case DW_LNE_end_sequence:
				emit = true;
				end_sequence = true;
				break;
			case DW_LNE_set_address:
				switch (extra.len) {
				case 4: {
					uint32_t address32;
					if (!read_u32(&extra, &address32))
						goto next;
					address = address32;
					break;
				}
				case 8:
					if (!read_u64(&extra, &address))
						goto next;
					break;
				default:
					DWARN("unexpected address length: %zu",
					    extra.len);
					goto next;
				}
				break;
			case DW_LNE_define_file:
				/* XXX: hope this isn't needed */
			default:
				DWARN("unknown extended opcode: %d", opcode);
				goto next;
			}
		} else {
			/* "Standard" opcodes. */
			switch (opcode) {
			case DW_LNS_copy:
				emit = true;
				reset_basic_block = true;
				break;
			case DW_LNS_advance_pc: {
				uint64_t delta;
				if (!read_uleb128(&unit, &delta))
					goto next;
				address += delta * min_insn_length;
				break;
			}
			case DW_LNS_advance_line: {
				int64_t delta;
				if (!read_sleb128(&unit, &delta))
					goto next;
				line += delta;
				break;
			}
			case DW_LNS_set_file:
				if (!read_uleb128(&unit, &file))
					goto next;
				break;
			case DW_LNS_set_column:
				if (!read_uleb128(&unit, &column))
					goto next;
				break;
			case DW_LNS_negate_stmt:
				is_stmt = !is_stmt;
				break;
			case DW_LNS_set_basic_block:
				basic_block = true;
				break;
			case DW_LNS_const_add_pc:
				address += (255 - opcode_base) / line_range;
				break;
			case DW_LNS_set_prologue_end:
				prologue_end = true;
				break;
			case DW_LNS_set_epilogue_begin:
				epilogue_begin = true;
				break;
			default:
				DWARN("unknown standard opcode: %d", opcode);
				goto next;
			}
		}

		if (emit) {
			if (address > pc) {
				/* Found an entry after our target PC. */
				if (!have_last) {
					/* Give up on this program. */
					break;
				}
				/* Return the last entry. */
				*outline = last_line;
				return (read_filename(&names, outdirname,
				    outbasename, opcode_base, last_file));
			}

			last_file = file;
			last_line = line;
			have_last = true;
		}

		if (reset_basic_block)
			basic_block = false;
	}

	goto next;
}

#ifndef _KERNEL
#include <sys/endian.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <elf_abi.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifndef ELFDATA
#if BYTE_ORDER == LITTLE_ENDIAN
#define ELFDATA ELFDATA2LSB
#elif BYTE_ORDER == BIG_ENDIAN
#define ELFDATA ELFDATA2MSB
#else
#error Unsupported byte order
#endif
#endif /* !ELFDATA */

static void
usage()
{
	extern const char *__progname;
	errx(1, "usage: %s [-s] [-e filename] [addr addr ...]", __progname);
}

/*
 * Basic addr2line clone for stand-alone testing.
 */
int
main(int argc, char *argv[])
{
	const char *filename = "a.out";

	int ch;
	bool showdir = true;
	while ((ch = getopt(argc, argv, "e:s")) != EOF) {
		switch (ch) {
		case 'e':
			filename = optarg;
			break;
		case 's':
			showdir = false;
			break;
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	/* Start by mapping the full file into memory. */
	int fd = open(filename, O_RDONLY);
	if (fd == -1)
		err(1, "open");

	struct stat st;
	if (fstat(fd, &st) == -1)
		err(1, "fstat");
	if (st.st_size < (off_t)sizeof(Elf_Ehdr))
		errx(1, "file too small to be ELF");
	if ((uintmax_t)st.st_size > SIZE_MAX)
		errx(1, "file too big to fit memory");
	size_t filesize = st.st_size;

	const char *p = mmap(NULL, filesize, PROT_READ, MAP_SHARED, fd, 0);
	if (p == MAP_FAILED)
		err(1, "mmap");

	close(fd);

	/* Read and validate ELF header. */
	Elf_Ehdr ehdr;
	memcpy(&ehdr, p, sizeof(ehdr));
	if (!IS_ELF(ehdr))
		errx(1, "file is not ELF");
	if (ehdr.e_ident[EI_CLASS] != ELFCLASS)
		errx(1, "unexpected word size");
	if (ehdr.e_ident[EI_DATA] != ELFDATA)
		errx(1, "unexpected data format");
	if (ehdr.e_shoff > filesize)
		errx(1, "bogus section table offset");
	if (ehdr.e_shentsize < sizeof(Elf_Shdr))
		errx(1, "unexpected section header size");
	if (ehdr.e_shnum > (filesize - ehdr.e_shoff) / ehdr.e_shentsize)
		errx(1, "bogus section header count");
	if (ehdr.e_shstrndx >= ehdr.e_shnum)
		errx(1, "bogus string table index");

	/* Find section header string table location and size. */
	Elf_Shdr shdr;
	memcpy(&shdr, p + ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize,
	    sizeof(shdr));
	if (shdr.sh_type != SHT_STRTAB)
		errx(1, "unexpected string table type");
	if (shdr.sh_offset > filesize)
		errx(1, "bogus string table offset");
	if (shdr.sh_size > filesize - shdr.sh_offset)
		errx(1, "bogus string table size");
	const char *shstrtab = p + shdr.sh_offset;
	size_t shstrtabsize = shdr.sh_size;

	/* Search through section table for .debug_line section. */
	size_t i;
	for (i = 0; i < ehdr.e_shnum; i++) {
		memcpy(&shdr, p + ehdr.e_shoff + i * ehdr.e_shentsize,
		    sizeof(shdr));
		if (0 == strncmp(".debug_line", shstrtab + shdr.sh_name,
		    shstrtabsize - shdr.sh_name))
			break;
	}
	if (i == ehdr.e_shnum)
		errx(1, "no DWARF line number table found");
	if (shdr.sh_offset > filesize)
		errx(1, "bogus line table offset");
	if (shdr.sh_size > filesize - shdr.sh_offset)
		errx(1, "bogus line table size");
	const char *linetab = p + shdr.sh_offset;
	size_t linetabsize = shdr.sh_size;

	const char *addrstr;
	while ((addrstr = *argv++) != NULL) {
		unsigned long addr = strtoul(addrstr, NULL, 16);

		const char *dir, *file;
		int line;
		if (!db_dwarf_line_at_pc(linetab, linetabsize, addr,
		    &dir, &file, &line)) {
			dir = NULL;
			file = "??";
			line = 0;
		}
		if (showdir && dir != NULL)
			printf("%s/", dir);
		printf("%s:%d\n", file, line);
	}

	return (0);
}
#endif /* !_KERNEL */


code:
/*	$OpenBSD: db_dwarf.h,v 1.1 2014/07/11 03:17:20 matthew Exp $	 */
/*
 * Copyright (c) 2014 Matthew Dempsky <matthew@dempsky.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _DDB_DB_DWARF_H_
#define _DDB_DB_DWARF_H_

bool db_dwarf_line_at_pc(const char *, size_t, uintptr_t,
    const char **, const char **, int *);

#endif /* _DDB_DB_DWARF_H_ */


code:
/*	$OpenBSD: db_elf.c,v 1.13 2015/03/14 03:38:46 jsg Exp $	*/
/*	$NetBSD: db_elf.c,v 1.13 2000/07/07 21:55:18 jhawk Exp $	*/

/*-
 * Copyright (c) 1997 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
 * NASA Ames Research Center.
 *
 * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
 */

#include <sys/types.h>
#include <sys/stdint.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/exec.h>

#include <machine/db_machdep.h>

#include <ddb/db_dwarf.h>
#include <ddb/db_sym.h>
#include <ddb/db_output.h>

#include <sys/exec_elf.h>

static char *db_elf_find_strtab(db_symtab_t *);
static char *db_elf_find_linetab(db_symtab_t *, size_t *);

#define	STAB_TO_SYMSTART(stab)	((Elf_Sym *)((stab)->start))
#define	STAB_TO_SYMEND(stab)	((Elf_Sym *)((stab)->end))
#define	STAB_TO_EHDR(stab)	((Elf_Ehdr *)((stab)->private))
#define	STAB_TO_SHDR(stab, e)	((Elf_Shdr *)((stab)->private + (e)->e_shoff))

boolean_t	db_elf_sym_init(int, void *, void *, const char *);
db_sym_t	db_elf_lookup(db_symtab_t *, char *);
db_sym_t	db_elf_search_symbol(db_symtab_t *, db_addr_t,
		    db_strategy_t, db_expr_t *);
void		db_elf_symbol_values(db_symtab_t *, db_sym_t,
		    char **, db_expr_t *);
boolean_t	db_elf_line_at_pc(db_symtab_t *, db_sym_t,
		    char **, int *, db_expr_t);
boolean_t	db_elf_sym_numargs(db_symtab_t *, db_sym_t, int *,
		    char **);
void		db_elf_forall(db_symtab_t *,
		    db_forall_func_t db_forall_func, void *);

db_symformat_t db_symformat_elf = {
	"ELF",
	db_elf_sym_init,
	db_elf_lookup,
	db_elf_search_symbol,
	db_elf_symbol_values,
	db_elf_line_at_pc,
	db_elf_sym_numargs,
	db_elf_forall
};

/*
 * Find the symbol table and strings; tell ddb about them.
 *
 * symsize:	size of symbol table
 * symtab:	pointer to start of symbol table
 * esymtab:	pointer to end of string table, for checking - rounded up to
 *		    integer boundry
 */
boolean_t
db_elf_sym_init(int symsize, void *symtab, void *esymtab, const char *name)
{
	Elf_Ehdr *elf;
	Elf_Shdr *shp;
	Elf_Sym *symp, *symtab_start, *symtab_end;
	char *shstrtab, *strtab_start, *strtab_end;
	int i;
	char *errstr = "";

	if (ALIGNED_POINTER(symtab, long) == 0) {
		db_printf("[ %s symbol table has bad start address %p ]\n",
		    name, symtab);
		return (FALSE);
	}

	symtab_start = symtab_end = NULL;
	strtab_start = strtab_end = NULL;

	/*
	 * The format of the symbols loaded by the boot program is:
	 *
	 *	Elf exec header
	 *	first section header
	 *	. . .
	 *	. . .
	 *	last section header
	 *	first symbol, string, or line table section
	 *	. . .
	 *	. . .
	 *	last symbol, string, or line table section
	 */

	/*
	 * Validate the Elf header.
	 */
	elf = (Elf_Ehdr *)symtab;
	if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
	    elf->e_ident[EI_CLASS] != ELFCLASS) {
		errstr = "bad magic";
		goto badheader;
	}

	if (elf->e_machine != ELF_TARG_MACH) {
		errstr = "bad e_machine";
		goto badheader;
	}

	/*
	 * Find the section header string table (.shstrtab), and look up
	 * the symbol table (.symtab) and string table (.strtab) via their
	 * names in shstrtab, rather than by table type.
	 * This works in the presence of multiple string tables, such as
	 * stabs data found when booting bsd.gdb.
	 */
	shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
	shstrtab = (char *)symtab + shp[elf->e_shstrndx].sh_offset;
	for (i = 0; i < elf->e_shnum; i++) {
		if (shp[i].sh_type == SHT_SYMTAB) {
			int j;

			if (shp[i].sh_offset == 0)
				continue;
			symtab_start = (Elf_Sym *)((char *)symtab +
			    shp[i].sh_offset);
			symtab_end = (Elf_Sym *)((char *)symtab +
			    shp[i].sh_offset + shp[i].sh_size);
			j = shp[i].sh_link;
			if (shp[j].sh_offset == 0)
				continue;
			strtab_start = (char *)symtab + shp[j].sh_offset;
			strtab_end = (char *)symtab + shp[j].sh_offset +
			    shp[j].sh_size;
			break;
		}

		/*
		 * This is the old way of doing things.
		 * XXX - verify that it's not needed.
		 */
		if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0) {
			strtab_start = (char *)symtab + shp[i].sh_offset;
			strtab_end = (char *)symtab + shp[i].sh_offset +
			    shp[i].sh_size;
		} else if (strcmp(".symtab", shstrtab+shp[i].sh_name) == 0) {
			symtab_start = (Elf_Sym *)((char *)symtab +
			    shp[i].sh_offset);
			symtab_end = (Elf_Sym *)((char *)symtab +
			    shp[i].sh_offset + shp[i].sh_size);
		}
	}

	/*
	 * Now, sanity check the symbols against the string table.
	 */
	if (symtab_start == NULL || strtab_start == NULL ||
	    ALIGNED_POINTER(symtab_start, long) == 0 ||
	    ALIGNED_POINTER(strtab_start, long) == 0) {
		errstr = "symtab unaligned";
		goto badheader;
	}
	for (symp = symtab_start; symp < symtab_end; symp++)
		if (symp->st_name + strtab_start > strtab_end) {
			errstr = "symtab corrupted";
			goto badheader;
		}

	/*
	 * Link the symbol table into the debugger.
	 */
	if (db_add_symbol_table((char *)symtab_start,
	    (char *)symtab_end, name, (char *)symtab) != -1) {
		db_printf("[ using %lu bytes of %s ELF symbol table ]\n",
		    (u_long)roundup(((char *)esymtab - (char *)symtab),
				    sizeof(u_long)), name);
		return (TRUE);
	}

	return (FALSE);

 badheader:
	db_printf("[ %s ELF symbol table not valid: %s ]\n", name, errstr);
	return (FALSE);
}

/*
 * Internal helper function - return a pointer to the string table
 * for the current symbol table.
 */
static char *
db_elf_find_strtab(db_symtab_t *stab)
{
	Elf_Ehdr *elf = STAB_TO_EHDR(stab);
	Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
	char *shstrtab;
	int i;

	shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
	for (i = 0; i < elf->e_shnum; i++) {
		if (shp[i].sh_type == SHT_SYMTAB)
			return ((char *)elf + shp[shp[i].sh_link].sh_offset);
		if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0)
			return ((char *)elf + shp[i].sh_offset);
	}

	return (NULL);
}

/*
 * Internal helper function - return a pointer to the line table
 * for the current symbol table.
 */
static char *
db_elf_find_linetab(db_symtab_t *stab, size_t *size)
{
	Elf_Ehdr *elf = STAB_TO_EHDR(stab);
	Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
	char *shstrtab;
	int i;

	shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
	for (i = 0; i < elf->e_shnum; i++) {
		if ((shp[i].sh_flags & SHF_ALLOC) != 0 &&
		    strcmp(".debug_line", shstrtab+shp[i].sh_name) == 0) {
			*size = shp[i].sh_size;
			return ((char *)elf + shp[i].sh_offset);
		}
	}

	return (NULL);
}

/*
 * Lookup the symbol with the given name.
 */
db_sym_t
db_elf_lookup(db_symtab_t *stab, char *symstr)
{
	Elf_Sym *symp, *symtab_start, *symtab_end;
	char *strtab;

	symtab_start = STAB_TO_SYMSTART(stab);
	symtab_end = STAB_TO_SYMEND(stab);

	strtab = db_elf_find_strtab(stab);
	if (strtab == NULL)
		return ((db_sym_t)0);

	for (symp = symtab_start; symp < symtab_end; symp++) {
		if (symp->st_name != 0 &&
		    db_eqname(strtab + symp->st_name, symstr, 0))
			return ((db_sym_t)symp);
	}

	return ((db_sym_t)0);
}

/*
 * Search for the symbol with the given address (matching within the
 * provided threshold).
 */
db_sym_t
db_elf_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strategy,
    db_expr_t *diffp)
{
	Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
	db_expr_t diff = *diffp;

	symtab_start = STAB_TO_SYMSTART(symtab);
	symtab_end = STAB_TO_SYMEND(symtab);

	rsymp = NULL;

	for (symp = symtab_start; symp < symtab_end; symp++) {
		if (symp->st_name == 0)
			continue;
#if 0
		/* This prevents me from seeing anythin in locore.s -- eeh */
		if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
		    ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
			continue;
#endif

		if (off >= symp->st_value) {
			if ((off - symp->st_value) < diff) {
				diff = off - symp->st_value;
				rsymp = symp;
				if (diff == 0) {
					if (strategy == DB_STGY_PROC &&
					    ELFDEFNNAME(ST_TYPE)(symp->st_info)
					      == STT_FUNC &&
					    ELFDEFNNAME(ST_BIND)(symp->st_info)
					      != STB_LOCAL)
						break;
					if (strategy == DB_STGY_ANY &&
					    ELFDEFNNAME(ST_BIND)(symp->st_info)
					      != STB_LOCAL)
						break;
				}
			} else if ((off - symp->st_value) == diff) {
				if (rsymp == NULL)
					rsymp = symp;
				else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info)
				      == STB_LOCAL &&
				    ELFDEFNNAME(ST_BIND)(symp->st_info)
				      != STB_LOCAL) {
					/* pick the external symbol */
					rsymp = symp;
				}
			}
		}
	}

	if (rsymp == NULL)
		*diffp = off;
	else
		*diffp = diff;

	return ((db_sym_t)rsymp);
}

/*
 * Return the name and value for a symbol.
 */
void
db_elf_symbol_values(db_symtab_t *symtab, db_sym_t sym, char **namep,
    db_expr_t *valuep)
{
	Elf_Sym *symp = (Elf_Sym *)sym;
	char *strtab;

	if (namep) {
		strtab = db_elf_find_strtab(symtab);
		if (strtab == NULL)
			*namep = NULL;
		else
			*namep = strtab + symp->st_name;
	}

	if (valuep)
		*valuep = symp->st_value;
}

/*
 * Return the file and line number of the current program counter
 * if we can find the appropriate debugging symbol.
 */
boolean_t
db_elf_line_at_pc(db_symtab_t *symtab, db_sym_t cursym, char **filename,
    int *linenum, db_expr_t off)
{
	const char *linetab;
	size_t linetab_size;

	linetab = db_elf_find_linetab(symtab, &linetab_size);
	if (linetab == NULL)
		return (FALSE);

	const char *dirname, *basename;
	if (!db_dwarf_line_at_pc(linetab, linetab_size, off,
	    &dirname, &basename, linenum))
		return (FALSE);

	static char path[PATH_MAX];
	if (dirname == NULL)
		strlcpy(path, basename, sizeof(path));
	else
		snprintf(path, sizeof(path), "%s/%s", dirname, basename);
	*filename = path;
	return (TRUE);
}

/*
 * Returns the number of arguments to a function and their
 * names if we can find the appropriate debugging symbol.
 */
boolean_t
db_elf_sym_numargs(db_symtab_t *symtab, db_sym_t cursym, int *nargp,
    char **argnamep)
{

	/*
	 * XXX We don't support this (yet).
	 */
	return (FALSE);
}

void
db_elf_forall(db_symtab_t *stab, db_forall_func_t db_forall_func, void *arg)
{
	char *strtab;
	static char suffix[2];
	Elf_Sym *symp, *symtab_start, *symtab_end;

	symtab_start = STAB_TO_SYMSTART(stab);
	symtab_end = STAB_TO_SYMEND(stab);

	strtab = db_elf_find_strtab(stab);
	if (strtab == NULL)
		return;

	for (symp = symtab_start; symp < symtab_end; symp++)
		if (symp->st_name != 0) {
			suffix[1] = '\0';
			switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) {
			case STT_OBJECT:
				suffix[0] = '+';
				break;
			case STT_FUNC:
				suffix[0] = '*';
				break;
			case STT_SECTION:
				suffix[0] = '&';
				break;
			case STT_FILE:
				suffix[0] = '/';
				break;
			default:
				suffix[0] = '\0';
			}
			(*db_forall_func)(stab, (db_sym_t)symp,
			    strtab + symp->st_name, suffix, 0, arg);
		}
	return;
}


code:
/*	$OpenBSD: db_examine.c,v 1.20 2014/09/14 14:17:24 jsg Exp $	*/
/*	$NetBSD: db_examine.c,v 1.11 1996/03/30 22:30:07 christos Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993,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
 */

#include <sys/param.h>
#include <sys/systm.h>

#include <machine/db_machdep.h>		/* type definitions */

#include <ddb/db_lex.h>
#include <ddb/db_output.h>
#include <ddb/db_command.h>
#include <ddb/db_sym.h>
#include <ddb/db_access.h>
#include <ddb/db_extern.h>
#include <ddb/db_interface.h>

char	db_examine_format[TOK_STRING_SIZE] = "x";

/*
 * Examine (print) data.  Syntax is:
 *		x/[bhlq][cdiorsuxz]*
 * For example, the command:
 *  	x/bxxxx
 * should print:
 *  	address:  01  23  45  67
 */
/*ARGSUSED*/
void
db_examine_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	if (modif[0] != '\0')
		db_strlcpy(db_examine_format, modif, sizeof(db_examine_format));

	if (count == -1)
		count = 1;

	db_examine((db_addr_t)addr, db_examine_format, count);
}

void
db_examine(db_addr_t addr, char *fmt, int count)
{
	int		c;
	db_expr_t	value;
	int		size;
	int		width;
	char *		fp;
	db_addr_t	incr;
	int		dis;
	char		tmpfmt[28];

	while (--count >= 0) {
		fp = fmt;

		/* defaults */
		size = 4;
		width = 12;
		incr = 0;
		dis = 0;

		while ((c = *fp++) != 0) {
			if (db_print_position() == 0) {
				/* Always print the address. */
				db_printsym(addr, DB_STGY_ANY, db_printf);
				db_printf(":\t");
				db_prev = addr;
			}
			incr = size;
			switch (c) {
			case 'b':	/* byte */
				size = 1;
				width = 4;
				break;
			case 'h':	/* half-word */
				size = 2;
				width = 8;
				break;
			case 'l':	/* long-word */
				size = 4;
				width = 12;
				break;
#ifdef __LP64__
			case 'q':	/* quad-word */
				size = 8;
				width = 20;
				break;
#endif
			case 'a':	/* address */
				db_printf("= 0x%lx\n", (long)addr);
				incr = 0;
				break;
			case 'r':	/* signed, current radix */
				value = db_get_value(addr, size, TRUE);
				db_format(tmpfmt, sizeof tmpfmt,
				    (long)value, DB_FORMAT_R, 0, width);
				db_printf("%-*s", width, tmpfmt);
				break;
			case 'x':	/* unsigned hex */
				value = db_get_value(addr, size, FALSE);
				db_printf("%-*lx", width, (long)value);
				break;
			case 'z':	/* signed hex */
				value = db_get_value(addr, size, TRUE);
				db_format(tmpfmt, sizeof tmpfmt,
				    (long)value, DB_FORMAT_Z, 0, width);
				db_printf("%-*s", width, tmpfmt);
				break;
			case 'd':	/* signed decimal */
				value = db_get_value(addr, size, TRUE);
				db_printf("%-*ld", width, (long)value);
				break;
			case 'u':	/* unsigned decimal */
				value = db_get_value(addr, size, FALSE);
				db_printf("%-*lu", width, (long)value);
				break;
			case 'o':	/* unsigned octal */
				value = db_get_value(addr, size, FALSE);
				db_printf("%-*lo", width, value);
				break;
			case 'c':	/* character */
				value = db_get_value(addr, 1, FALSE);
				incr = 1;
				if (value >= ' ' && value <= '~')
					db_printf("%c", (int)value);
				else
					db_printf("\\%03o", (int)value);
				break;
			case 's':	/* null-terminated string */
				incr = 0;
				for (;;) {
					value = db_get_value(addr + incr, 1,
					    FALSE);
					incr++;
					if (value == 0)
						break;
					if (value >= ' ' && value <= '~')
						db_printf("%c", (int)value);
					else
						db_printf("\\%03o", (int)value);
				}
				break;
			case 'i':	/* instruction */
			case 'I':	/* instruction, alternate form */
				dis = c;
				break;
			default:
				incr = 0;
				break;
			}
		}
		/* if we had a disassembly modifier, do it last */
		switch (dis) {
		case 'i':	/* instruction */
			addr = db_disasm(addr, FALSE);
			break;
		case 'I':	/* instruction, alternate form */
			addr = db_disasm(addr, TRUE);
			break;
		default:
			addr += incr;
			break;
		}
		if (db_print_position() != 0)
			db_printf("\n");
	}
	db_next = addr;
}

/*
 * Print value.
 */
char	db_print_format = 'x';

/*ARGSUSED*/
void
db_print_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	db_expr_t	value;
	char		tmpfmt[28];

	if (modif[0] != '\0')
		db_print_format = modif[0];

	switch (db_print_format) {
	case 'a':
		db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf);
		break;
	case 'r':
		db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr,
		    DB_FORMAT_R, 0, sizeof(db_expr_t) * 2 * 6 / 5));
		break;
	case 'x':
		db_printf("%*lx", (uint)sizeof(db_expr_t) * 2, addr);
		break;
	case 'z':
		db_printf("%s", db_format(tmpfmt, sizeof tmpfmt, addr,
		    DB_FORMAT_Z, 0, sizeof(db_expr_t) * 2));
		break;
	case 'd':
		db_printf("%*ld", (uint)sizeof(db_expr_t) * 2 * 6 / 5, addr);
		break;
	case 'u':
		db_printf("%*lu", (uint)sizeof(db_expr_t) * 2 * 6 / 5, addr);
		break;
	case 'o':
		db_printf("%*lo", (uint)sizeof(db_expr_t) * 2 * 4 / 3, addr);
		break;
	case 'c':
		value = addr & 0xFF;
		if (value >= ' ' && value <= '~')
			db_printf("%c", (int)value);
		else
			db_printf("\\%03o", (int)value);
		break;
	}
	db_printf("\n");
}

void
db_print_loc_and_inst(db_addr_t loc)
{
	db_printsym(loc, DB_STGY_PROC, db_printf);
	db_printf(":\t");
	(void) db_disasm(loc, FALSE);
}

/* local copy is needed here so that we can trace strlcpy() in libkern */
size_t
db_strlcpy(char *dst, const char *src, size_t siz)
{
	char *d = dst;
	const char *s = src;
	size_t n = siz;

	/* Copy as many bytes as will fit */
	if (n != 0 && --n != 0) {
		do {
			if ((*d++ = *s++) == 0)
				break;
		} while (--n != 0);
	}

	/* Not enough room in dst, add NUL and traverse rest of src */
	if (n == 0) {
		if (siz != 0)
			*d = '\0';		/* NUL-terminate dst */
		while (*s++)
			;
	}

	return(s - src - 1);	/* count does not include NUL */
}

/*
 * Search for a value in memory.
 * Syntax: search [/bhl] addr value [mask] [,count]
 */
/*ARGSUSED*/
void
db_search_cmd(db_expr_t daddr, int have_addr, db_expr_t dcount, char *modif)
{
	int		t;
	db_addr_t	addr;
	int		size;
	db_expr_t	value;
	db_expr_t	mask;
	db_expr_t	count;

	t = db_read_token();
	if (t == tSLASH) {
		t = db_read_token();
		if (t != tIDENT) {
			bad_modifier:
			db_printf("Bad modifier\n");
			db_flush_lex();
			return;
		}

		if (!strcmp(db_tok_string, "b"))
			size = 1;
		else if (!strcmp(db_tok_string, "h"))
			size = 2;
		else if (!strcmp(db_tok_string, "l"))
			size = 4;
		else
			goto bad_modifier;
	} else {
		db_unread_token(t);
		size = 4;
	}

	if (!db_expression(&value)) {
		db_printf("Address missing\n");
		db_flush_lex();
		return;
	}
	addr = (db_addr_t) value;

	if (!db_expression(&value)) {
		db_printf("Value missing\n");
		db_flush_lex();
		return;
	}

	if (!db_expression(&mask))
		mask = (int) ~0;

	t = db_read_token();
	if (t == tCOMMA) {
		if (!db_expression(&count)) {
			db_printf("Count missing\n");
			db_flush_lex();
			return;
		}
	} else {
		db_unread_token(t);
		count = -1;		/* forever */
	}
	db_skip_to_eol();

	db_search(addr, size, value, mask, count);
}

void
db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask,
    db_expr_t count)
{
	/* Negative counts means forever.  */
	while (count < 0 || count-- != 0) {
		db_prev = addr;
		if ((db_get_value(addr, size, FALSE) & mask) == value)
			break;
		addr += size;
	}
	db_next = addr;
}


code:
/*	$OpenBSD: db_expr.c,v 1.11 2014/09/14 14:17:24 jsg Exp $	*/
/*	$NetBSD: db_expr.c,v 1.5 1996/02/05 01:56:58 christos Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993,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
 */

#include <sys/param.h>

#include <machine/db_machdep.h>

#include <ddb/db_lex.h>
#include <ddb/db_access.h>
#include <ddb/db_command.h>
#include <ddb/db_sym.h>
#include <ddb/db_extern.h>
#include <ddb/db_variables.h>

boolean_t
db_term(db_expr_t *valuep)
{
	int	t;

	t = db_read_token();
	if (t == tIDENT) {
	    if (!db_value_of_name(db_tok_string, valuep)) {
		db_error("Symbol not found\n");
		/*NOTREACHED*/
	    }
	    return (TRUE);
	}
	if (t == tNUMBER) {
	    *valuep = db_tok_number;
	    return (TRUE);
	}
	if (t == tDOT) {
	    *valuep = (db_expr_t)db_dot;
	    return (TRUE);
	}
	if (t == tDOTDOT) {
	    *valuep = (db_expr_t)db_prev;
	    return (TRUE);
	}
	if (t == tPLUS) {
	    *valuep = (db_expr_t) db_next;
	    return (TRUE);
	}
	if (t == tDITTO) {
	    *valuep = (db_expr_t)db_last_addr;
	    return (TRUE);
	}
	if (t == tDOLLAR) {
	    if (!db_get_variable(valuep))
		return (FALSE);
	    return (TRUE);
	}
	if (t == tLPAREN) {
	    if (!db_expression(valuep)) {
		db_error("Syntax error\n");
		/*NOTREACHED*/
	    }
	    t = db_read_token();
	    if (t != tRPAREN) {
		db_error("Syntax error\n");
		/*NOTREACHED*/
	    }
	    return (TRUE);
	}
	db_unread_token(t);
	return (FALSE);
}

boolean_t
db_unary(db_expr_t *valuep)
{
	int	t;

	t = db_read_token();
	if (t == tMINUS) {
	    if (!db_unary(valuep)) {
		db_error("Syntax error\n");
		/*NOTREACHED*/
	    }
	    *valuep = -*valuep;
	    return (TRUE);
	}
	if (t == tSTAR) {
	    /* indirection */
	    if (!db_unary(valuep)) {
		db_error("Syntax error\n");
		/*NOTREACHED*/
	    }
	    *valuep = db_get_value((db_addr_t)*valuep, sizeof(db_addr_t), FALSE);
	    return (TRUE);
	}
	db_unread_token(t);
	return (db_term(valuep));
}

boolean_t
db_mult_expr(db_expr_t *valuep)
{
	db_expr_t	lhs, rhs;
	int		t;

	if (!db_unary(&lhs))
	    return (FALSE);

	t = db_read_token();
	while (t == tSTAR || t == tSLASH || t == tPCT || t == tHASH) {
	    if (!db_term(&rhs)) {
		db_error("Syntax error\n");
		/*NOTREACHED*/
	    }
	    if (t == tSTAR)
		lhs *= rhs;
	    else {
		if (rhs == 0) {
		    db_error("Divide by 0\n");
		    /*NOTREACHED*/
		}
		if (t == tSLASH)
		    lhs /= rhs;
		else if (t == tPCT)
		    lhs %= rhs;
		else
		    lhs = ((lhs+rhs-1)/rhs)*rhs;
	    }
	    t = db_read_token();
	}
	db_unread_token(t);
	*valuep = lhs;
	return (TRUE);
}

boolean_t
db_add_expr(db_expr_t *valuep)
{
	db_expr_t	lhs, rhs;
	int		t;

	if (!db_mult_expr(&lhs))
	    return (FALSE);

	t = db_read_token();
	while (t == tPLUS || t == tMINUS) {
	    if (!db_mult_expr(&rhs)) {
		db_error("Syntax error\n");
		/*NOTREACHED*/
	    }
	    if (t == tPLUS)
		lhs += rhs;
	    else
		lhs -= rhs;
	    t = db_read_token();
	}
	db_unread_token(t);
	*valuep = lhs;
	return (TRUE);
}

boolean_t
db_shift_expr(db_expr_t *valuep)
{
	db_expr_t	lhs, rhs;
	int		t;

	if (!db_add_expr(&lhs))
	    return (FALSE);

	t = db_read_token();
	while (t == tSHIFT_L || t == tSHIFT_R) {
	    if (!db_add_expr(&rhs)) {
		db_error("Syntax error\n");
		/*NOTREACHED*/
	    }
	    if (rhs < 0) {
		db_error("Negative shift amount\n");
		/*NOTREACHED*/
	    }
	    if (t == tSHIFT_L)
		lhs <<= rhs;
	    else {
		/* Shift right is unsigned */
		lhs = (unsigned) lhs >> rhs;
	    }
	    t = db_read_token();
	}
	db_unread_token(t);
	*valuep = lhs;
	return (TRUE);
}

int
db_expression(db_expr_t *valuep)
{
	return (db_shift_expr(valuep));
}


code:
/*	$OpenBSD: db_extern.h,v 1.13 2006/07/06 18:14:14 miod Exp $	*/
/*	$NetBSD: db_extern.h,v 1.1 1996/02/05 01:57:00 christos Exp $	*/

/*
 * Copyright (c) 1995 Christos Zoulas.  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 Christos Zoulas.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * 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.
 */
#ifndef _DDB_DB_EXTERN_H_
#define _DDB_DB_EXTERN_H_

/* db_sym.c */
void ddb_init(void);

/* db_examine.c */
void db_examine_cmd(db_expr_t, int, db_expr_t, char *);
void db_examine(db_addr_t, char *, int);
void db_print_cmd(db_expr_t, int, db_expr_t, char *);
void db_print_loc_and_inst(db_addr_t);
size_t db_strlcpy(char *, const char *, size_t);
void db_search_cmd(db_expr_t, boolean_t, db_expr_t, char *);
void db_search(db_addr_t, int, db_expr_t, db_expr_t, db_expr_t);

/* db_expr.c */
boolean_t db_term(db_expr_t *);
boolean_t db_unary(db_expr_t *);
boolean_t db_mult_expr(db_expr_t *);
boolean_t db_add_expr(db_expr_t *);
boolean_t db_shift_expr(db_expr_t *);
int db_expression(db_expr_t *);

/* db_hangman.c */
void db_hangman(db_expr_t, int, db_expr_t, char *);

/* db_input.c */
void db_putstring(char *, int);
void db_putnchars(int, int);
void db_delete(int, int);
void db_delete_line(void);
int db_inputchar(int);
int db_readline(char *, int);

/* db_print.c */
void db_show_regs(db_expr_t, boolean_t, db_expr_t, char *);

/* db_trap.c */
void db_trap(int, int);

/* db_write_cmd.c */
void db_write_cmd(db_expr_t, boolean_t, db_expr_t, char *);

#endif /* _DDB_DB_EXTERN_H_ */


code:
/*	$OpenBSD: db_hangman.c,v 1.32 2015/03/14 03:38:46 jsg Exp $	*/

/*
 * Copyright (c) 1996 Theo de Raadt, Michael Shalayeff
 * 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/param.h>
#include <sys/systm.h>

#include <machine/db_machdep.h>

#include <ddb/db_sym.h>
#include <ddb/db_output.h>

#include <dev/cons.h>

#define ABC_ISCLR(c)	sabc->abc[(c)-'a']==0
#define ABC_ISWRONG(c)	sabc->abc[(c)-'a']=='_'
#define ABC_SETWRONG(c)		(sabc->abc[(c)-'a']='_')
#define ABC_SETRIGHT(c)		(sabc->abc[(c)-'a']='+')
#define ABC_CLR()	memset(sabc->abc,0,sizeof sabc->abc)
struct _abc {
	char	abc[26+2];	/* for int32 alignment */
};

#define	TOLOWER(c)	((c)|0x20)
#define	ISLOWALPHA(c)	('a'<=(c) && (c)<='z')
#define	ISALPHA(c)	ISLOWALPHA(TOLOWER(c))

void	 db_hang(int, char *, struct _abc *);

u_long		db_plays, db_guesses;

static const char hangpic[]=
	"\n88888\r\n"
	"9 7 6\r\n"
	"97  5\r\n"
	"9  423\r\n"
	"9   2\r\n"
	"9  1 0\r\n"
	"9\r\n"
	"9  ";
static const char substchar[]="\\/|\\/O|/-|";

struct db_hang_forall_arg {
	int cnt;
	db_sym_t sym;
};

/*
 * Horrible abuse of the forall function, but we're not in a hurry.
 */
static void db_hang_forall(db_symtab_t *, db_sym_t, char *, char *, int,
			void *);

static void
db_hang_forall(db_symtab_t *stab, db_sym_t sym, char *name, char *suff, int pre,
    void *varg)
{
	struct db_hang_forall_arg *arg = (struct db_hang_forall_arg *)varg;

	if (arg->cnt-- == 0)
		arg->sym = sym;
}

static __inline char *
db_randomsym(size_t *lenp)
{
	extern db_symtab_t db_symtabs[];
	db_symtab_t *stab;
	int nsymtabs, nsyms;
	char	*p, *q;
	struct db_hang_forall_arg dfa;

	for (nsymtabs = 0; db_symtabs[nsymtabs].name != NULL; nsymtabs++)
		;

	if (nsymtabs == 0)
		return (NULL);

	stab = &db_symtabs[arc4random_uniform(nsymtabs)];

	dfa.cnt = 0;
	X_db_forall(stab, db_hang_forall, &dfa);
	nsyms = -dfa.cnt;

	if (nsyms == 0)
		return (NULL);

	dfa.cnt = arc4random_uniform(nsyms);
	X_db_forall(stab, db_hang_forall, &dfa);

	q = db_qualify(dfa.sym, stab->name);

	/* don't show symtab name if there are less than 3 of 'em */
	if (nsymtabs < 3)
		while (*q++ != ':');

	/* strlen(q) && ignoring underscores and colons */
	for ((*lenp) = 0, p = q; *p; p++)
		if (ISALPHA(*p))
			(*lenp)++;

	return (q);
}

void
db_hang(int tries, char *word, struct _abc *sabc)
{
	const char	*p;
	int i;
	int c;
#ifdef ABC_BITMASK
	int m;
#endif

	for (p = hangpic; *p; p++)
		cnputc((*p >= '0' && *p <= '9') ? ((tries <= (*p) - '0') ?
		    substchar[(*p) - '0'] : ' ') : *p);

	for (p = word; *p; p++) {
		c = TOLOWER(*p);
		cnputc(ISLOWALPHA(c) && ABC_ISCLR(c) ? '-' : *p);
	}

#ifdef ABC_WRONGSTR
	db_printf(" (%s)\r", ABC_WRONGSTR);
#else
	db_printf(" (");

#ifdef ABC_BITMASK
	m = sabc->wrong;
	for (i = 'a'; i <= 'z'; ++i, m >>= 1)
		if (m&1)
			cnputc(i);
#else
	for (i = 'a'; i <= 'z'; ++i)
		if (ABC_ISWRONG(i))
			cnputc(i);
#endif

	db_printf(")\r");
#endif
}

void
db_hangman(db_expr_t addr, int haddr, db_expr_t count, char *modif)
{
	char	*word;
	size_t	tries;
	size_t	len;
	struct _abc sabc[1];
	int	skill;

	if (modif[0] != 's' || (skill = modif[1] - '0') > 9U)
		skill = 3;
	word = NULL;
	tries = 0;
	for (;;) {

		if (word == NULL) {
			ABC_CLR();

			tries = skill + 1;
			word = db_randomsym(&len);
			if (word == NULL)
				break;

			db_plays++;
		}

		{
			int c;

			db_hang(tries, word, sabc);
			c = cngetc();
			c = TOLOWER(c);

			if (ISLOWALPHA(c) && ABC_ISCLR(c)) {
				char	*p;
				size_t	n;

					/* strchr(word,c) */
				for (n = 0, p = word; *p ; p++)
					if (TOLOWER(*p) == c)
						n++;

				if (n) {
					ABC_SETRIGHT(c);
					len -= n;
				} else {
					ABC_SETWRONG(c);
					tries--;
				}
			}
		}

		if (tries && len)
			continue;

		if (!tries && skill > 2) {
			char	*p = word;
			for (; *p; p++)
				if (ISALPHA(*p))
					ABC_SETRIGHT(TOLOWER(*p));
		}
		if (tries)
			db_guesses++;
		db_hang(tries, word, sabc);
		db_printf("\nScore: %lu/%lu\n", db_plays, db_guesses);
		word = NULL;
		if (tries)
			break;
	}
}


code:
/*	$OpenBSD: db_input.c,v 1.14 2015/03/14 03:38:46 jsg Exp $	*/
/*	$NetBSD: db_input.c,v 1.7 1996/02/05 01:57:02 christos Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993,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
 */

#include <sys/param.h>
#include <sys/systm.h>

#include <machine/db_machdep.h>

#include <ddb/db_var.h>
#include <ddb/db_output.h>
#include <ddb/db_sym.h>
#include <ddb/db_extern.h>

#include <dev/cons.h>

/*
 * Character input and editing.
 */

/*
 * We don't track output position while editing input,
 * since input always ends with a new-line.  We just
 * reset the line position at the end.
 */
char *	db_lbuf_start;	/* start of input line buffer */
char *	db_lbuf_end;	/* end of input line buffer */
char *	db_lc;		/* current character */
char *	db_le;		/* one past last character */
#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'

void
db_putstring(char *s, int count)
{
	while (--count >= 0)
	    cnputc(*s++);
}

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
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;
}

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

/* returns TRUE at end-of-line */
int
db_inputchar(int c)
{
	switch (c) {
	    case CTRL('b'):
		/* back up one character */
		if (db_lc > db_lbuf_start) {
		    cnputc(BACKUP);
		    db_lc--;
		}
		break;
	    case CTRL('f'):
		/* forward one character */
		if (db_lc < db_le) {
		    cnputc(*db_lc);
		    db_lc++;
		}
		break;
	    case CTRL('a'):
		/* beginning of line */
		while (db_lc > db_lbuf_start) {
		    cnputc(BACKUP);
		    db_lc--;
		}
		break;
	    case CTRL('e'):
		/* end of line */
		while (db_lc < db_le) {
		    cnputc(*db_lc);
		    db_lc++;
		}
		break;
	    case CTRL('w'):
		/* erase word back */
		while (db_lc > db_lbuf_start && db_lc[-1] != BLANK)
		    db_delete(1, DEL_BWD);
		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'):
		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'):
		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
	    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_le++ = c;
		return TRUE;
	    default:
		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);
}


code:
/*	$OpenBSD: db_interface.h,v 1.16 2010/11/05 15:17:50 claudio Exp $	*/
/*	$NetBSD: db_interface.h,v 1.1 1996/02/05 01:57:03 christos Exp $	*/

/*
 * Copyright (c) 1995 Christos Zoulas.  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 Christos Zoulas.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * 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.
 */
#ifndef _DDB_DB_INTERFACE_H_
#define _DDB_DB_INTERFACE_H_

/* arch/<arch>/<arch>/db_trace.c */
void db_stack_trace_print(db_expr_t, int, db_expr_t, char *,
    int (*)(const char *, ...));

/* arch/<arch>/<arch>/db_disasm.c */
db_addr_t db_disasm(db_addr_t, boolean_t);

/* kern/kern_proc.c */
void db_show_all_procs(db_expr_t, int, db_expr_t, char *);

/* kern/kern_timeout.c */
void db_show_callout(db_expr_t, int, db_expr_t, char *);

struct mount;

/* kern/vfs_subr.c */
void vfs_buf_print(void *, int, int (*)(const char *, ...));
void vfs_vnode_print(void *, int, int (*)(const char *, ...));
void vfs_mount_print(struct mount *, int, int (*)(const char *, ...));

/* kern/subr_pool.c */
void db_show_all_pools(db_expr_t, int, db_expr_t, char *);

/* kern/uipc_mbuf.c */
void m_print(void *, int (*)(const char *, ...));

/* nfs/nfs_debug.c */
void db_show_all_nfsreqs(db_expr_t, int, db_expr_t, char *);
void nfs_request_print(void *, int, int (*)(const char *, ...));
void db_show_all_nfsnodes(db_expr_t, int, db_expr_t, char *);
void nfs_node_print(void *, int, int (*)(const char *, ...));

/* ufs/ffs/ffs_softdep.c */
struct worklist;
void worklist_print(struct worklist *, int, int (*)(const char *, ...));
void softdep_print(struct buf *, int, int (*)(const char *, ...));

/* arch/<arch>/<arch>/db_interface.c */
void db_machine_init(void);

#endif /* _DDB_DB_INTERFACE_H_ */


code:
/*	$OpenBSD: db_lex.c,v 1.12 2015/03/14 03:38:46 jsg Exp $	*/
/*	$NetBSD: db_lex.c,v 1.8 1996/02/05 01:57:05 christos Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993,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
 */

/*
 * Lexical analyzer.
 */
#include <sys/param.h>
#include <sys/systm.h>

#include <machine/db_machdep.h>

#include <ddb/db_lex.h>
#include <ddb/db_output.h>
#include <ddb/db_command.h>
#include <ddb/db_extern.h>
#include <ddb/db_var.h>

char	db_line[120];
char *	db_lp, *db_endlp;

db_expr_t db_tok_number;
char	db_tok_string[TOK_STRING_SIZE];

int
db_read_line(void)
{
	int	i;

	i = db_readline(db_line, sizeof(db_line));
	if (i == 0)
	    return (0);	/* EOI */
	db_lp = db_line;
	db_endlp = db_lp + i;
	return (i);
}

void
db_flush_line(void)
{
	db_lp = db_line;
	db_endlp = db_line;
}

int	db_look_char = 0;

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;
}

int	db_look_token = 0;

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
	    t = db_lex();
	return (t);
}

void
db_flush_lex(void)
{
	db_flush_line();
	db_look_char = 0;
	db_look_token = 0;
}

int
db_lex(void)
{
	int	c;

	c = db_read_char();
	while (c <= ' ' || c > '~') {
	    if (c == '\n' || c == -1)
		return (tEOL);
	    c = db_read_char();
	}

	if (c >= '0' && c <= '9') {
	    /* number */
	    int	r, digit = 0;

	    if (c > '0')
		r = db_radix;
	    else {
		c = db_read_char();
		if (c == 'O' || c == 'o')
		    r = 8;
		else if (c == 'T' || c == 't')
		    r = 10;
		else if (c == 'X' || c == 'x')
		    r = 16;
		else {
		    r = db_radix;
		    db_unread_char(c);
		}
		c = db_read_char();
	    }
	    db_tok_number = 0;
	    for (;;) {
		if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
		    digit = c - '0';
		else if (r == 16 && ((c >= 'A' && c <= 'F') ||
				     (c >= 'a' && c <= 'f'))) {
		    if (c >= 'a')
			digit = c - 'a' + 10;
		    else if (c >= 'A')
			digit = c - 'A' + 10;
		}
		else
		    break;
		db_tok_number = db_tok_number * r + digit;
		c = db_read_char();
	    }
	    if ((c >= '0' && c <= '9') ||
		(c >= 'A' && c <= 'Z') ||
		(c >= 'a' && c <= 'z') ||
		(c == '_'))
	    {
		db_error("Bad character in number\n");
		/*NOTREACHED*/
	    }
	    db_unread_char(c);
	    return (tNUMBER);
	}
	if ((c >= 'A' && c <= 'Z') ||
	    (c >= 'a' && c <= 'z') ||
	    c == '_' || c == '\\')
	{
	    /* string */
	    char *cp;

	    cp = db_tok_string;
	    if (c == '\\') {
		c = db_read_char();
		if (c == '\n' || c == -1) {
		    db_error("Bad escape\n");
		    /*NOTREACHED*/
		}
	    }
	    *cp++ = c;
	    while (1) {
		c = db_read_char();
		if ((c >= 'A' && c <= 'Z') ||
		    (c >= 'a' && c <= 'z') ||
		    (c >= '0' && c <= '9') ||
		    c == '_' || c == '\\' || c == ':')
		{
		    if (c == '\\') {
			c = db_read_char();
			if (c == '\n' || c == -1) {
			    db_error("Bad escape\n");
			    /*NOTREACHED*/
			}
		    }
		    *cp++ = c;
		    if (cp == db_tok_string+sizeof(db_tok_string)) {
			db_error("String too long\n");
			/*NOTREACHED*/
		    }
		    continue;
		}
		else {
		    *cp = '\0';
		    break;
		}
	    }
	    db_unread_char(c);
	    return (tIDENT);
	}

	switch (c) {
	    case '+':
		return (tPLUS);
	    case '-':
		return (tMINUS);
	    case '.':
		c = db_read_char();
		if (c == '.')
		    return (tDOTDOT);
		db_unread_char(c);
		return (tDOT);
	    case '*':
		return (tSTAR);
	    case '/':
		return (tSLASH);
	    case '=':
		return (tEQ);
	    case '%':
		return (tPCT);
	    case '#':
		return (tHASH);
	    case '(':
		return (tLPAREN);
	    case ')':
		return (tRPAREN);
	    case ',':
		return (tCOMMA);
	    case '"':
		return (tDITTO);
	    case '$':
		return (tDOLLAR);
	    case '!':
		return (tEXCL);
	    case '<':
		c = db_read_char();
		if (c == '<')
		    return (tSHIFT_L);
		db_unread_char(c);
		break;
	    case '>':
		c = db_read_char();
		if (c == '>')
		    return (tSHIFT_R);
		db_unread_char(c);
		break;
	    case -1:
		return (tEOF);
	}
	db_printf("Bad character\n");
	db_flush_lex();
	return (tEOF);
}


code:
/*	$OpenBSD: db_lex.h,v 1.7 2002/07/01 21:56:55 miod Exp $	*/
/*	$NetBSD: db_lex.h,v 1.7 1996/02/05 01:57:07 christos Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993,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
 */

/*
 * Lexical analyzer.
 */
int db_read_line(void);
void db_flush_line(void);
int db_read_char(void);
void db_unread_char(int);
void db_unread_token(int);
int db_read_token(void);
void db_flush_lex(void);
int db_lex(void);

extern db_expr_t db_tok_number;
#define	TOK_STRING_SIZE		120
extern char db_tok_string[TOK_STRING_SIZE];

#define	tEOF		(-1)
#define	tEOL		1
#define	tNUMBER		2
#define	tIDENT		3
#define	tPLUS		4
#define	tMINUS		5
#define	tDOT		6
#define	tSTAR		7
#define	tSLASH		8
#define	tEQ		9
#define	tLPAREN		10
#define	tRPAREN		11
#define	tPCT		12
#define	tHASH		13
#define	tCOMMA		14
#define	tDITTO		15
#define	tDOLLAR		16
#define	tEXCL		17
#define	tSHIFT_L	18
#define	tSHIFT_R	19
#define	tDOTDOT		20


code:
/*	$OpenBSD: db_output.c,v 1.29 2015/03/14 03:38:46 jsg Exp $	*/
/*	$NetBSD: db_output.c,v 1.13 1996/04/01 17:27:14 christos Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993,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.
 */

/*
 * Printf and character output for debugger.
 */
#include <sys/param.h>
#include <sys/stdarg.h>
#include <sys/systm.h>

#include <dev/cons.h>

#include <machine/db_machdep.h>

#include <ddb/db_command.h>
#include <ddb/db_output.h>
#include <ddb/db_interface.h>
#include <ddb/db_sym.h>
#include <ddb/db_var.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 */
int	db_radix = 16;			/* output numbers radix */

static void db_more(void);

/*
 * 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) {
		while (last_print < next_tab) { /* DON'T send a tab!!! */
			cnputc(' ');
			last_print++;
		}
	    }
	    else {
		cnputc(' ');
		last_print++;
	    }
	}
	db_last_non_space = db_output_position;
}

static void
db_more(void)
{
	char *p;
	int quit_output = 0;

	for (p = "--db_more--"; *p; p++)
	    cnputc(*p);
	switch(cngetc()) {
	case ' ':
	    db_output_line = 0;
	    break;
	case 'q':
	case CTRL('c'):
	    db_output_line = 0;
	    quit_output = 1;
	    break;
	default:
	    db_output_line--;
	    break;
	}
	p = "\b\b\b\b\b\b\b\b\b\b\b           \b\b\b\b\b\b\b\b\b\b\b";
	while (*p)
	    cnputc(*p++);
	if (quit_output) {
	    db_error(0);
	    /* NOTREACHED */
	}
}

/*
 * Output character.  Buffer whitespace.
 */
void
db_putchar(int c)
{
	if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1)
	    db_more();

	if (c > ' ' && c <= '~') {
	    /*
	     * Printing character.
	     * If we have spaces to print, print them first.
	     * Use tabs if possible.
	     */
	    db_force_whitespace();
	    cnputc(c);
	    db_output_position++;
	    if (db_max_width >= DB_MIN_MAX_WIDTH
		&& db_output_position >= db_max_width-1) {
		/* auto new line */
		cnputc('\n');
		db_output_position = 0;
		db_last_non_space = 0;
		db_output_line++;
	    }
	    db_last_non_space = db_output_position;
	}
	else if (c == '\n') {
	    /* Return */
	    cnputc(c);
	    db_output_position = 0;
	    db_last_non_space = 0;
	    db_output_line++;
	}
	else if (c == '\t') {
	    /* assume tabs every 8 positions */
	    db_output_position = NEXT_TAB(db_output_position);
	}
	else if (c == ' ') {
	    /* space */
	    db_output_position++;
	}
	else if (c == '\007') {
	    /* bell */
	    cnputc(c);
	}
	/* other characters are assumed non-printing */
}

/*
 * Return output position
 */
int
db_print_position(void)
{
	return (db_output_position);
}

/*
 * End line if too long.
 */
void
db_end_line(int space)
{
	if (db_output_position >= db_max_width - space)
	    db_printf("\n");
}

char *
db_format(char *buf, size_t bufsize, long val, int format, int alt, int width)
{
	const char *fmt;

	if (format == DB_FORMAT_Z || db_radix == 16)
		fmt = alt ? "-%#*lx" : "-%*lx";
	else if (db_radix == 8)
		fmt = alt ? "-%#*lo" : "-%*lo";
	else
		fmt = alt ? "-%#*lu" : "-%*lu";

	/* The leading '-' is a nasty (and beautiful) idea from NetBSD */
	if (val < 0 && format != DB_FORMAT_N)
		val = -val;
	else
		fmt++;

	snprintf(buf, bufsize, fmt, width, val);

	return (buf);
}

void
db_stack_dump(void)
{
	static int intrace;

	if (intrace) {
		printf("Faulted in traceback, aborting...\n");
		return;
	}

	intrace = 1;
	printf("Starting stack trace...\n");
	db_stack_trace_print((db_expr_t)__builtin_frame_address(0), TRUE,
	    256 /* low limit */, "", printf);
	printf("End of stack trace.\n");
	intrace = 0;
}


code:
/*	$OpenBSD: db_output.h,v 1.16 2013/12/12 21:00:09 guenther Exp $ */
/*	$NetBSD: db_output.h,v 1.9 1996/04/04 05:13:50 cgd Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993,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:	8/90
 */

/*
 * Printing routines for kernel debugger.
 */
void db_force_whitespace(void);
void db_putchar(int);
int db_print_position(void);
int db_printf(const char *, ...)
    __attribute__((__format__(__kprintf__,1,2)));
int db_vprintf(const char *, va_list)
    __attribute__((__format__(__kprintf__,1,0)));
void db_end_line(int);

/*
 * This is a replacement for the non-standard %z, %n and %r printf formats
 * in db_printf.
 *
 * db_format(buf, bufsize, val, format, alt, width)
 *
 * val is the value we want printed.
 * format is one of DB_FORMAT_[ZRN]
 * alt specifies if we should provide an "alternate" format (# in the printf
 *   format).
 * width is the field width. 0 is the same as no width specifier.
 */
#define DB_FORMAT_Z	1
#define DB_FORMAT_R	2
#define DB_FORMAT_N	3
#define DB_FORMAT_BUF_SIZE	64	/* should be plenty for all formats */
char *db_format(char *, size_t, long, int, int, int);

/* XXX - this is the wrong place, but we have no better. */
void db_stack_dump(void);


code:
/*	$OpenBSD: db_print.c,v 1.15 2015/03/14 03:38:46 jsg Exp $	*/
/*	$NetBSD: db_print.c,v 1.5 1996/02/05 01:57:11 christos Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993,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
 */

/*
 * Miscellaneous printing.
 */
#include <sys/param.h>
#include <sys/systm.h>

#include <machine/db_machdep.h>

#include <ddb/db_variables.h>
#include <ddb/db_sym.h>
#include <ddb/db_output.h>
#include <ddb/db_extern.h>

/*ARGSUSED*/
void
db_show_regs(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	struct db_variable *regp;
	db_expr_t	value, offset;
	char *		name;
	char		tmpfmt[28];

	for (regp = db_regs; regp < db_eregs; regp++) {
	    db_read_variable(regp, &value);
	    db_printf("%-12s%s", regp->name, db_format(tmpfmt, sizeof tmpfmt,
	      (long)value, DB_FORMAT_N, 1, sizeof(long) * 3));
	    db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset);
	    if (name != 0 && offset <= db_maxoff && offset != value) {
		db_printf("\t%s", name);
		if (offset != 0)
		    db_printf("+%s", db_format(tmpfmt, sizeof tmpfmt,
		      (long)offset, DB_FORMAT_R, 1, 0));
	    }
	    db_printf("\n");
	}
	db_print_loc_and_inst(PC_REGS(DDB_REGS));
}