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> 2013-03-11 Markus Metzger <markus.t.metzger@intel.com>
* record.h (record_disconnect): New. * record.h (record_disconnect): New.

View File

@ -24,10 +24,17 @@
#include "observer.h" #include "observer.h"
#include "inferior.h" #include "inferior.h"
#include "common/common-utils.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. */ /* This is the debug switch for process record. */
unsigned int record_debug = 0; 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 *record_cmdlist = NULL;
struct cmd_list_element *set_record_cmdlist = NULL; struct cmd_list_element *set_record_cmdlist = NULL;
struct cmd_list_element *show_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. */ /* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_record; extern initialize_file_ftype _initialize_record;
@ -330,6 +507,13 @@ _initialize_record (void)
NULL, show_record_debug, &setdebuglist, NULL, show_record_debug, &setdebuglist,
&showdebuglist); &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, c = add_prefix_cmd ("record", class_obscure, cmd_record_start,
_("Start recording."), _("Start recording."),
&record_cmdlist, "record ", 0, &cmdlist); &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\ Restore the program to its state at instruction number N.\n\
Argument is instruction number, as shown by 'info record'."), Argument is instruction number, as shown by 'info record'."),
&record_cmdlist); &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 (); 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 static void
debug_to_prepare_to_store (struct regcache *regcache) 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. */ /* Go to a specific location in the recorded execution trace. */
void (*to_goto_record) (ULONGEST insn); 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; int to_magic;
/* Need sub-structure for target machine related rather than comm related? /* 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. */ /* See to_goto_record in struct target_ops. */
extern void target_goto_record (ULONGEST insn); 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) */ #endif /* !defined (TARGET_H) */