2262 lines
60 KiB
C
2262 lines
60 KiB
C
/* dlite.c - DLite, the lite debugger, routines */
|
|
|
|
/* SimpleScalar(TM) Tool Suite
|
|
* Copyright (C) 1994-2003 by Todd M. Austin, Ph.D. and SimpleScalar, LLC.
|
|
* All Rights Reserved.
|
|
*
|
|
* THIS IS A LEGAL DOCUMENT, BY USING SIMPLESCALAR,
|
|
* YOU ARE AGREEING TO THESE TERMS AND CONDITIONS.
|
|
*
|
|
* No portion of this work may be used by any commercial entity, or for any
|
|
* commercial purpose, without the prior, written permission of SimpleScalar,
|
|
* LLC (info@simplescalar.com). Nonprofit and noncommercial use is permitted
|
|
* as described below.
|
|
*
|
|
* 1. SimpleScalar is provided AS IS, with no warranty of any kind, express
|
|
* or implied. The user of the program accepts full responsibility for the
|
|
* application of the program and the use of any results.
|
|
*
|
|
* 2. Nonprofit and noncommercial use is encouraged. SimpleScalar may be
|
|
* downloaded, compiled, executed, copied, and modified solely for nonprofit,
|
|
* educational, noncommercial research, and noncommercial scholarship
|
|
* purposes provided that this notice in its entirety accompanies all copies.
|
|
* Copies of the modified software can be delivered to persons who use it
|
|
* solely for nonprofit, educational, noncommercial research, and
|
|
* noncommercial scholarship purposes provided that this notice in its
|
|
* entirety accompanies all copies.
|
|
*
|
|
* 3. ALL COMMERCIAL USE, AND ALL USE BY FOR PROFIT ENTITIES, IS EXPRESSLY
|
|
* PROHIBITED WITHOUT A LICENSE FROM SIMPLESCALAR, LLC (info@simplescalar.com).
|
|
*
|
|
* 4. No nonprofit user may place any restrictions on the use of this software,
|
|
* including as modified by the user, by any other authorized user.
|
|
*
|
|
* 5. Noncommercial and nonprofit users may distribute copies of SimpleScalar
|
|
* in compiled or executable form as set forth in Section 2, provided that
|
|
* either: (A) it is accompanied by the corresponding machine-readable source
|
|
* code, or (B) it is accompanied by a written offer, with no time limit, to
|
|
* give anyone a machine-readable copy of the corresponding source code in
|
|
* return for reimbursement of the cost of distribution. This written offer
|
|
* must permit verbatim duplication by anyone, or (C) it is distributed by
|
|
* someone who received only the executable form, and is accompanied by a
|
|
* copy of the written offer of source code.
|
|
*
|
|
* 6. SimpleScalar was developed by Todd M. Austin, Ph.D. The tool suite is
|
|
* currently maintained by SimpleScalar LLC (info@simplescalar.com). US Mail:
|
|
* 2395 Timbercrest Court, Ann Arbor, MI 48105.
|
|
*
|
|
* Copyright (C) 1994-2003 by Todd M. Austin, Ph.D. and SimpleScalar, LLC.
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
|
|
#include "host.h"
|
|
#include "misc.h"
|
|
#include "machine.h"
|
|
#include "version.h"
|
|
#include "eval.h"
|
|
#include "regs.h"
|
|
#include "memory.h"
|
|
#include "sim.h"
|
|
#include "symbol.h"
|
|
#include "loader.h"
|
|
#include "options.h"
|
|
#include "stats.h"
|
|
#include "range.h"
|
|
#include "dlite.h"
|
|
|
|
/* architected state accessors, initialized by dlite_init() */
|
|
static dlite_reg_obj_t f_dlite_reg_obj = NULL;
|
|
static dlite_mem_obj_t f_dlite_mem_obj = NULL;
|
|
static dlite_mstate_obj_t f_dlite_mstate_obj = NULL;
|
|
|
|
/* set non-zero to enter DLite after next instruction */
|
|
int dlite_active = FALSE;
|
|
|
|
/* non-zero to force a check for a break */
|
|
int dlite_check = FALSE;
|
|
|
|
/* set non-zero to exit DLite command loop */
|
|
static int dlite_return = FALSE;
|
|
|
|
/* size modifier mask bit definitions */
|
|
#define MOD_BYTE 0x0001 /* b - print a byte */
|
|
#define MOD_HALF 0x0002 /* h - print a half (short) */
|
|
#define MOD_WORD 0x0004 /* w - print a word */
|
|
#define MOD_QWORD 0x0008 /* q - print a qword */
|
|
#define MOD_FLOAT 0x0010 /* F - print a float */
|
|
#define MOD_DOUBLE 0x0020 /* f - print a double */
|
|
#define MOD_CHAR 0x0040 /* c - print a character */
|
|
#define MOD_STRING 0x0080 /* s - print a string */
|
|
|
|
#define MOD_SIZES \
|
|
(MOD_BYTE|MOD_HALF|MOD_WORD|MOD_QWORD \
|
|
|MOD_FLOAT|MOD_DOUBLE|MOD_CHAR|MOD_STRING)
|
|
|
|
/* format modifier mask bit definitions */
|
|
#define MOD_DECIMAL 0x0100 /* d - print in decimal format */
|
|
#define MOD_UNSIGNED 0x0200 /* u - print in unsigned format */
|
|
#define MOD_OCTAL 0x0400 /* o - print in octal format */
|
|
#define MOD_HEX 0x0800 /* x - print in hex format */
|
|
#define MOD_BINARY 0x1000 /* 1 - print in binary format */
|
|
|
|
#define MOD_FORMATS \
|
|
(MOD_DECIMAL|MOD_UNSIGNED|MOD_OCTAL|MOD_HEX|MOD_BINARY)
|
|
|
|
|
|
/* DLite modifier parser, transforms /<mods> strings to modifier mask */
|
|
static char * /* error string, NULL for no err */
|
|
modifier_parser(char *p, /* ptr to /<mods> string */
|
|
char **endp, /* ptr to first byte not consumed */
|
|
int *pmod) /* modifier mask written to *PMOD */
|
|
{
|
|
int modifiers = 0;
|
|
|
|
/* default modifiers */
|
|
*pmod = 0;
|
|
|
|
/* is this a valid modifier? */
|
|
if (*p == '/')
|
|
{
|
|
p++;
|
|
/* parse modifiers until end-of-string or whitespace is found */
|
|
while (*p != '\0' && *p != '\n' && *p != ' ' && *p != '\t')
|
|
{
|
|
switch (*p)
|
|
{
|
|
case 'b':
|
|
modifiers |= MOD_BYTE;
|
|
break;
|
|
case 'h':
|
|
modifiers |= MOD_HALF;
|
|
break;
|
|
case 'w':
|
|
modifiers |= MOD_WORD;
|
|
break;
|
|
case 'q':
|
|
modifiers |= MOD_QWORD;
|
|
break;
|
|
case 'd':
|
|
modifiers |= MOD_DECIMAL;
|
|
break;
|
|
case 'u':
|
|
modifiers |= MOD_UNSIGNED;
|
|
break;
|
|
case 'o':
|
|
modifiers |= MOD_OCTAL;
|
|
break;
|
|
case 'x':
|
|
modifiers |= MOD_HEX;
|
|
break;
|
|
case '1':
|
|
modifiers |= MOD_BINARY;
|
|
break;
|
|
case 'F':
|
|
modifiers |= MOD_FLOAT;
|
|
break;
|
|
case 'f':
|
|
modifiers |= MOD_DOUBLE;
|
|
break;
|
|
case 'c':
|
|
modifiers |= MOD_CHAR;
|
|
break;
|
|
case 's':
|
|
modifiers |= MOD_STRING;
|
|
break;
|
|
default:
|
|
return "bad modifier (use one or more of /bhwqduox1fdcs)";
|
|
}
|
|
p++;
|
|
}
|
|
}
|
|
|
|
/* no error, return end of string and modifier mask */
|
|
*endp = p;
|
|
*pmod = modifiers;
|
|
return NULL;
|
|
}
|
|
|
|
/* DLite default expression evaluator */
|
|
static struct eval_state_t *dlite_evaluator = NULL;
|
|
static struct regs_t *local_regs = NULL;
|
|
|
|
/* DLite identifier evaluator, used by the expression evaluator, returns
|
|
the value of the ident in ES->TOK_BUF, sets eval_error to value other
|
|
than ERR_NOERR if an error is encountered */
|
|
static struct eval_value_t /* value of identifier */
|
|
ident_evaluator(struct eval_state_t *es) /* expression evaluator */
|
|
{
|
|
int i;
|
|
char *err_str;
|
|
struct eval_value_t val;
|
|
struct stat_stat_t *stat;
|
|
struct sym_sym_t *sym;
|
|
static struct eval_value_t err_value = { et_int, { 0 } };
|
|
|
|
/* is this a builtin register definition? */
|
|
for (i=0; md_reg_names[i].str != NULL; i++)
|
|
{
|
|
if (!mystricmp(es->tok_buf, md_reg_names[i].str))
|
|
{
|
|
err_str =
|
|
f_dlite_reg_obj(local_regs, /* !is_write */FALSE,
|
|
md_reg_names[i].file, md_reg_names[i].reg, &val);
|
|
if (err_str)
|
|
{
|
|
eval_error = ERR_UNDEFVAR;
|
|
val = err_value;
|
|
}
|
|
return val;
|
|
}
|
|
}
|
|
|
|
/* else, try to locate a program symbol */
|
|
sym_loadsyms(ld_prog_fname, /* load locals */TRUE);
|
|
sym = sym_bind_name(es->tok_buf, NULL, sdb_any);
|
|
if (sym)
|
|
{
|
|
/* found a symbol with this name, return it's (address) value */
|
|
val.type = et_addr;
|
|
val.value.as_addr = sym->addr;
|
|
return val;
|
|
}
|
|
|
|
/* else, try to locate a statistical value symbol */
|
|
stat = stat_find_stat(sim_sdb, es->tok_buf);
|
|
if (stat)
|
|
{
|
|
/* found it, convert stat value to an eval_value_t value */
|
|
switch (stat->sc)
|
|
{
|
|
case sc_int:
|
|
val.type = et_int;
|
|
val.value.as_int = *stat->variant.for_int.var;
|
|
break;
|
|
case sc_uint:
|
|
val.type = et_uint;
|
|
val.value.as_uint = *stat->variant.for_uint.var;
|
|
break;
|
|
#ifdef HOST_HAS_QWORD
|
|
case sc_qword:
|
|
val.type = et_qword;
|
|
val.value.as_qword = *stat->variant.for_qword.var;
|
|
break;
|
|
#endif /* HOST_HAS_QWORD */
|
|
case sc_float:
|
|
val.type = et_float;
|
|
val.value.as_float = *stat->variant.for_float.var;
|
|
break;
|
|
case sc_double:
|
|
val.type = et_double;
|
|
val.value.as_double = *stat->variant.for_double.var;
|
|
break;
|
|
case sc_dist:
|
|
case sc_sdist:
|
|
eval_error = ERR_BADEXPR;
|
|
val = err_value;
|
|
break;
|
|
case sc_formula:
|
|
{
|
|
/* instantiate a new evaluator to avoid recursion problems */
|
|
struct eval_state_t *es = eval_new(ident_evaluator, sim_sdb);
|
|
char *endp;
|
|
|
|
val = eval_expr(es, stat->variant.for_formula.formula, &endp);
|
|
if (eval_error != ERR_NOERR || *endp != '\0')
|
|
{
|
|
/* pass through eval_error */
|
|
val = err_value;
|
|
}
|
|
/* else, use value returned */
|
|
eval_delete(es);
|
|
}
|
|
break;
|
|
default:
|
|
panic("bogus stat class");
|
|
}
|
|
return val;
|
|
}
|
|
/* else, not found */
|
|
|
|
/* else, this is a bogus symbol */
|
|
eval_error = ERR_UNDEFVAR;
|
|
val = err_value;
|
|
return val;
|
|
}
|
|
|
|
/* maximum number of arguments that can passed to a dlite command handler */
|
|
#define MAX_ARGS 4
|
|
|
|
/* maximum length of a dlite command string argument */
|
|
#define MAX_STR 128
|
|
|
|
/* argument array entry, argument arrays are passed to command handlers */
|
|
union arg_val_t {
|
|
int as_modifier;
|
|
struct eval_value_t as_value;
|
|
int as_access;
|
|
char as_str[MAX_STR];
|
|
};
|
|
|
|
/* a DLite command handler function pointer */
|
|
typedef char * /* err str, NULL for no err */
|
|
(*cmd_fn_t)(int nargs, /* number of arguments */
|
|
union arg_val_t args[], /* argument vector */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem); /* memory to access */
|
|
|
|
/* DLite command descriptor, fully describes a command supported by the
|
|
DLite debugger command handler */
|
|
struct dlite_cmd_t {
|
|
char *cmd_str; /* DLite command string */
|
|
char *arg_strs[MAX_ARGS]; /* NULL-terminated cmd args (? - optional):
|
|
m - size/type modifiers
|
|
a - address expression
|
|
c - count expression
|
|
e - any expression
|
|
s - any string
|
|
t - access type {r|w|x}
|
|
i - breakpoint id */
|
|
cmd_fn_t cmd_fn; /* implementing function */
|
|
char *help_str; /* DLite command help string */
|
|
};
|
|
|
|
/* forward handler decls */
|
|
static char *
|
|
dlite_help(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_version(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_terminate(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_quit(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_cont(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_step(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_print(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_options(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_option(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_stats(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_stat(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_whatis(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_regs(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_iregs(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_fpregs(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_cregs(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_mstate(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_display(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_dump(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_dis(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_break(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_dbreak(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_rbreak(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_breaks(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_delete(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_clear(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_symbols(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_tsymbols(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_dsymbols(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
static char *
|
|
dlite_symbol(int nargs, union arg_val_t args[],
|
|
struct regs_t *regs, struct mem_t *mem);
|
|
|
|
/* DLite debugger command parser command definitions, NOTE: optional
|
|
arguments must be trailing arguments, otherwise the command parser will
|
|
break (modifiers are an exception to this rule) */
|
|
static struct dlite_cmd_t cmd_db[] =
|
|
{
|
|
{ "help", { "s?", NULL }, dlite_help,
|
|
"print command reference" },
|
|
{ "version", { NULL }, dlite_version,
|
|
"print DLite version information" },
|
|
{ "terminate", { NULL }, dlite_terminate,
|
|
"terminate the simulation with statistics" },
|
|
{ "quit", { NULL }, dlite_quit,
|
|
"exit the simulator" },
|
|
{ "cont", { "a?", NULL }, dlite_cont,
|
|
"continue program execution (optionally at <addr>)" },
|
|
{ "step", { NULL }, dlite_step,
|
|
"step program one instruction" },
|
|
#if 0 /* NYI */
|
|
{ "next", { NULL }, dlite_next,
|
|
"step program one instruction in current procedure" },
|
|
#endif
|
|
{ "print", { "m?", "e", NULL }, dlite_print,
|
|
"print the value of <expr> using format <modifiers>" },
|
|
{ "options", { NULL }, dlite_options,
|
|
"print the value of all options" },
|
|
{ "option", { "s", NULL }, dlite_option,
|
|
"print the value of an option" },
|
|
{ "stats", { NULL }, dlite_stats,
|
|
"print the value of all statistical variables" },
|
|
{ "stat", { "s", NULL }, dlite_stat,
|
|
"print the value of a statistical variable" },
|
|
{ "whatis", { "e", NULL }, dlite_whatis,
|
|
"print the type of expression <expr>" },
|
|
{ "---", { NULL }, NULL, NULL },
|
|
{ "regs", { NULL }, dlite_regs,
|
|
"print all register contents" },
|
|
{ "iregs", { NULL }, dlite_iregs,
|
|
"print integer register contents" },
|
|
{ "fpregs", { NULL }, dlite_fpregs,
|
|
"print floating point register contents" },
|
|
{ "cregs", { NULL }, dlite_cregs,
|
|
"print control register contents" },
|
|
{ "mstate", { "s?", NULL }, dlite_mstate,
|
|
"print machine specific state (simulator dependent)" },
|
|
{ "display", { "m?", "a", NULL }, dlite_display,
|
|
"display the value at memory location <addr> using format <modifiers>" },
|
|
{ "dump", { "a?", "c?", NULL }, dlite_dump,
|
|
"dump memory at <addr> (optionally for <cnt> words)" },
|
|
{ "dis", { "a?", "c?", NULL }, dlite_dis,
|
|
"disassemble instructions at <addr> (for <cnt> insts)" },
|
|
{ "break", { "a", NULL }, dlite_break,
|
|
"set breakpoint at <addr>, returns <id> of breakpoint" },
|
|
{ "dbreak", { "a", "t?", NULL }, dlite_dbreak,
|
|
"set data breakpoint at <addr> (for (r)ead, (w)rite,\n"
|
|
" and/or e(x)ecute, returns <id> of breakpoint" },
|
|
{ "rbreak", { "s", "t?", NULL }, dlite_rbreak,
|
|
"set read/write/exec breakpoint at <range> (for (r)ead, (w)rite,\n"
|
|
" and/or e(x)ecute, returns <id> of breakpoint" },
|
|
{ "breaks", { NULL }, dlite_breaks,
|
|
"list active code and data breakpoints" },
|
|
{ "delete", { "i", NULL }, dlite_delete,
|
|
"delete breakpoint <id>" },
|
|
{ "clear", { NULL }, dlite_clear,
|
|
"clear all breakpoints (code and data)" },
|
|
{ "---", { NULL }, NULL, NULL },
|
|
{ "symbols", { NULL }, dlite_symbols,
|
|
"print the value of all program symbols" },
|
|
{ "tsymbols", { NULL }, dlite_tsymbols,
|
|
"print the value of all program text symbols" },
|
|
{ "dsymbols", { NULL }, dlite_dsymbols,
|
|
"print the value of all program data symbols" },
|
|
{ "symbol", { "s", NULL }, dlite_symbol,
|
|
"print the value of a symbol" },
|
|
{ "---", { NULL }, NULL, NULL },
|
|
/* list terminator */
|
|
{ NULL, { NULL }, NULL, NULL }
|
|
};
|
|
|
|
/* help command trailing text */
|
|
static char *dlite_help_tail =
|
|
"Arguments <addr>, <cnt>, <expr>, and <id> are any legal expression:\n"
|
|
" <expr> <- <factor> +|- <expr>\n"
|
|
" <factor> <- <term> *|/ <factor>\n"
|
|
" <term> <- ( <expr> )\n"
|
|
" | - <term>\n"
|
|
" | <const>\n"
|
|
" | <symbol>\n"
|
|
" | <file:loc>\n"
|
|
"\n"
|
|
"Command modifiers <mods> are any of the following:\n"
|
|
"\n"
|
|
" b - print a byte\n"
|
|
" h - print a half (short)\n"
|
|
" w - print a word (default)\n"
|
|
#ifdef HOST_HAS_QWORD
|
|
" q - print a qword\n"
|
|
#endif /* HOST_HAS_QWORD */
|
|
" F - print a float\n"
|
|
" f - print a double\n"
|
|
" c - print a character\n"
|
|
" s - print a string\n"
|
|
" d - print in decimal format (default)\n"
|
|
" u - print in unsigned decimal format\n"
|
|
" o - print in octal format\n"
|
|
" x - print in hex format\n"
|
|
" 1 - print in binary format\n";
|
|
|
|
|
|
/* execute DLite command string CMD */
|
|
static char * /* err str, NULL if no err */
|
|
dlite_exec(char *cmd_str, /* command string */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int i, arg_cnt;
|
|
struct dlite_cmd_t *cmd;
|
|
char cmd_buf[512], *p, *q, *endp;
|
|
union arg_val_t args[MAX_ARGS];
|
|
|
|
p = cmd_str;
|
|
q = cmd_buf;
|
|
|
|
/* skip any whitespace before argument */
|
|
while (*p == ' ' || *p == '\t' || *p == '\n')
|
|
p++;
|
|
|
|
/* anything left? */
|
|
if (*p == '\0')
|
|
{
|
|
/* NOP, no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* copy out command name string */
|
|
while (*p != '\0' && *p != '\n' && *p != ' ' && *p != '\t' && *p != '/')
|
|
*q++ = *p++;
|
|
*q = '\0';
|
|
|
|
/* find matching command */
|
|
for (cmd=cmd_db; cmd->cmd_str != NULL; cmd++)
|
|
{
|
|
if (!strcmp(cmd->cmd_str, cmd_buf))
|
|
break;
|
|
}
|
|
if (cmd->cmd_str == NULL)
|
|
return "unknown command";
|
|
|
|
/* match arguments for *CMD */
|
|
for (i=0, arg_cnt=0; i<MAX_ARGS && cmd->arg_strs[i] != NULL; i++, arg_cnt++)
|
|
{
|
|
int optional, access, modifiers;
|
|
char *arg, arg_type, *err_str;
|
|
struct eval_value_t val;
|
|
|
|
/* skip any whitespace before argument */
|
|
while (*p == ' ' || *p == '\t' || *p == '\n')
|
|
p++;
|
|
|
|
arg = cmd->arg_strs[i];
|
|
arg_type = arg[0];
|
|
optional = (arg[1] == '?');
|
|
|
|
if (*p == '\0')
|
|
{
|
|
if (optional)
|
|
{
|
|
/* all arguments parsed */
|
|
break;
|
|
}
|
|
else
|
|
return "missing an argument";
|
|
}
|
|
|
|
endp = p;
|
|
switch (arg_type)
|
|
{
|
|
case 'm':
|
|
err_str = modifier_parser(p, &endp, &modifiers);
|
|
if (err_str)
|
|
return err_str;
|
|
args[arg_cnt].as_modifier = modifiers;
|
|
break;
|
|
case 'a':
|
|
local_regs = regs;
|
|
val = eval_expr(dlite_evaluator, p, &endp);
|
|
if (eval_error)
|
|
return eval_err_str[eval_error];
|
|
args[arg_cnt].as_value = val;
|
|
break;
|
|
case 'c':
|
|
local_regs = regs;
|
|
val = eval_expr(dlite_evaluator, p, &endp);
|
|
if (eval_error)
|
|
return eval_err_str[eval_error];
|
|
args[arg_cnt].as_value = val;
|
|
break;
|
|
case 'e':
|
|
local_regs = regs;
|
|
val = eval_expr(dlite_evaluator, p, &endp);
|
|
if (eval_error)
|
|
return eval_err_str[eval_error];
|
|
args[arg_cnt].as_value = val;
|
|
break;
|
|
case 't':
|
|
access = 0;
|
|
while (*p != '\0' && *p != '\n' && *p != ' ' && *p != '\t')
|
|
{
|
|
switch (*p)
|
|
{
|
|
case 'r':
|
|
access |= ACCESS_READ;
|
|
break;
|
|
case 'w':
|
|
access |= ACCESS_WRITE;
|
|
break;
|
|
case 'x':
|
|
access |= ACCESS_EXEC;
|
|
break;
|
|
default:
|
|
return "bad access type specifier (use r|w|x)";
|
|
}
|
|
p++;
|
|
}
|
|
endp = p;
|
|
args[arg_cnt].as_access = access;
|
|
break;
|
|
case 'i':
|
|
local_regs = regs;
|
|
val = eval_expr(dlite_evaluator, p, &endp);
|
|
if (eval_error)
|
|
return eval_err_str[eval_error];
|
|
args[arg_cnt].as_value = val;
|
|
break;
|
|
case 's':
|
|
q = args[arg_cnt].as_str;
|
|
while (*p != ' ' && *p != '\t' && *p != '\0')
|
|
*q++ = *p++;
|
|
*q = '\0';
|
|
endp = p;
|
|
break;
|
|
default:
|
|
panic("bogus argument type: `%c'", arg_type);
|
|
}
|
|
p = endp;
|
|
}
|
|
|
|
|
|
/* skip any whitespace before any trailing argument */
|
|
while (*p == ' ' || *p == '\t' || *p == '\n')
|
|
p++;
|
|
|
|
/* check for any orphan arguments */
|
|
if (*p != '\0')
|
|
return "too many arguments";
|
|
|
|
/* if we reach here, all arguments were parsed correctly, call handler */
|
|
return cmd->cmd_fn(arg_cnt, args, regs, mem);
|
|
}
|
|
|
|
/* print expression value VAL using modifiers MODIFIERS */
|
|
static char * /* err str, NULL for no err */
|
|
print_val(int modifiers, /* print modifiers */
|
|
struct eval_value_t val) /* expr value to print */
|
|
{
|
|
char *format = "", *prefix = "", radix, buf[512];
|
|
|
|
/* fill in any default size */
|
|
if ((modifiers & MOD_SIZES) == 0)
|
|
{
|
|
/* compute default size */
|
|
switch (val.type)
|
|
{
|
|
case et_int: modifiers |= MOD_WORD; break;
|
|
case et_uint: modifiers |= MOD_WORD; break;
|
|
case et_addr:
|
|
#ifdef HOST_HAS_QWORD
|
|
if (sizeof(md_addr_t) > 4)
|
|
modifiers |= MOD_QWORD;
|
|
else
|
|
#endif /* HOST_HAS_QWORD */
|
|
modifiers |= MOD_WORD;
|
|
break;
|
|
#ifdef HOST_HAS_QWORD
|
|
case et_qword: modifiers |= MOD_QWORD; break;
|
|
case et_sqword: modifiers |= MOD_QWORD; break;
|
|
#endif /* HOST_HAS_QWORD */
|
|
case et_float: modifiers |= MOD_FLOAT; break;
|
|
case et_double: modifiers |= MOD_DOUBLE; break;
|
|
case et_symbol:
|
|
default: return "bad print value";
|
|
}
|
|
}
|
|
if (((modifiers & MOD_SIZES) & ((modifiers & MOD_SIZES) - 1)) != 0)
|
|
return "multiple size specifiers";
|
|
|
|
/* fill in any default format */
|
|
if ((modifiers & MOD_FORMATS) == 0)
|
|
{
|
|
/* compute default size */
|
|
switch (val.type)
|
|
{
|
|
case et_int: modifiers |= MOD_DECIMAL; break;
|
|
case et_uint: modifiers |= MOD_UNSIGNED; break;
|
|
case et_addr: modifiers |= MOD_HEX; break;
|
|
#ifdef HOST_HAS_QWORD
|
|
case et_qword: modifiers |= MOD_UNSIGNED; break;
|
|
case et_sqword: modifiers |= MOD_DECIMAL; break;
|
|
#endif /* HOST_HAS_QWORD */
|
|
case et_float: /* use default format */break;
|
|
case et_double: /* use default format */break;
|
|
case et_symbol:
|
|
default: return "bad print value";
|
|
}
|
|
}
|
|
if (((modifiers & MOD_FORMATS) & ((modifiers & MOD_FORMATS) - 1)) != 0)
|
|
return "multiple format specifiers";
|
|
|
|
/* decode modifiers */
|
|
if (modifiers & (MOD_BYTE|MOD_HALF|MOD_WORD|MOD_QWORD))
|
|
{
|
|
if (modifiers & MOD_DECIMAL)
|
|
radix = 'd';
|
|
else if (modifiers & MOD_UNSIGNED)
|
|
radix = 'u';
|
|
else if (modifiers & MOD_OCTAL)
|
|
radix = 'o';
|
|
else if (modifiers & MOD_HEX)
|
|
radix = 'x';
|
|
else if (modifiers & MOD_BINARY)
|
|
return "binary format not yet implemented";
|
|
else
|
|
panic("no default integer format");
|
|
|
|
if (modifiers & MOD_BYTE)
|
|
{
|
|
if (modifiers & MOD_OCTAL)
|
|
{
|
|
prefix = "0";
|
|
format = "03";
|
|
}
|
|
else if (modifiers & MOD_HEX)
|
|
{
|
|
prefix = "0x";
|
|
format = "02";
|
|
}
|
|
else
|
|
{
|
|
prefix = "";
|
|
format = "";
|
|
}
|
|
|
|
sprintf(buf, "%s%%%s%c", prefix, format, radix);
|
|
myfprintf(stdout, buf, eval_as_uint(val));
|
|
}
|
|
else if (modifiers & MOD_HALF)
|
|
{
|
|
if (modifiers & MOD_OCTAL)
|
|
{
|
|
prefix = "0";
|
|
format = "06";
|
|
}
|
|
else if (modifiers & MOD_HEX)
|
|
{
|
|
prefix = "0x";
|
|
format = "04";
|
|
}
|
|
else
|
|
{
|
|
prefix = "";
|
|
format = "";
|
|
}
|
|
|
|
sprintf(buf, "%s%%%s%c", prefix, format, radix);
|
|
myfprintf(stdout, buf, eval_as_uint(val));
|
|
}
|
|
else if (modifiers & MOD_WORD)
|
|
{
|
|
if (modifiers & MOD_OCTAL)
|
|
{
|
|
prefix = "0";
|
|
format = "011";
|
|
}
|
|
else if (modifiers & MOD_HEX)
|
|
{
|
|
prefix = "0x";
|
|
format = "08";
|
|
}
|
|
else
|
|
{
|
|
prefix = "";
|
|
format = "";
|
|
}
|
|
|
|
sprintf(buf, "%s%%%s%c", prefix, format, radix);
|
|
myfprintf(stdout, buf, eval_as_uint(val));
|
|
}
|
|
#ifdef HOST_HAS_QWORD
|
|
else if (modifiers & MOD_QWORD)
|
|
{
|
|
if (modifiers & MOD_OCTAL)
|
|
{
|
|
prefix = "0";
|
|
format = "022";
|
|
}
|
|
else if (modifiers & MOD_HEX)
|
|
{
|
|
prefix = "0x";
|
|
format = "016";
|
|
}
|
|
else
|
|
{
|
|
prefix = "";
|
|
format = "";
|
|
}
|
|
|
|
sprintf(buf, "%s%%%sl%c", prefix, format, radix);
|
|
myfprintf(stdout, buf, eval_as_qword(val));
|
|
}
|
|
#endif /* HOST_HAS_QWORD */
|
|
}
|
|
else if (modifiers & MOD_FLOAT)
|
|
fprintf(stdout, "%f", (double)eval_as_float(val));
|
|
else if (modifiers & MOD_DOUBLE)
|
|
fprintf(stdout, "%f", eval_as_double(val));
|
|
else if (modifiers & MOD_CHAR)
|
|
fprintf(stdout, "`%c'", eval_as_uint(val));
|
|
else if (modifiers & MOD_STRING)
|
|
return "string format not yet implemented";
|
|
else /* no format specified, default to value type format */
|
|
panic("no default format");
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* default memory state accessor */
|
|
char * /* err str, NULL for no err */
|
|
dlite_mem_obj(struct mem_t *mem, /* memory space to access */
|
|
int is_write, /* access type */
|
|
md_addr_t addr, /* address to access */
|
|
char *p, /* input/output buffer */
|
|
int nbytes) /* size of access */
|
|
{
|
|
enum mem_cmd cmd;
|
|
|
|
if (!is_write)
|
|
cmd = Read;
|
|
else
|
|
cmd = Write;
|
|
|
|
#if 0
|
|
char *errstr;
|
|
errstr = mem_valid(cmd, addr, nbytes, /* !declare */FALSE);
|
|
if (errstr)
|
|
return errstr;
|
|
#endif
|
|
|
|
/* else, no error, access memory */
|
|
mem_access(mem, cmd, addr, p, nbytes);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* default machine state accessor */
|
|
char * /* err str, NULL for no err */
|
|
dlite_mstate_obj(FILE *stream, /* output stream */
|
|
char *cmd, /* optional command string */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
/* nada */
|
|
fprintf(stream, "No machine state.\n");
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* scroll terminator, wait for user to press return */
|
|
static void
|
|
dlite_pause(void)
|
|
{
|
|
char buf[512];
|
|
fprintf(stdout, "Press <return> to continue...");
|
|
fflush(stdout);
|
|
fgets(buf, 512, stdin);
|
|
}
|
|
|
|
/* print help information for DLite command CMD */
|
|
static void
|
|
print_help(struct dlite_cmd_t *cmd) /* command to describe */
|
|
{
|
|
int i;
|
|
|
|
/* print command name */
|
|
fprintf(stdout, " %s ", cmd->cmd_str);
|
|
|
|
/* print arguments of command */
|
|
for (i=0; i < MAX_ARGS && cmd->arg_strs[i] != NULL; i++)
|
|
{
|
|
int optional;
|
|
char *arg, arg_type;
|
|
|
|
arg = cmd->arg_strs[i];
|
|
arg_type = arg[0];
|
|
optional = (arg[1] == '?');
|
|
|
|
if (optional)
|
|
fprintf(stdout, "{");
|
|
else
|
|
fprintf(stdout, "<");
|
|
|
|
switch (arg_type)
|
|
{
|
|
case 'm':
|
|
fprintf(stdout, "/modifiers");
|
|
break;
|
|
case 'a':
|
|
fprintf(stdout, "addr");
|
|
break;
|
|
case 'c':
|
|
fprintf(stdout, "count");
|
|
break;
|
|
case 'e':
|
|
fprintf(stdout, "expr");
|
|
break;
|
|
case 't':
|
|
fprintf(stdout, "r|w|x");
|
|
break;
|
|
case 'i':
|
|
fprintf(stdout, "id");
|
|
break;
|
|
case 's':
|
|
fprintf(stdout, "string");
|
|
break;
|
|
default:
|
|
panic("bogus argument type: `%c'", arg_type);
|
|
}
|
|
|
|
if (optional)
|
|
fprintf(stdout, "}");
|
|
else
|
|
fprintf(stdout, ">");
|
|
|
|
fprintf(stdout, " ");
|
|
}
|
|
fprintf(stdout, "\n");
|
|
|
|
/* print command description */
|
|
fprintf(stdout, " %s\n", cmd->help_str);
|
|
}
|
|
|
|
/* print help messages for all (or single) DLite debugger commands */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_help(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
struct dlite_cmd_t *cmd;
|
|
|
|
if (nargs != 0 && nargs != 1)
|
|
return "too many arguments";
|
|
|
|
if (nargs == 1)
|
|
{
|
|
/* print help for specified commands */
|
|
for (cmd=cmd_db; cmd->cmd_str != NULL; cmd++)
|
|
{
|
|
if (!strcmp(cmd->cmd_str, args[0].as_str))
|
|
break;
|
|
}
|
|
if (!cmd->cmd_str)
|
|
return "command unknown";
|
|
|
|
print_help(cmd);
|
|
}
|
|
else
|
|
{
|
|
/* print help for all commands */
|
|
for (cmd=cmd_db; cmd->cmd_str != NULL; cmd++)
|
|
{
|
|
/* `---' specifies a good point for a scroll pause */
|
|
if (!strcmp(cmd->cmd_str, "---"))
|
|
dlite_pause();
|
|
else
|
|
print_help(cmd);
|
|
}
|
|
|
|
fprintf (stdout, "\n");
|
|
if (dlite_help_tail)
|
|
fprintf (stdout, "%s\n", dlite_help_tail);
|
|
}
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print version information for simulator */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_version(int nargs, union arg_val_t args[],/* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
if (nargs != 0)
|
|
return "too many arguments";
|
|
|
|
/* print simulator version info */
|
|
fprintf(stdout, "The SimpleScalar/%s Tool Set, version %d.%d of %s.\n",
|
|
VER_TARGET, VER_MAJOR, VER_MINOR, VER_UPDATE);
|
|
fprintf(stdout,
|
|
"Copyright (c) 1994-1998 by Todd M. Austin. All Rights Reserved.\n");
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* terminate simulation with statistics */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_terminate(int nargs, union arg_val_t args[],/* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
if (nargs != 0)
|
|
return "too many arguments";
|
|
|
|
fprintf(stdout, "DLite: terminating simulation...\n");
|
|
longjmp(sim_exit_buf, /* exitcode */1);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* quit the simulator, omit any stats dump */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_quit(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
if (nargs != 0)
|
|
return "too many arguments";
|
|
|
|
fprintf(stdout, "DLite: exiting simulator...\n");
|
|
exit(1);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* continue executing program (possibly at specified address) */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_cont(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
struct eval_value_t val;
|
|
|
|
if (!f_dlite_reg_obj || !f_dlite_mem_obj)
|
|
panic("DLite is not configured");
|
|
|
|
if (nargs != 0 && nargs != 1)
|
|
return "too many arguments";
|
|
|
|
if (nargs == 1)
|
|
{
|
|
/* continue from specified address, check address */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "address argument must be an integral type";
|
|
|
|
/* reset PC */
|
|
val.type = et_addr;
|
|
val.value.as_addr = eval_as_addr(args[0].as_value);
|
|
f_dlite_reg_obj(regs, /* is_write */TRUE, rt_PC, 0, &val);
|
|
|
|
myfprintf(stdout, "DLite: continuing execution @ 0x%08p...\n",
|
|
val.value.as_addr);
|
|
}
|
|
|
|
/* signal end of main debugger loop, and continuation of prog execution */
|
|
dlite_active = FALSE;
|
|
dlite_return = TRUE;
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* step program one instruction */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_step(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
if (nargs != 0)
|
|
return "too many arguments";
|
|
|
|
/* signal on instruction step */
|
|
dlite_active = TRUE;
|
|
dlite_return = TRUE;
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
#if 0 /* NYI */
|
|
/* step program one instruction in current procedure */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_next(int nargs, union arg_val_t args[]) /* command arguments */
|
|
{
|
|
if (nargs != 0)
|
|
return "too many arguments";
|
|
|
|
/* signal on instruction step */
|
|
dlite_step_cnt = 1;
|
|
dlite_step_into = FALSE;
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
/* print the value of <expr> using format <modifiers> */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_print(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int modifiers = 0;
|
|
char *err_str;
|
|
struct eval_value_t val;
|
|
|
|
if (nargs != 1 && nargs != 2)
|
|
return "wrong number of arguments";
|
|
|
|
if (nargs == 2)
|
|
{
|
|
/* arguments include modifiers and expression value */
|
|
modifiers = args[0].as_modifier;
|
|
val = args[1].as_value;
|
|
}
|
|
else
|
|
{
|
|
/* arguments include only expression value */
|
|
val = args[0].as_value;
|
|
}
|
|
|
|
/* print expression value */
|
|
err_str = print_val(modifiers, val);
|
|
if (err_str)
|
|
return err_str;
|
|
fprintf(stdout, "\n");
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print the value of all command line options */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_options(int nargs, union arg_val_t args[],/* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
if (nargs != 0)
|
|
return "wrong number of arguments";
|
|
|
|
/* print all options */
|
|
opt_print_options(sim_odb, stdout, /* terse */TRUE, /* !notes */FALSE);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print the value of all (or single) command line options */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_option(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
struct opt_opt_t *opt;
|
|
|
|
if (nargs != 1)
|
|
return "wrong number of arguments";
|
|
|
|
/* print a single option, specified by argument */
|
|
opt = opt_find_option(sim_odb, args[0].as_str);
|
|
if (!opt)
|
|
return "option is not defined";
|
|
|
|
/* else, print this option's value */
|
|
fprintf(stdout, "%-16s ", opt->name);
|
|
opt_print_option(opt, stdout);
|
|
if (opt->desc)
|
|
fprintf(stdout, " # %s", opt->desc);
|
|
fprintf(stdout, "\n");
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print the value of all statistical variables */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_stats(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
if (nargs != 0)
|
|
return "wrong number of arguments";
|
|
|
|
/* print all options */
|
|
stat_print_stats(sim_sdb, stdout);
|
|
sim_aux_stats(stdout);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print the value of a statistical variable */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_stat(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
struct stat_stat_t *stat;
|
|
|
|
if (nargs != 1)
|
|
return "wrong number of arguments";
|
|
|
|
/* print a single option, specified by argument */
|
|
stat = stat_find_stat(sim_sdb, args[0].as_str);
|
|
if (!stat)
|
|
return "statistical variable is not defined";
|
|
|
|
/* else, print this option's value */
|
|
stat_print_stat(sim_sdb, stat, stdout);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print the type of expression <expr> */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_whatis(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
if (nargs != 1)
|
|
return "wrong number of arguments";
|
|
|
|
fprintf(stdout, "type == `%s'\n", eval_type_str[args[0].as_value.type]);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print integer register contents */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_iregs(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
char *err_str;
|
|
|
|
if (nargs != 0)
|
|
return "too many arguments";
|
|
|
|
/* print integer registers */
|
|
myfprintf(stdout, "PC: 0x%08p NPC: 0x%08p\n",
|
|
regs->regs_PC, regs->regs_NPC);
|
|
if ((err_str = dlite_cregs(nargs, args, regs, mem)) != NULL)
|
|
return err_str;
|
|
md_print_iregs(regs->regs_R, stdout);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print floating point register contents */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_fpregs(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
/* print floating point registers */
|
|
md_print_fpregs(regs->regs_F, stdout);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print floating point register contents */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_cregs(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
/* print floating point registers */
|
|
md_print_cregs(regs->regs_C, stdout);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print all register contents */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_regs(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
char *err_str;
|
|
|
|
myfprintf(stdout, "PC: 0x%08p NPC: 0x%08p\n",
|
|
regs->regs_PC, regs->regs_NPC);
|
|
if ((err_str = dlite_cregs(nargs, args, regs, mem)) != NULL)
|
|
return err_str;
|
|
md_print_iregs(regs->regs_R, stdout);
|
|
dlite_pause();
|
|
if ((err_str = dlite_fpregs(nargs, args, regs, mem)) != NULL)
|
|
return err_str;
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print machine specific state (simulator dependent) */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_mstate(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
char *errstr;
|
|
|
|
if (nargs != 0 && nargs != 1)
|
|
return "too many arguments";
|
|
|
|
if (f_dlite_mstate_obj)
|
|
{
|
|
if (nargs == 0)
|
|
{
|
|
errstr = f_dlite_mstate_obj(stdout, NULL, regs, mem);
|
|
if (errstr)
|
|
return errstr;
|
|
}
|
|
else
|
|
{
|
|
errstr = f_dlite_mstate_obj(stdout, args[0].as_str, regs, mem);
|
|
if (errstr)
|
|
return errstr;
|
|
}
|
|
}
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* display the value at memory location <addr> using format <modifiers> */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_display(int nargs, union arg_val_t args[],/* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int modifiers, size;
|
|
md_addr_t addr;
|
|
unsigned char buf[512];
|
|
struct eval_value_t val;
|
|
char *errstr;
|
|
|
|
if (nargs != 1 && nargs != 2)
|
|
return "wrong number of arguments";
|
|
|
|
if (nargs == 1)
|
|
{
|
|
/* no modifiers */
|
|
modifiers = 0;
|
|
|
|
/* check address */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "address argument must be an integral type";
|
|
|
|
/* reset address */
|
|
addr = eval_as_addr(args[0].as_value);
|
|
}
|
|
else if (nargs == 2)
|
|
{
|
|
modifiers = args[0].as_modifier;
|
|
|
|
/* check address */
|
|
if (!EVAL_INTEGRAL(args[1].as_value.type))
|
|
return "address argument must be an integral type";
|
|
|
|
/* reset address */
|
|
addr = eval_as_addr(args[1].as_value);
|
|
}
|
|
|
|
/* determine operand size */
|
|
if (modifiers & (MOD_BYTE|MOD_CHAR))
|
|
size = 1;
|
|
else if (modifiers & MOD_HALF)
|
|
size = 2;
|
|
else if (modifiers & (MOD_QWORD|MOD_DOUBLE))
|
|
size = 8;
|
|
else /* no modifiers, or MOD_WORD|MOD_FLOAT */
|
|
size = 4;
|
|
|
|
/* read memory */
|
|
errstr = f_dlite_mem_obj(mem, /* !is_write */FALSE, addr, (char *)buf, size);
|
|
if (errstr)
|
|
return errstr;
|
|
|
|
/* marshall a value */
|
|
if (modifiers & (MOD_BYTE|MOD_CHAR))
|
|
{
|
|
/* size == 1 */
|
|
val.type = et_int;
|
|
val.value.as_int = (int)*(unsigned char *)buf;
|
|
}
|
|
else if (modifiers & MOD_HALF)
|
|
{
|
|
/* size == 2 */
|
|
val.type = et_int;
|
|
val.value.as_int = (int)*(unsigned short *)buf;
|
|
}
|
|
else if (modifiers & (MOD_QWORD|MOD_DOUBLE))
|
|
{
|
|
/* size == 8 */
|
|
val.type = et_double;
|
|
val.value.as_double = *(double *)buf;
|
|
}
|
|
else /* no modifiers, or MOD_WORD|MOD_FLOAT */
|
|
{
|
|
/* size == 4 */
|
|
val.type = et_uint;
|
|
val.value.as_uint = *(unsigned int *)buf;
|
|
}
|
|
|
|
/* print the value */
|
|
errstr = print_val(modifiers, val);
|
|
if (errstr)
|
|
return errstr;
|
|
fprintf(stdout, "\n");
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* `dump' command print format */
|
|
#define BYTES_PER_LINE 16 /* must be a power of two */
|
|
#define LINES_PER_SCREEN 4
|
|
|
|
/* dump the contents of memory to screen */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_dump(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int i, j;
|
|
int count = LINES_PER_SCREEN * BYTES_PER_LINE, i_count, fmt_count, fmt_lines;
|
|
md_addr_t fmt_addr, i_addr;
|
|
static md_addr_t addr = 0;
|
|
unsigned char byte;
|
|
char buf[512];
|
|
char *errstr;
|
|
|
|
if (nargs < 0 || nargs > 2)
|
|
return "too many arguments";
|
|
|
|
if (nargs == 1)
|
|
{
|
|
/* check address */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "address argument must be an integral type";
|
|
|
|
/* reset PC */
|
|
addr = eval_as_addr(args[0].as_value);
|
|
}
|
|
else if (nargs == 2)
|
|
{
|
|
/* check address */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "address argument must be an integral type";
|
|
|
|
/* reset addr */
|
|
addr = eval_as_addr(args[0].as_value);
|
|
|
|
/* check count */
|
|
if (!EVAL_INTEGRAL(args[1].as_value.type))
|
|
return "count argument must be an integral type";
|
|
|
|
if (eval_as_uint(args[1].as_value) > 1024)
|
|
return "bad count argument";
|
|
|
|
/* reset count */
|
|
count = eval_as_uint(args[1].as_value);
|
|
}
|
|
/* else, nargs == 0, use addr, count */
|
|
|
|
/* normalize start address and count */
|
|
fmt_addr = addr & ~(BYTES_PER_LINE - 1);
|
|
fmt_count = (count + (BYTES_PER_LINE - 1)) & ~(BYTES_PER_LINE - 1);
|
|
fmt_lines = fmt_count / BYTES_PER_LINE;
|
|
|
|
if (fmt_lines < 1)
|
|
panic("no output lines");
|
|
|
|
/* print dump */
|
|
if (fmt_lines == 1)
|
|
{
|
|
/* unformatted dump */
|
|
i_addr = fmt_addr;
|
|
myfprintf(stdout, "0x%08p: ", i_addr);
|
|
for (i=0; i < count; i++)
|
|
{
|
|
errstr =
|
|
f_dlite_mem_obj(mem, /* !is_write */FALSE,
|
|
i_addr, (char *)&byte, 1);
|
|
if (errstr)
|
|
return errstr;
|
|
fprintf(stdout, "%02x ", byte);
|
|
if (isprint(byte))
|
|
buf[i] = byte;
|
|
else
|
|
buf[i] = '.';
|
|
i_addr++;
|
|
addr++;
|
|
}
|
|
buf[i] = '\0';
|
|
|
|
/* character view */
|
|
fprintf(stdout, "[%s]\n", buf);
|
|
}
|
|
else /* lines > 1 */
|
|
{
|
|
i_count = 0;
|
|
i_addr = fmt_addr;
|
|
for (i=0; i < fmt_lines; i++)
|
|
{
|
|
myfprintf(stdout, "0x%08p: ", i_addr);
|
|
|
|
/* byte view */
|
|
for (j=0; j < BYTES_PER_LINE; j++)
|
|
{
|
|
if (i_addr >= addr && i_count <= count)
|
|
{
|
|
errstr =
|
|
f_dlite_mem_obj(mem, /* !is_write */FALSE,
|
|
i_addr, (char *)&byte, 1);
|
|
if (errstr)
|
|
return errstr;
|
|
fprintf(stdout, "%02x ", byte);
|
|
if (isprint(byte))
|
|
buf[j] = byte;
|
|
else
|
|
buf[j] = '.';
|
|
i_count++;
|
|
addr++;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stdout, " ");
|
|
buf[j] = ' ';
|
|
}
|
|
i_addr++;
|
|
}
|
|
buf[j] = '\0';
|
|
|
|
/* character view */
|
|
fprintf(stdout, "[%s]\n", buf);
|
|
}
|
|
}
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* disassembler print format */
|
|
#define INSTS_PER_SCREEN 16
|
|
|
|
/* disassemble instructions at specified address */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_dis(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int i;
|
|
int count = INSTS_PER_SCREEN;
|
|
static md_addr_t addr = 0;
|
|
md_inst_t inst;
|
|
char *errstr;
|
|
|
|
if (nargs < 0 || nargs > 2)
|
|
return "too many arguments";
|
|
|
|
if (nargs == 1)
|
|
{
|
|
/* check address */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "address argument must be an integral type";
|
|
|
|
/* reset PC */
|
|
addr = eval_as_addr(args[0].as_value);
|
|
}
|
|
else if (nargs == 2)
|
|
{
|
|
/* check address */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "address argument must be an integral type";
|
|
|
|
/* reset addr */
|
|
addr = eval_as_addr(args[0].as_value);
|
|
|
|
/* check count */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "count argument must be an integral type";
|
|
|
|
/* reset count */
|
|
count = eval_as_uint(args[1].as_value);
|
|
|
|
if (count < 0 || count > 1024)
|
|
return "bad count argument";
|
|
}
|
|
/* else, nargs == 0, use addr, count */
|
|
|
|
if ((addr % sizeof(md_inst_t)) != 0)
|
|
return "instruction addresses are a multiple of eight";
|
|
|
|
/* disassemble COUNT insts at ADDR */
|
|
for (i=0; i<count; i++)
|
|
{
|
|
/* read and disassemble instruction */
|
|
myfprintf(stdout, " 0x%08p: ", addr);
|
|
errstr =
|
|
f_dlite_mem_obj(mem, /* !is_write */FALSE,
|
|
addr, (char *)&inst, sizeof(inst));
|
|
inst = MD_SWAPI(inst);
|
|
if (errstr)
|
|
return errstr;
|
|
md_print_insn(inst, addr, stdout);
|
|
fprintf(stdout, "\n");
|
|
|
|
/* go to next instruction */
|
|
addr += sizeof(md_inst_t);
|
|
}
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* break instance descriptor, one allocated for each breakpoint set */
|
|
struct dlite_break_t {
|
|
struct dlite_break_t *next; /* next active breakpoint */
|
|
int id; /* break id */
|
|
int class; /* break class */
|
|
struct range_range_t range; /* break range */
|
|
};
|
|
|
|
/* all active break points, in a list */
|
|
static struct dlite_break_t *dlite_bps = NULL;
|
|
|
|
/* unique id of next breakpoint */
|
|
static int break_id = 1;
|
|
|
|
/* return breakpoint class as a string */
|
|
static char * /* breakpoint class string */
|
|
bp_class_str(int class) /* breakpoint class mask */
|
|
{
|
|
if (class == (ACCESS_READ|ACCESS_WRITE|ACCESS_EXEC))
|
|
return "read|write|exec";
|
|
else if (class == (ACCESS_READ|ACCESS_WRITE))
|
|
return "read|write";
|
|
else if (class == (ACCESS_WRITE|ACCESS_EXEC))
|
|
return "write|exec";
|
|
else if (class == (ACCESS_READ|ACCESS_EXEC))
|
|
return "read|exec";
|
|
else if (class == ACCESS_READ)
|
|
return "read";
|
|
else if (class == ACCESS_WRITE)
|
|
return "write";
|
|
else if (class == ACCESS_EXEC)
|
|
return "exec";
|
|
else
|
|
panic("bogus access class");
|
|
}
|
|
|
|
/* set a breakpoint of class CLASS at address ADDR */
|
|
static char * /* err str, NULL for no err */
|
|
set_break(int class, /* break class, use ACCESS_* */
|
|
struct range_range_t *range) /* range breakpoint */
|
|
{
|
|
struct dlite_break_t *bp;
|
|
|
|
/* add breakpoint to break list */
|
|
bp = calloc(1, sizeof(struct dlite_break_t));
|
|
if (!bp)
|
|
fatal("out of virtual memory");
|
|
|
|
bp->id = break_id++;
|
|
bp->range = *range;
|
|
bp->class = class;
|
|
|
|
bp->next = dlite_bps;
|
|
dlite_bps = bp;
|
|
|
|
fprintf(stdout, "breakpoint #%d set @ ", bp->id);
|
|
range_print_range(&bp->range, stdout);
|
|
fprintf(stdout, ", class: %s\n", bp_class_str(class));
|
|
|
|
/* a breakpoint is set now, check for a breakpoint */
|
|
dlite_check = TRUE;
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* delete breakpoint with id ID */
|
|
static char * /* err str, NULL for no err */
|
|
delete_break(int id) /* id of brkpnt to delete */
|
|
{
|
|
struct dlite_break_t *bp, *prev;
|
|
|
|
if (!dlite_bps)
|
|
return "no breakpoints set";
|
|
|
|
for (bp=dlite_bps,prev=NULL; bp != NULL; prev=bp,bp=bp->next)
|
|
{
|
|
if (bp->id == id)
|
|
break;
|
|
}
|
|
if (!bp)
|
|
return "breakpoint not found";
|
|
|
|
if (!prev)
|
|
{
|
|
/* head of list, unlink */
|
|
dlite_bps = bp->next;
|
|
}
|
|
else
|
|
{
|
|
/* middle or end of list */
|
|
prev->next = bp->next;
|
|
}
|
|
|
|
fprintf(stdout, "breakpoint #%d deleted @ ", bp->id);
|
|
range_print_range(&bp->range, stdout);
|
|
fprintf(stdout, ", class: %s\n", bp_class_str(bp->class));
|
|
|
|
bp->next = NULL;
|
|
free(bp);
|
|
|
|
if (!dlite_bps)
|
|
{
|
|
/* no breakpoints set, cancel checks */
|
|
dlite_check = FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* breakpoints are set, do checks */
|
|
dlite_check = TRUE;
|
|
}
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* this variable clues dlite_main() into why it was called */
|
|
static int break_access = 0;
|
|
|
|
/* internal break check interface */
|
|
int /* non-zero if brkpt hit */
|
|
__check_break(md_addr_t next_PC, /* address of next inst */
|
|
int access, /* mem access of last inst */
|
|
md_addr_t addr, /* mem addr of last inst */
|
|
counter_t icount, /* instruction count */
|
|
counter_t cycle) /* cycle count */
|
|
{
|
|
struct dlite_break_t *bp;
|
|
|
|
if (dlite_active)
|
|
{
|
|
/* single-stepping, break always */
|
|
break_access = /* single step */0;
|
|
return TRUE;
|
|
}
|
|
/* else, check for a breakpoint */
|
|
|
|
for (bp=dlite_bps; bp != NULL; bp=bp->next)
|
|
{
|
|
switch (bp->range.start.ptype)
|
|
{
|
|
case pt_addr:
|
|
if ((bp->class & ACCESS_EXEC)
|
|
&& !range_cmp_range(&bp->range, next_PC))
|
|
{
|
|
/* hit a code breakpoint */
|
|
myfprintf(stdout,
|
|
"Stopping at code breakpoint #%d @ 0x%08p...\n",
|
|
bp->id, next_PC);
|
|
break_access = ACCESS_EXEC;
|
|
return TRUE;
|
|
}
|
|
if ((bp->class & ACCESS_READ)
|
|
&& ((access & ACCESS_READ)
|
|
&& !range_cmp_range(&bp->range, addr)))
|
|
{
|
|
/* hit a read breakpoint */
|
|
myfprintf(stdout,
|
|
"Stopping at read breakpoint #%d @ 0x%08p...\n",
|
|
bp->id, addr);
|
|
break_access = ACCESS_READ;
|
|
return TRUE;
|
|
}
|
|
if ((bp->class & ACCESS_WRITE)
|
|
&& ((access & ACCESS_WRITE)
|
|
&& !range_cmp_range(&bp->range, addr)))
|
|
{
|
|
/* hit a write breakpoint */
|
|
myfprintf(stdout,
|
|
"Stopping at write breakpoint #%d @ 0x%08p...\n",
|
|
bp->id, addr);
|
|
break_access = ACCESS_WRITE;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case pt_inst:
|
|
if (!range_cmp_range(&bp->range, icount))
|
|
{
|
|
/* hit a code breakpoint */
|
|
fprintf(stdout,
|
|
"Stopping at inst count breakpoint #%d @ %.0f...\n",
|
|
bp->id, (double)icount);
|
|
break_access = ACCESS_EXEC;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case pt_cycle:
|
|
if (!range_cmp_range(&bp->range, cycle))
|
|
{
|
|
/* hit a code breakpoint */
|
|
fprintf(stdout,
|
|
"Stopping at cycle count breakpoint #%d @ %.0f...\n",
|
|
bp->id, (double)cycle);
|
|
break_access = ACCESS_EXEC;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
panic("bogus range type");
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/* no matching breakpoint found */
|
|
break_access = /* no break */0;
|
|
return FALSE;
|
|
}
|
|
|
|
/* set a text breakpoint */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_break(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
md_addr_t addr;
|
|
struct range_range_t range;
|
|
|
|
if (nargs != 1)
|
|
return "wrong number of arguments";
|
|
|
|
/* check address */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "address argument must be an integral type";
|
|
|
|
/* reset addr */
|
|
addr = eval_as_addr(args[0].as_value);
|
|
|
|
/* build the range */
|
|
range.start.ptype = pt_addr;
|
|
range.start.pos = addr;
|
|
range.end.ptype = pt_addr;
|
|
#ifdef TARGET_ALPHA
|
|
/* need some extra space here, as functional have multiple entry points
|
|
depending on if $GP needs to be loaded or not */
|
|
range.end.pos = addr + 9;
|
|
#else /* !TARGET_ALPHA */
|
|
range.end.pos = addr + 1;
|
|
#endif /* TARGET_ALPHA */
|
|
|
|
/* set a code break point */
|
|
return set_break(ACCESS_EXEC, &range);
|
|
}
|
|
|
|
/* set a data breakpoint at specified address */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_dbreak(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int access;
|
|
md_addr_t addr;
|
|
struct range_range_t range;
|
|
|
|
if (nargs != 1 && nargs != 2)
|
|
return "wrong number of arguments";
|
|
|
|
if (nargs == 1)
|
|
{
|
|
/* check address */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "address argument must be an integral type";
|
|
|
|
/* reset addr */
|
|
addr = eval_as_addr(args[0].as_value);
|
|
|
|
/* break on read or write */
|
|
access = ACCESS_READ|ACCESS_WRITE;
|
|
}
|
|
else if (nargs == 2)
|
|
{
|
|
/* check address */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "address argument must be an integral type";
|
|
|
|
/* reset addr */
|
|
addr = eval_as_addr(args[0].as_value);
|
|
|
|
/* get access */
|
|
access = args[1].as_access;
|
|
}
|
|
|
|
/* build the range */
|
|
range.start.ptype = pt_addr;
|
|
range.start.pos = addr;
|
|
range.end.ptype = pt_addr;
|
|
range.end.pos = addr + 1;
|
|
|
|
/* set the breakpoint */
|
|
return set_break(access, &range);
|
|
}
|
|
|
|
/* set a breakpoint at specified range */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_rbreak(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int access;
|
|
char *errstr;
|
|
struct range_range_t range;
|
|
|
|
if (nargs != 1 && nargs != 2)
|
|
return "wrong number of arguments";
|
|
|
|
if (nargs == 2)
|
|
{
|
|
/* get access */
|
|
access = args[1].as_access;
|
|
}
|
|
else
|
|
{
|
|
/* break on read or write or exec */
|
|
access = ACCESS_READ|ACCESS_WRITE|ACCESS_EXEC;
|
|
}
|
|
|
|
/* check range */
|
|
errstr = range_parse_range(args[0].as_str, &range);
|
|
if (errstr)
|
|
return errstr;
|
|
|
|
/* sanity checks for ranges */
|
|
if (range.start.ptype != range.end.ptype)
|
|
return "range endpoints are not of the same type";
|
|
else if (range.start.pos > range.end.pos)
|
|
return "range start is after range end";
|
|
|
|
/* set the breakpoint */
|
|
return set_break(access, &range);
|
|
}
|
|
|
|
/* list all outstanding breakpoints */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_breaks(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
struct dlite_break_t *bp;
|
|
|
|
if (!dlite_bps)
|
|
{
|
|
fprintf(stdout, "No active breakpoints.\n");
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
fprintf(stdout, "Active breakpoints:\n");
|
|
for (bp=dlite_bps; bp != NULL; bp=bp->next)
|
|
{
|
|
fprintf(stdout, " breakpoint #%d @ ", bp->id);
|
|
range_print_range(&bp->range, stdout);
|
|
fprintf(stdout, ", class: %s\n", bp_class_str(bp->class));
|
|
}
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* delete specified breakpoint */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_delete(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int id;
|
|
|
|
if (nargs != 1)
|
|
return "wrong number of arguments";
|
|
|
|
/* check bp id */
|
|
if (!EVAL_INTEGRAL(args[0].as_value.type))
|
|
return "id must be an integral type";
|
|
|
|
id = eval_as_uint(args[0].as_value);
|
|
return delete_break(id);
|
|
}
|
|
|
|
/* clear all breakpoints */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_clear(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
if (!dlite_bps)
|
|
{
|
|
fprintf(stdout, "No active breakpoints.\n");
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
while (dlite_bps != NULL)
|
|
{
|
|
/* delete first breakpoint */
|
|
delete_break(dlite_bps->id);
|
|
}
|
|
fprintf(stdout, "All breakpoints cleared.\n");
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print the value of all program symbols */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_symbols(int nargs, union arg_val_t args[],/* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int i;
|
|
|
|
if (nargs != 0)
|
|
return "wrong number of arguments";
|
|
|
|
/* load symbols, if not already loaded */
|
|
sym_loadsyms(ld_prog_fname, /* !locals */FALSE);
|
|
|
|
/* print all symbol values */
|
|
for (i=0; i<sym_nsyms; i++)
|
|
sym_dumpsym(sym_syms[i], stdout);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print the value of all text symbols */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_tsymbols(int nargs, union arg_val_t args[],/* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int i;
|
|
|
|
if (nargs != 0)
|
|
return "wrong number of arguments";
|
|
|
|
/* load symbols, if not already loaded */
|
|
sym_loadsyms(ld_prog_fname, /* !locals */FALSE);
|
|
|
|
/* print all symbol values */
|
|
for (i=0; i<sym_ntextsyms; i++)
|
|
sym_dumpsym(sym_textsyms[i], stdout);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print the value of all text symbols */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_dsymbols(int nargs, union arg_val_t args[],/* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int i;
|
|
|
|
if (nargs != 0)
|
|
return "wrong number of arguments";
|
|
|
|
/* load symbols, if not already loaded */
|
|
sym_loadsyms(ld_prog_fname, /* !locals */FALSE);
|
|
|
|
/* print all symbol values */
|
|
for (i=0; i<sym_ndatasyms; i++)
|
|
sym_dumpsym(sym_datasyms[i], stdout);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* print the value of all (or single) command line options */
|
|
static char * /* err str, NULL for no err */
|
|
dlite_symbol(int nargs, union arg_val_t args[], /* command arguments */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
int index;
|
|
struct sym_sym_t *sym;
|
|
|
|
if (nargs != 1)
|
|
return "wrong number of arguments";
|
|
|
|
/* load symbols, if not already loaded */
|
|
sym_loadsyms(ld_prog_fname, /* !locals */FALSE);
|
|
|
|
/* print a single option, specified by argument */
|
|
sym = sym_bind_name(args[0].as_str, &index, sdb_any);
|
|
if (!sym)
|
|
return "symbol is not defined";
|
|
|
|
/* else, print this symbols's value */
|
|
sym_dumpsym(sym_syms_by_name[index], stdout);
|
|
|
|
/* no error */
|
|
return NULL;
|
|
}
|
|
|
|
/* initialize the DLite debugger */
|
|
void
|
|
dlite_init(dlite_reg_obj_t reg_obj, /* register state object */
|
|
dlite_mem_obj_t mem_obj, /* memory state object */
|
|
dlite_mstate_obj_t mstate_obj) /* machine state object */
|
|
{
|
|
/* architected state accessors */
|
|
f_dlite_reg_obj = reg_obj;
|
|
f_dlite_mem_obj = mem_obj;
|
|
f_dlite_mstate_obj = mstate_obj;
|
|
|
|
/* instantiate the expression evaluator */
|
|
dlite_evaluator = eval_new(ident_evaluator, NULL);
|
|
}
|
|
|
|
/* print a mini-state header */
|
|
static void
|
|
dlite_status(md_addr_t regs_PC, /* PC of just completed inst */
|
|
md_addr_t next_PC, /* PC of next inst to exec */
|
|
counter_t cycle, /* current cycle */
|
|
int dbreak, /* last break a data break? */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
md_inst_t inst;
|
|
char *errstr;
|
|
|
|
if (dbreak)
|
|
{
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "Instruction (now finished) that caused data break:\n");
|
|
myfprintf(stdout, "[%10n] 0x%08p: ", cycle, regs_PC);
|
|
errstr =
|
|
f_dlite_mem_obj(mem, /* !is_write */FALSE,
|
|
regs_PC, (char *)&inst, sizeof(inst));
|
|
inst = MD_SWAPI(inst);
|
|
if (errstr)
|
|
fprintf(stdout, "<invalid memory>: %s", errstr);
|
|
else
|
|
md_print_insn(inst, regs_PC, stdout);
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "\n");
|
|
}
|
|
|
|
/* read and disassemble instruction */
|
|
myfprintf(stdout, "[%10n] 0x%08p: ", cycle, next_PC);
|
|
errstr =
|
|
f_dlite_mem_obj(mem, /* !is_write */FALSE,
|
|
next_PC, (char *)&inst, sizeof(inst));
|
|
inst = MD_SWAPI(inst);
|
|
if (errstr)
|
|
fprintf(stdout, "<invalid memory>: %s", errstr);
|
|
else
|
|
md_print_insn(inst, next_PC, stdout);
|
|
fprintf(stdout, "\n");
|
|
}
|
|
|
|
/* DLite command line prompt */
|
|
#define DLITE_PROMPT "DLite! > "
|
|
|
|
/* DLite debugger main loop */
|
|
void
|
|
dlite_main(md_addr_t regs_PC, /* addr of last inst to exec */
|
|
md_addr_t next_PC, /* addr of next inst to exec */
|
|
counter_t cycle, /* current procesor cycle */
|
|
struct regs_t *regs, /* registers to access */
|
|
struct mem_t *mem) /* memory to access */
|
|
{
|
|
char buf[512], *err_str;
|
|
int dbreak = (break_access & (ACCESS_READ|ACCESS_WRITE)) != 0;
|
|
static char cmd[512] = "";
|
|
|
|
dlite_active = TRUE;
|
|
dlite_return = FALSE;
|
|
dlite_status(regs_PC, next_PC, cycle, dbreak, regs, mem);
|
|
|
|
while (dlite_active && !dlite_return)
|
|
{
|
|
fprintf(stdout, DLITE_PROMPT);
|
|
fflush(stdout);
|
|
fgets(buf, 512, stdin);
|
|
|
|
/* chop */
|
|
if (buf[strlen(buf)-1] == '\n')
|
|
buf[strlen(buf)-1] = '\0';
|
|
|
|
if (buf[0] != '\0')
|
|
{
|
|
/* use this command */
|
|
strcpy(cmd, buf);
|
|
}
|
|
/* else, use last command */
|
|
|
|
err_str = dlite_exec(cmd, regs, mem);
|
|
if (err_str)
|
|
fprintf(stdout, "Dlite: error: %s\n", err_str);
|
|
}
|
|
}
|