2010-06-29 Hui Zhu <teawater@gmail.com>

* record.c (set_record_pic_cmdlist,
	show_record_pic_cmdlist): New variables.
	(set_record_pic_command,
	show_record_pic_command): New functions.
	(record_pic_function, record_pic_line, record_pic_enum,
	set_record_pic_type, record_pic_hide_nofunction,
	record_pic_hide_nosource, record_pic_hide_same): New variables.
	(record_pic_fputs): New function.
	(function_list, node_list, edge_list): New struct.
	(function_list, node_list, edge_list): New variables.
	(record_pic_cleanups, record_pic_node,
	record_pic_edge, cmd_record_pic): New functions.
	(_initialize_record): Add new commands for record pic.
This commit is contained in:
Hui Zhu 2010-06-29 05:52:17 +00:00
parent dc3b15be96
commit a480d2f6c8
2 changed files with 626 additions and 0 deletions

View File

@ -1,3 +1,19 @@
2010-06-29 Hui Zhu <teawater@gmail.com>
* record.c (set_record_pic_cmdlist,
show_record_pic_cmdlist): New variables.
(set_record_pic_command,
show_record_pic_command): New functions.
(record_pic_function, record_pic_line, record_pic_enum,
set_record_pic_type, record_pic_hide_nofunction,
record_pic_hide_nosource, record_pic_hide_same): New variables.
(record_pic_fputs): New function.
(function_list, node_list, edge_list): New struct.
(function_list, node_list, edge_list): New variables.
(record_pic_cleanups, record_pic_node,
record_pic_edge, cmd_record_pic): New functions.
(_initialize_record): Add new commands for record pic.
2010-06-28 Jan Kratochvil <jan.kratochvil@redhat.com>
* dwarf2read.c (read_structure_type) <fi.typedef_field_list>: Call

View File

@ -2549,6 +2549,555 @@ cmd_record_save (char *args, int from_tty)
recfilename);
}
/* For "record pic" command. */
static struct cmd_list_element *set_record_pic_cmdlist,
*show_record_pic_cmdlist;
static void
set_record_pic_command (char *args, int from_tty)
{
printf_unfiltered (_("\
\"set record pic\" must be followed by an apporpriate subcommand.\n"));
help_list (set_record_cmdlist, "set record pic ", all_commands, gdb_stdout);
}
static void
show_record_pic_command (char *args, int from_tty)
{
cmd_show_list (show_record_pic_cmdlist, from_tty, "");
}
static const char record_pic_function[] = "function";
static const char record_pic_line[] = "line";
static const char *record_pic_enum[] =
{
record_pic_function,
record_pic_line,
NULL,
};
static const char *set_record_pic_type = record_pic_line;
static int record_pic_hide_nofunction = 1;
static int record_pic_hide_nosource = 1;
static int record_pic_hide_same = 1;
static void
record_pic_fputs (FILE *fp, const char *buf)
{
if (fputs (buf, fp) == EOF)
error (_("Write to file error."));
}
struct function_list
{
struct function_list *next;
CORE_ADDR addr;
int fid;
};
struct node_list
{
struct node_list *next;
int count;
CORE_ADDR addr;
int showall;
struct symtab *symtab;
int line;
struct minimal_symbol *function;
int fid;
};
struct edge_list
{
struct edge_list *next;
int count;
struct node_list *s;
struct node_list *t;
int frame_diff;
int is_return;
};
struct function_list *function_list = NULL;
struct node_list *node_list = NULL;
struct edge_list *edge_list = NULL;
static void
record_pic_cleanups (void *data)
{
FILE *fp = data;
struct function_list *fl, *fl2;
struct node_list *nl, *nl2;
struct edge_list *el, *el2;
fl = function_list;
while (fl)
{
fl2 = fl;
fl = fl->next;
xfree (fl2);
}
function_list = NULL;
nl = node_list;
while (nl)
{
nl2 = nl;
nl = nl->next;
xfree (nl2);
}
node_list = NULL;
el = edge_list;
while (el)
{
el2 = el;
el = el->next;
xfree (el2);
}
edge_list = NULL;
fclose (fp);
}
static void
record_pic_node (char *buf, int buf_max, struct gdbarch *gdbarch,
const char *type, struct node_list *nlp)
{
if (type == record_pic_function)
{
snprintf (buf, buf_max, "%s %s %s",
(nlp->symtab) ? nlp->symtab->filename : "",
(nlp->function) ? SYMBOL_LINKAGE_NAME (nlp->function) : "",
(!nlp->function) ? paddress (gdbarch, nlp->addr) : "");
}
else
{
if (nlp->showall)
{
snprintf (buf, buf_max, "%s:%d %s %s", nlp->symtab->filename,
nlp->line,
(nlp->function) ? SYMBOL_LINKAGE_NAME (nlp->function) : "",
paddress (gdbarch, nlp->addr));
}
else
{
if (nlp->symtab)
snprintf (buf, buf_max, "%s %d %s",
(nlp->function) ? SYMBOL_LINKAGE_NAME (nlp->function) : "",
nlp->line, paddress (gdbarch, nlp->addr));
else
snprintf (buf, buf_max, "%s %s",
(nlp->function) ? SYMBOL_LINKAGE_NAME (nlp->function) : "",
paddress (gdbarch, nlp->addr));
}
}
}
static void
record_pic_edge (char *buf, int buf_max, struct edge_list *elp,
char *node, char *prev_node)
{
if (elp->frame_diff)
{
if (elp->is_return)
snprintf (buf, buf_max, "edge: {color:blue sourcename: \"%s\" "
"targetname: \"%s\"",
prev_node, node);
else
snprintf (buf, buf_max, "edge: {color:red sourcename: \"%s\" "
"targetname: \"%s\"",
prev_node, node);
}
else
snprintf (buf, buf_max,
"edge: {sourcename: \"%s\" targetname: \"%s\"",
prev_node, node);
}
/* Save the execution log to a vcg file. */
static void
cmd_record_pic (char *args, int from_tty)
{
char *recfilename, recfilename_buffer[40];
FILE *fp;
struct cleanup *old_cleanups, *set_cleanups;
struct regcache *regcache;
struct gdbarch *gdbarch;
struct record_entry *cur_record_list;
char prev_node[256], line[256];
CORE_ADDR prev_addr;
struct frame_id fi, caller_fi, prev_fi, prev_caller_fi;
struct function_list *function_list_tail, *function_list_prev;
struct edge_list *edge_list_tail = NULL;
struct node_list *node_list_tail = NULL;
struct symtab_and_line sal, prev_sal;
struct node_list *prev_nlp;
struct node_list prev_nlp_real;
int fid_count = 1;
/* Check if record target is running. */
if (current_target.to_stratum != record_stratum)
error (_("This command can only be used with target 'record' \
or target 'record-core'."));
if (args && *args)
recfilename = args;
else
{
/* Default recfile name is "gdb_record_PID.vcg". */
snprintf (recfilename_buffer, sizeof (recfilename_buffer),
"gdb_record_%d.vcg", PIDGET (inferior_ptid));
recfilename = recfilename_buffer;
}
/* Open the output file. */
fp = fopen (recfilename, "wb");
if (!fp)
error (_("Unable to open file '%s'"), recfilename);
old_cleanups = make_cleanup (record_pic_cleanups, fp);
/* Save the current record entry to "cur_record_list". */
cur_record_list = record_list;
/* Get the values of regcache and gdbarch. */
regcache = get_current_regcache ();
gdbarch = get_regcache_arch (regcache);
/* Disable the GDB operation record. */
set_cleanups = record_gdb_operation_disable_set ();
/* Reverse execute to the begin of record list. */
while (1)
{
/* Check for beginning and end of log. */
if (record_list == &record_first)
break;
record_exec_insn (regcache, gdbarch, record_list);
if (record_list->prev)
record_list = record_list->prev;
}
/* Write out the record log. */
/* Write the head. */
record_pic_fputs (fp, "graph: {title: \"GDB process record\"\n");
/* Write the first node. */
record_pic_fputs (fp, "node: {title: \"[BEGIN]\" vertical_order:0}\n");
/* Initialization. */
snprintf (prev_node, 256, "[BEGIN]");
prev_fi = null_frame_id;
prev_caller_fi = null_frame_id;
prev_addr = 0;
prev_sal.symtab = NULL;
prev_sal.pc = 0;
prev_sal.end = 0;
prev_nlp_real.addr = 0;
prev_nlp = &prev_nlp_real;
/* Create first entry for function_list. */
function_list = xmalloc (sizeof (struct function_list));
function_list->next = NULL;
function_list->addr = 0;
function_list->fid = -1;
function_list_tail = function_list;
function_list_prev = function_list;
/* Save the entries to fp and forward execute to the end of
record list. */
record_list = &record_first;
while (1)
{
if (record_list->type == record_end)
{
int frame_diff = 0;
CORE_ADDR addr = regcache_read_pc (regcache);
/* Check if the ADDR is stil in the same line with the
prev cycle. */
if (prev_sal.symtab
&& addr >= prev_sal.pc && addr < prev_sal.end)
goto exec;
sal = find_pc_line (addr, 0);
if (record_pic_hide_nosource && !sal.symtab)
goto exec;
/* Check if the inferior is in same frame with prev cycle.
Check both the current fi and caller fi because the last
addr of function is different with current function. */
reinit_frame_cache ();
fi = get_frame_id (get_current_frame ());
caller_fi = frame_unwind_caller_id (get_current_frame ());
if (!frame_id_eq (prev_fi, fi)
&& !frame_id_eq (prev_caller_fi, caller_fi))
frame_diff = 1;
if (set_record_pic_type == record_pic_line || frame_diff)
{
int is_return = 0;
struct node_list *nlp = NULL;
struct edge_list *elp = NULL;
char node[256];
struct minimal_symbol *function;
/* Get the node addr. */
if (set_record_pic_type == record_pic_function)
{
/* Get the start addr of function. */
addr = get_pc_function_start (addr);
if (addr == 0)
{
if (record_pic_hide_nofunction)
goto exec;
addr = regcache_read_pc (regcache);
}
}
else
{
/* Get the start addr of line. */
if (sal.symtab)
addr = sal.pc;
}
function = lookup_minimal_symbol_by_pc (addr);
if (!function && record_pic_hide_nofunction)
goto exec;
if (frame_id_eq (fi, prev_caller_fi))
is_return = 1;
if (record_pic_hide_same)
{
/* Check if addr in node_list. */
for (nlp = node_list; nlp; nlp = nlp->next)
{
if (nlp->addr == addr)
{
if (!is_return
|| set_record_pic_type != record_pic_function)
nlp->count ++;
break;
}
}
/* Check if prev_addr and addr in edge_list. */
if (nlp)
{
for (elp = edge_list; elp; elp = elp->next)
{
if (elp->s->addr == prev_addr && elp->t->addr == addr)
{
elp->count ++;
break;
}
}
}
}
if (!nlp)
{
struct node_list nl;
CORE_ADDR function_addr;
struct function_list *flp;
nl.addr = addr;
if (frame_diff && sal.symtab)
nl.showall = 1;
else
nl.showall = 0;
nl.symtab = sal.symtab;
nl.line = sal.line;
nl.function = function;
/* Get the fid of the nl. */
if (set_record_pic_type != record_pic_function)
function_addr = get_pc_function_start (addr);
else
function_addr = addr;
if (function_list_prev->addr == function_addr)
nl.fid = function_list_prev->fid;
else
{
for (flp = function_list; flp; flp = flp->next)
{
if (flp->addr == function_addr)
{
nl.fid = flp->fid;
break;
}
}
if (flp == NULL)
{
/* Creat a new entry to function_list. */
nl.fid = fid_count ++;
flp = xmalloc (sizeof (struct function_list));
flp->addr = function_addr;
flp->fid = nl.fid;
flp->next = NULL;
function_list_tail->next = flp;
function_list_tail = flp;
}
function_list_prev = flp;
}
if (record_pic_hide_same)
{
nlp = xmalloc (sizeof (struct node_list));
*nlp = nl;
nlp->count = 1;
/* Add node to node_list. */
nlp->next = NULL;
if (node_list_tail)
node_list_tail->next = nlp;
if (node_list == NULL)
node_list = nlp;
node_list_tail = nlp;
}
else
{
/* Draw the node. */
record_pic_node (node, 256, gdbarch,
set_record_pic_type, &nl);
snprintf (line, 256, "%s i:%s", node,
pulongest (record_list->u.end.insn_num));
strcpy (node, line);
snprintf (line, 256, "node: {title: \"%s\" "
"vertical_order: %d}\n",
node, nl.fid);
record_pic_fputs (fp, line);
}
}
if (!elp)
{
struct edge_list el;
el.is_return = is_return;
el.frame_diff = frame_diff;
if (record_pic_hide_same)
{
elp = xmalloc (sizeof (struct edge_list));
*elp = el;
elp->s = prev_nlp;
elp->t = nlp;
elp->count = 1;
/* Add edge to edge_list. */
elp->next = NULL;
if (edge_list_tail)
edge_list_tail->next = elp;
if (edge_list == NULL)
edge_list = elp;
edge_list_tail = elp;
}
else
{
/* Draw the edge. */
record_pic_edge (line, 256, &el, node, prev_node);
record_pic_fputs (fp, line);
record_pic_fputs (fp, " }\n");
}
}
if (record_pic_hide_same)
prev_nlp = nlp;
else
snprintf (prev_node, 256, "%s", node);
prev_addr = addr;
}
prev_sal = sal;
prev_fi = fi;
prev_caller_fi = caller_fi;
}
exec:
/* Execute entry. */
record_exec_insn (regcache, gdbarch, record_list);
if (record_list->next)
record_list = record_list->next;
else
break;
}
if (record_pic_hide_same)
{
struct node_list *nlp = NULL;
struct edge_list *elp = NULL;
char node[256];
for (nlp = node_list; nlp; nlp = nlp->next)
{
/* Draw the node. */
record_pic_node (node, 256, gdbarch, set_record_pic_type, nlp);
snprintf (line, 256, "node: {title: \"%s c:%d\" "
"vertical_order: %d}\n", node,
nlp->count, nlp->fid);
record_pic_fputs (fp, line);
}
record_pic_node (node, 256, gdbarch, set_record_pic_type, edge_list->t);
snprintf (line, 256,
"edge: {color:red sourcename: \"[BEGIN]\" targetname: \"%s c:%d\"}\n",
node, edge_list->count);
record_pic_fputs (fp, line);
for (elp = edge_list->next; elp; elp = elp->next)
{
/* Draw the edge. */
record_pic_node (prev_node, 256, gdbarch, set_record_pic_type,
elp->s);
snprintf (line, 256, "%s c:%d", prev_node, elp->s->count);
strcpy (prev_node, line);
record_pic_node (node, 256, gdbarch, set_record_pic_type,
elp->t);
snprintf (line, 256, "%s c:%d", node, elp->t->count);
strcpy (node, line);
record_pic_edge (line, 256, elp, node, prev_node);
record_pic_fputs (fp, line);
snprintf (line, 256, " label: \"c:%d\"}\n", elp->count);
record_pic_fputs (fp, line);
}
}
/* Write the last node. */
snprintf (line, 256, "node: {title: \"[END]\" vertical_order: %d}\n",
fid_count);
record_pic_fputs (fp, line);
snprintf (line, 256,
"edge: {color:red sourcename: \"%s\" targetname: \"[END]\" }\n",
prev_node);
record_pic_fputs (fp, line);
/* Write the tail. */
record_pic_fputs (fp, "}\n");
/* Reverse execute to cur_record_list. */
while (1)
{
/* Check for beginning and end of log. */
if (record_list == cur_record_list)
break;
record_exec_insn (regcache, gdbarch, record_list);
if (record_list->prev)
record_list = record_list->prev;
}
do_cleanups (set_cleanups);
do_cleanups (old_cleanups);
/* Succeeded. */
printf_filtered (_("Saved file %s with execution log.\n"),
recfilename);
}
/* record_goto_insn -- rewind the record log (forward or backward,
depending on DIR) to the given entry, changing the program state
correspondingly. */
@ -2745,4 +3294,65 @@ Default is OFF.\n\
When ON, query if PREC cannot record memory change of next instruction."),
NULL, NULL,
&set_record_cmdlist, &show_record_cmdlist);
/* For "record pic" command. */
c = add_cmd ("pic", class_obscure, cmd_record_pic,
_("Save the execution log to a vcg file.\n\
Argument is optional filename.\n\
Default filename is 'gdb_record_<process_id>.vcg'."),
&record_cmdlist);
set_cmd_completer (c, filename_completer);
add_prefix_cmd ("pic", class_support, set_record_pic_command,
_("Set record pic options"), &set_record_pic_cmdlist,
"set record pic ", 0, &set_record_cmdlist);
add_prefix_cmd ("pic", class_support, show_record_pic_command,
_("Show record pic options"), &show_record_pic_cmdlist,
"show record pic ", 0, &show_record_cmdlist);
add_setshow_enum_cmd ("type", no_class,
record_pic_enum, &set_record_pic_type, _("\
Set the type of the nodes that record pic command saved."), _("\
Show the type of the nodes that record pic command saved."), _("\
When LINE, each node of vcg file that command record pic saved\n\
will be a line of the inferior.\n\
When FUNCTION, each node of vcg file that command record pic saved\n\
will be a function of the inferior."),
NULL, NULL,
&set_record_pic_cmdlist, &show_record_pic_cmdlist);
add_setshow_boolean_cmd ("hide-nofunction", no_class,
&record_pic_hide_nofunction, _("\
Set whether record pic command hide the nodes that don't have the function name."), _("\
Show whether record pic command hide the nodes that don't have the function name."), _("\
Default is ON.\n\
When ON, record pic command will hide the nodes that don't have\n\
the function name.\n\
When OFF, record pic command will show the nodes that don't have\n\
the function name."),
NULL, NULL,
&set_record_pic_cmdlist, &show_record_pic_cmdlist);
add_setshow_boolean_cmd ("hide-nosource", no_class,
&record_pic_hide_nosource, _("\
Set whether record pic command hide the nodes that don't have the source message."), _("\
Show whether record pic command hide the nodes that don't have the source message."), _("\
Default is ON.\n\
When ON, record pic command will hide the nodes that don't have\n\
the source message.\n\
When OFF, record pic command will show the nodes that don't have\n\
the source message."),
NULL, NULL,
&set_record_pic_cmdlist, &show_record_pic_cmdlist);
add_setshow_boolean_cmd ("hide-sameaddr", no_class,
&record_pic_hide_same, _("\
Set whether record pic command hide the nodes that have the same address node in vcg file."), _("\
Show whether record pic command hide the nodes that have the same address node in vcg file."), _("\
Default is ON.\n\
When ON, record pic command will hide the nodes that have\n\
the same address node in vcg file.\n\
And record pic will show the execute count number of this line\n\
in format \"c:number\".\n\
When OFF, record pic command will show the nodes that have\n\
the same address node in vcg file.\n\
And record pic show the instruction number in format \"i:number\"\n\
that \"record goto\" support."),
NULL, NULL,
&set_record_pic_cmdlist, &show_record_pic_cmdlist);
}