Add a command to provide a disassembly of the execution trace log.

gdb/
	* target.h (target_ops) <to_insn_history, to_insn_history_from,
	to_insn_history_range>: New fields.
	(target_insn_history): New.
	(target_insn_history_from): New.
	(target_insn_history_range): New.
	* target.c (target_insn_history): New.
	(target_insn_history_from): New.
	(target_insn_history_range): New.
	* record.c: Include cli/cli-utils.h, disasm.h, ctype.h.
	(record_insn_history_size): New.
	(get_insn_number): New.
	(get_context_size): New.
	(no_chunk): New.
	(get_insn_history_modifiers): New.
	(cmd_record_insn_history): New.
	(_initialize_record): Add "set/show record instruction-history-size"
	command. Add "record instruction-history" command.
This commit is contained in:
Markus Metzger 2013-03-11 08:48:38 +00:00
parent 7c1687a966
commit 67c86d0683
4 changed files with 299 additions and 0 deletions

View File

@ -1,3 +1,23 @@
2013-03-11 Markus Metzger <markus.t.metzger@intel.com>
* target.h (target_ops) <to_insn_history, to_insn_history_from,
to_insn_history_range>: New fields.
(target_insn_history): New.
(target_insn_history_from): New.
(target_insn_history_range): New.
* target.c (target_insn_history): New.
(target_insn_history_from): New.
(target_insn_history_range): New.
* record.c: Include cli/cli-utils.h, disasm.h, ctype.h.
(record_insn_history_size): New.
(get_insn_number): New.
(get_context_size): New.
(no_chunk): New.
(get_insn_history_modifiers): New.
(cmd_record_insn_history): New.
(_initialize_record): Add "set/show record instruction-history-size"
command. Add "record instruction-history" command.
2013-03-11 Markus Metzger <markus.t.metzger@intel.com>
* record.h (record_disconnect): New.

View File

@ -24,10 +24,17 @@
#include "observer.h"
#include "inferior.h"
#include "common/common-utils.h"
#include "cli/cli-utils.h"
#include "disasm.h"
#include <ctype.h>
/* This is the debug switch for process record. */
unsigned int record_debug = 0;
/* The number of instructions to print in "record instruction-history". */
static unsigned int record_insn_history_size = 10;
struct cmd_list_element *record_cmdlist = NULL;
struct cmd_list_element *set_record_cmdlist = NULL;
struct cmd_list_element *show_record_cmdlist = NULL;
@ -314,6 +321,176 @@ cmd_record_goto (char *arg, int from_tty)
}
}
/* Read an instruction number from an argument string. */
static ULONGEST
get_insn_number (char **arg)
{
ULONGEST number;
const char *begin, *end, *pos;
begin = *arg;
pos = skip_spaces_const (begin);
if (!isdigit (*pos))
error (_("Expected positive number, got: %s."), pos);
number = strtoulst (pos, &end, 10);
*arg += (end - begin);
return number;
}
/* Read a context size from an argument string. */
static int
get_context_size (char **arg)
{
char *pos;
int number;
pos = skip_spaces (*arg);
if (!isdigit (*pos))
error (_("Expected positive number, got: %s."), pos);
return strtol (pos, arg, 10);
}
/* Complain about junk at the end of an argument string. */
static void
no_chunk (char *arg)
{
if (*arg != 0)
error (_("Junk after argument: %s."), arg);
}
/* Read instruction-history modifiers from an argument string. */
static int
get_insn_history_modifiers (char **arg)
{
int modifiers;
char *args;
modifiers = 0;
args = *arg;
if (args == NULL)
return modifiers;
while (*args == '/')
{
++args;
if (*args == '\0')
error (_("Missing modifier."));
for (; *args; ++args)
{
if (isspace (*args))
break;
if (*args == '/')
continue;
switch (*args)
{
case 'm':
modifiers |= DISASSEMBLY_SOURCE;
modifiers |= DISASSEMBLY_FILENAME;
break;
case 'r':
modifiers |= DISASSEMBLY_RAW_INSN;
break;
case 'f':
modifiers |= DISASSEMBLY_OMIT_FNAME;
break;
default:
error (_("Invalid modifier: %c."), *args);
}
}
args = skip_spaces (args);
}
/* Update the argument string. */
*arg = args;
return modifiers;
}
/* The "record instruction-history" command. */
static void
cmd_record_insn_history (char *arg, int from_tty)
{
int flags, size;
require_record_target ();
flags = get_insn_history_modifiers (&arg);
/* We use a signed size to also indicate the direction. Make sure that
unlimited remains unlimited. */
size = (int) record_insn_history_size;
if (size < 0)
size = INT_MAX;
if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0)
target_insn_history (size, flags);
else if (strcmp (arg, "-") == 0)
target_insn_history (-size, flags);
else
{
ULONGEST begin, end;
begin = get_insn_number (&arg);
if (*arg == ',')
{
arg = skip_spaces (++arg);
if (*arg == '+')
{
arg += 1;
size = get_context_size (&arg);
no_chunk (arg);
target_insn_history_from (begin, size, flags);
}
else if (*arg == '-')
{
arg += 1;
size = get_context_size (&arg);
no_chunk (arg);
target_insn_history_from (begin, -size, flags);
}
else
{
end = get_insn_number (&arg);
no_chunk (arg);
target_insn_history_range (begin, end, flags);
}
}
else
{
no_chunk (arg);
target_insn_history_from (begin, size, flags);
}
dont_repeat ();
}
}
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_record;
@ -330,6 +507,13 @@ _initialize_record (void)
NULL, show_record_debug, &setdebuglist,
&showdebuglist);
add_setshow_uinteger_cmd ("instruction-history-size", no_class,
&record_insn_history_size, _("\
Set number of instructions to print in \"record instruction-history\"."), _("\
Show number of instructions to print in \"record instruction-history\"."),
NULL, NULL, NULL, &set_record_cmdlist,
&show_record_cmdlist);
c = add_prefix_cmd ("record", class_obscure, cmd_record_start,
_("Start recording."),
&record_cmdlist, "record ", 0, &cmdlist);
@ -371,4 +555,23 @@ Default filename is 'gdb_record.<process_id>'."),
Restore the program to its state at instruction number N.\n\
Argument is instruction number, as shown by 'info record'."),
&record_cmdlist);
add_cmd ("instruction-history", class_obscure, cmd_record_insn_history, _("\
Print disassembled instructions stored in the execution log.\n\
With a /m modifier, source lines are included (if available).\n\
With a /r modifier, raw instructions in hex are included.\n\
With a /f modifier, function names are omitted.\n\
With no argument, disassembles ten more instructions after the previous \
disassembly.\n\
\"record instruction-history -\" disassembles ten instructions before a \
previous disassembly.\n\
One argument specifies an instruction number as shown by 'info record', and \
ten instructions are disassembled after that instruction.\n\
Two arguments with comma between them specify starting and ending instruction \
numbers to disassemble.\n\
If the second argument is preceded by '+' or '-', it specifies the distance \
from the first argument.\n\
The number of instructions to disassemble can be defined with \"set record \
instruction-history-size\"."),
&record_cmdlist);
}

View File

@ -4388,6 +4388,57 @@ target_goto_record (ULONGEST insn)
tcomplain ();
}
/* See target.h. */
void
target_insn_history (int size, int flags)
{
struct target_ops *t;
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_insn_history != NULL)
{
t->to_insn_history (size, flags);
return;
}
tcomplain ();
}
/* See target.h. */
void
target_insn_history_from (ULONGEST from, int size, int flags)
{
struct target_ops *t;
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_insn_history_from != NULL)
{
t->to_insn_history_from (from, size, flags);
return;
}
tcomplain ();
}
/* See target.h. */
void
target_insn_history_range (ULONGEST begin, ULONGEST end, int flags)
{
struct target_ops *t;
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_insn_history_range != NULL)
{
t->to_insn_history_range (begin, end, flags);
return;
}
tcomplain ();
}
static void
debug_to_prepare_to_store (struct regcache *regcache)
{

View File

@ -906,6 +906,22 @@ struct target_ops
/* Go to a specific location in the recorded execution trace. */
void (*to_goto_record) (ULONGEST insn);
/* Disassemble SIZE instructions in the recorded execution trace from
the current position.
If SIZE < 0, disassemble abs (SIZE) preceding instructions; otherwise,
disassemble SIZE succeeding instructions. */
void (*to_insn_history) (int size, int flags);
/* Disassemble SIZE instructions in the recorded execution trace around
FROM.
If SIZE < 0, disassemble abs (SIZE) instructions before FROM; otherwise,
disassemble SIZE instructions after FROM. */
void (*to_insn_history_from) (ULONGEST from, int size, int flags);
/* Disassemble a section of the recorded execution trace from instruction
BEGIN (inclusive) to instruction END (exclusive). */
void (*to_insn_history_range) (ULONGEST begin, ULONGEST end, int flags);
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@ -1997,4 +2013,13 @@ extern void target_goto_record_end (void);
/* See to_goto_record in struct target_ops. */
extern void target_goto_record (ULONGEST insn);
/* See to_insn_history. */
extern void target_insn_history (int size, int flags);
/* See to_insn_history_from. */
extern void target_insn_history_from (ULONGEST from, int size, int flags);
/* See to_insn_history_range. */
extern void target_insn_history_range (ULONGEST begin, ULONGEST end, int flags);
#endif /* !defined (TARGET_H) */