mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-24 02:24:46 +08:00
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:
parent
7c1687a966
commit
67c86d0683
@ -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.
|
||||
|
203
gdb/record.c
203
gdb/record.c
@ -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);
|
||||
}
|
||||
|
51
gdb/target.c
51
gdb/target.c
@ -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)
|
||||
{
|
||||
|
25
gdb/target.h
25
gdb/target.h
@ -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) */
|
||||
|
Loading…
Reference in New Issue
Block a user