* d10v-tdep.c: Add support for examination and interpretation

of instruction trace buffer.
	(trace, untrace, info trace, tdisassemble): New commands.
This commit is contained in:
Stan Shebs 1996-12-06 07:37:24 +00:00
parent d28f058e54
commit 48712b3060
2 changed files with 321 additions and 24 deletions

View File

@ -1,3 +1,11 @@
start-sanitize-d10v
Thu Dec 5 23:30:44 1996 Stan Shebs <shebs@andros.cygnus.com>
* d10v-tdep.c: Add support for examination and interpretation
of instruction trace buffer.
(trace, untrace, info trace, tdisassemble): New commands.
end-sanitize-d10v
Thu Dec 5 14:06:23 1996 Doug Evans <dje@canuck.cygnus.com>
* config/sparc/tm-sparclet.h (TARGET_BYTE_ORDER): Undef.
@ -8,9 +16,7 @@ Thu Dec 5 14:06:23 1996 Doug Evans <dje@canuck.cygnus.com>
Wed Dec 4 16:34:05 1996 Geoffrey Noer <noer@cygnus.com>
* config/mn10300/mn10300.mt
* config/mn10300/tm-mn10300.h: new config files for mn10300
processor
* config/mn10300/mn10300.mt, config/mn10300/tm-mn10300.h: New.
Tue Dec 3 13:02:08 1996 Fred Fish <fnf@ninemoons.com>
@ -29,11 +35,11 @@ Tue Dec 3 11:38:14 1996 Michael Snyder <msnyder@cleaver.cygnus.com>
code for generic call_dummy frames.
* config/h8300/tm-h8300.h: turn on USE_GENERIC_DUMMY_FRAMES
start-sanitize-m32r
* config/m32r/tm-m32r.h: turn on USE_GENERIC_DUMMY_FRAMES
* config/m32r/tm-m32r.h: Ditto.
end-sanitize-m32r
* config/sh/tm-sh.h: turn on USE_GENERIC_DUMMY_FRAMES
* config/sh/tm-sh.h: Ditto.
start-sanitize-v850
* config/v850/tm-v850.h: turn on USE_GENERIC_DUMMY_FRAMES
* config/v850/tm-v850.h: Ditto.
end-sanitize-v850
Sun Dec 1 00:41:47 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
@ -43,7 +49,7 @@ Sun Dec 1 00:41:47 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
Sun Dec 1 00:40:46 1996 Geoffrey Noer <noer@cygnus.com>
* configure.tgt: add new mn10300 entry
* configure.tgt: Add new mn10300 entry.
Sun Dec 1 00:18:59 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
@ -255,18 +261,14 @@ Thu Nov 28 00:46:24 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
Wed Nov 27 11:29:06 1996 Michael Snyder <msnyder@cleaver.cygnus.com>
* blockframe.c: ...Remove old-style CALL_DUMMY code...
* h8300-tdep.c: ditto
* config/h8300/tm-h8300.h: ditto
* blockframe.c: Remove old-style CALL_DUMMY code.
* h8300-tdep.c, config/h8300/tm-h8300.h: Ditto.
start-sanitize-m32r
* m32r-tdep.c: ditto
* config/m32r/tm-m32r.h: ditto
* m32r-tdep.c, config/m32r/tm-m32r.h: Ditto.
end-sanitize-m32r
* sh-tdep.c: ditto
* config/sh/tm-sh.h: ditto
* sh-tdep.c, config/sh/tm-sh.h: Ditto.
start-sanitize-v850
* v850-tdep.c: ditto
* config/v850/tm-v850.h: ditto
* v850-tdep.c, config/v850/tm-v850.h: Ditto.
end-sanitize-v850
Wed Nov 27 10:32:14 1996 Michael Snyder <msnyder@cleaver.cygnus.com>

View File

@ -436,13 +436,6 @@ show_regs (args, from_tty)
printf_filtered ("A0-A1 %010llx %010llx\n",num1, num2);
}
void
_initialize_d10v_tdep ()
{
tm_print_insn = print_insn_d10v;
add_com ("regs", class_vars, show_regs, "Print all registers");
}
static CORE_ADDR
d10v_xlate_addr (addr)
int addr;
@ -651,5 +644,307 @@ d10v_extract_return_value (valtype, regbuf, valbuf)
char regbuf[REGISTER_BYTES];
char *valbuf;
{
memcpy (valbuf, regbuf + REGISTER_BYTE (2), TYPE_LENGTH (valtype));
memcpy (valbuf, regbuf + REGISTER_BYTE (2), TYPE_LENGTH (valtype));
}
/* The following code implements access to, and display of, the D10V's
instruction trace buffer. The buffer consists of 64K or more
4-byte words of data, of which each words includes an 8-bit count,
and 8-bit segment number, and a 16-bit instruction address.
In theory, the trace buffer is continuously capturing instruction
data that the CPU presents on its "debug bus", but in practice, the
ROMified GDB stub only enables tracing when it continues or steps
the program, and stops tracing when the program stops; so it
actually works for GDB to read the buffer counter out of memory and
then read each trace word. The counter records where the tracing
stops, but there is no record of where it started, so we remember
the PC when we resumed and then search backwards in the trace
buffer for a word that includes that address. This is not perfect,
because you will miss trace data if the resumption PC is the target
of a branch. (The value of the buffer counter is semi-random, any
trace data from a previous program stop is gone.) */
/* The address of the last word recorded in the trace buffer. */
#define DBBC_ADDR (0xd80000)
/* The base of the trace buffer, at least for the "Board_0". */
#define TRACE_BUFFER_BASE (0xf40000)
static void trace_command PARAMS ((char *, int));
static void untrace_command PARAMS ((char *, int));
static void trace_info PARAMS ((char *, int));
static void tdisassemble_command PARAMS ((char *, int));
static void display_trace PARAMS ((int, int));
/* True when instruction traces are being collected. */
static int tracing;
/* Remembered PC. */
static CORE_ADDR last_pc;
static int trace_display;
struct trace_buffer {
int size;
short *counts;
CORE_ADDR *addrs;
} trace_data;
static void
trace_command (args, from_tty)
char *args;
int from_tty;
{
/* Clear the host-side trace buffer, allocating space if needed. */
trace_data.size = 0;
if (trace_data.counts == NULL)
trace_data.counts = (short *) xmalloc (65536 * sizeof(short));
if (trace_data.addrs == NULL)
trace_data.addrs = (CORE_ADDR *) xmalloc (65536 * sizeof(CORE_ADDR));
tracing = 1;
printf_filtered ("Tracing is now on.\n");
}
static void
untrace_command (args, from_tty)
char *args;
int from_tty;
{
tracing = 0;
printf_filtered ("Tracing is now off.\n");
}
static void
trace_info (args, from_tty)
char *args;
int from_tty;
{
int i;
printf_filtered ("%d entries in trace buffer:\n", trace_data.size);
for (i = 0; i < trace_data.size; ++i)
{
printf_filtered ("%d: %d instruction%s at 0x%x\n",
i, trace_data.counts[i],
(trace_data.counts[i] == 1 ? "" : "s"),
trace_data.addrs[i]);
}
printf_filtered ("Tracing is currently %s.\n", (tracing ? "on" : "off"));
}
/* Print the instruction at address MEMADDR in debugged memory,
on STREAM. Returns length of the instruction, in bytes. */
static int
print_insn (memaddr, stream)
CORE_ADDR memaddr;
GDB_FILE *stream;
{
/* If there's no disassembler, something is very wrong. */
if (tm_print_insn == NULL)
abort ();
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
tm_print_insn_info.endian = BFD_ENDIAN_BIG;
else
tm_print_insn_info.endian = BFD_ENDIAN_LITTLE;
return (*tm_print_insn) (memaddr, &tm_print_insn_info);
}
void
d10v_eva_prepare_to_trace ()
{
if (!tracing)
return;
last_pc = read_register (PC_REGNUM);
}
/* Collect trace data from the target board and format it into a form
more useful for display. */
void
d10v_eva_get_trace_data ()
{
int count, i, j, oldsize;
int trace_addr, trace_seg, trace_cnt, next_cnt;
unsigned int last_trace, trace_word, next_word;
unsigned int *tmpspace;
if (!tracing)
return;
tmpspace = xmalloc (65536 * sizeof(unsigned int));
last_trace = read_memory_unsigned_integer (DBBC_ADDR, 2) << 2;
#if 0
printf_filtered("Last pc is %x, is now %x\n",
last_pc, read_register (PC_REGNUM));
#endif
/* Collect buffer contents from the target, stopping when we reach
the word recorded when execution resumed. */
count = 0;
while (last_trace > 0)
{
QUIT;
trace_word =
read_memory_unsigned_integer (TRACE_BUFFER_BASE + last_trace, 4);
trace_addr = trace_word & 0xffff;
#if 0
trace_seg = (trace_word >> 16) & 0xff;
trace_cnt = (trace_word >> 24) & 0xff;
printf_filtered("Trace word at %x is %x %x %x\n", last_trace,
trace_cnt, trace_seg, trace_addr);
#endif
last_trace -= 4;
/* Ignore an apparently nonsensical entry. */
if (trace_addr == 0xffd5)
continue;
tmpspace[count++] = trace_word;
if (trace_addr == last_pc)
break;
if (count > 65535)
break;
}
/* Move the data to the host-side trace buffer, adjusting counts to
include the last instruction executed and transforming the address
into something that GDB likes. */
for (i = 0; i < count; ++i)
{
trace_word = tmpspace[i];
next_word = ((i == 0) ? 0 : tmpspace[i - 1]);
trace_addr = trace_word & 0xffff;
next_cnt = (next_word >> 24) & 0xff;
j = trace_data.size + count - i - 1;
trace_data.addrs[j] = (trace_addr << 2) + 0x1000000;
trace_data.counts[j] = next_cnt + 1;
}
oldsize = trace_data.size;
trace_data.size += count;
free (tmpspace);
#if 0
for (i = 0; i < trace_data.size; ++i)
{
printf_filtered("%d insns after %x\n",
trace_data.counts[i], trace_data.addrs[i]);
}
#endif
if (trace_display)
display_trace (oldsize, trace_data.size);
}
static void
tdisassemble_command (arg, from_tty)
char *arg;
int from_tty;
{
int i, count;
CORE_ADDR low, high;
char *space_index;
if (!arg)
{
low = 0;
high = trace_data.size;
}
else if (!(space_index = (char *) strchr (arg, ' ')))
{
low = parse_and_eval_address (arg);
high = low + 5;
}
else
{
/* Two arguments. */
*space_index = '\0';
low = parse_and_eval_address (arg);
high = parse_and_eval_address (space_index + 1);
}
printf_filtered ("Dump of trace ");
printf_filtered ("from ");
print_address_numeric (low, 1, gdb_stdout);
printf_filtered (" to ");
print_address_numeric (high, 1, gdb_stdout);
printf_filtered (":\n");
display_trace (low, high);
printf_filtered ("End of trace dump.\n");
gdb_flush (gdb_stdout);
}
static void
display_trace (low, high)
int low, high;
{
int i, count;
CORE_ADDR next_address;
for (i = low; i < high; ++i)
{
next_address = trace_data.addrs[i];
count = trace_data.counts[i];
while (count-- > 0)
{
QUIT;
print_address (next_address, gdb_stdout);
printf_filtered (":");
printf_filtered ("\t");
wrap_here (" ");
next_address = next_address + print_insn (next_address, gdb_stdout);
printf_filtered ("\n");
gdb_flush (gdb_stdout);
}
}
}
void
_initialize_d10v_tdep ()
{
tm_print_insn = print_insn_d10v;
add_com ("regs", class_vars, show_regs, "Print all registers");
add_com ("trace", class_support, trace_command,
"Enable tracing of instruction execution.");
add_com ("untrace", class_support, untrace_command,
"Disable tracing of instruction execution.");
add_com ("tdisassemble", class_vars, tdisassemble_command,
"Disassemble the trace buffer.\n\
Two optional arguments specify a range of trace buffer entries\n\
as reported by info trace (NOT addresses!).");
add_info ("trace", trace_info,
"Display info about the trace data buffer.");
add_show_from_set (add_set_cmd ("tracedisplay", no_class,
var_integer, (char *)&trace_display,
"Set automatic display of trace.\n", &setlist),
&showlist);
}