mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-20 18:08:24 +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:
@ -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.
|
||||||
|
203
gdb/record.c
203
gdb/record.c
@ -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);
|
||||||
}
|
}
|
||||||
|
51
gdb/target.c
51
gdb/target.c
@ -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)
|
||||||
{
|
{
|
||||||
|
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. */
|
/* 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) */
|
||||||
|
Reference in New Issue
Block a user