public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] record.c: make prec can save the execution log to a pic file
@ 2010-06-15 17:13 Hui Zhu
  2010-06-16  0:42 ` Michael Snyder
  0 siblings, 1 reply; 11+ messages in thread
From: Hui Zhu @ 2010-06-15 17:13 UTC (permalink / raw)
  To: gdb-patches ml

Hi guys,

Before you read my introduce about this feature, please see the pic
file in http://www.tuhigh.com/photo/p/1600958
This is a inferior execute log pic file.  The [BEGIN] and [END] is the
begin and the end this record.  The red line means call a function.
The blue line means function return.  The black line means simple
execute.
This pic is convented from vcg file to jpg file by graph-easy
(http://search.cpan.org/~tels/Graph-Easy/bin/graph-easy)
To see the vcg file directly.  I suggest you to use vcgviewer
(http://code.google.com/p/vcgviewer/).

This patch add some new commands:
record pic
Save the execution log to a vcg file.

set record pic type line/function
Set the type of record pic command saved file.
When LINE, show each line of the inferior.
When FUNCTION, just show the each function.

set record hide-nofunction on/off
Set whether record pic command hide the node that don't have function name.
Default is ON.
When ON, record pic command will hide the node that don't have function name.
When OFF, record pic command will show the node that don't have function name.

set record hide-nosource on/off
Set whether record pic command hide the node that don't have source message.
Default is ON.
When ON, record pic command will hide the node that don't have function name.
When OFF, record pic command will show the node that don't have function name.

set record hide-same on/off
Set whether record pic command hide the node that was shown in before.
Default is ON.
When ON, record pic command will hide the node that was shown in before.
It will show the execute count number of this line in format \"c:number\".
When OFF, record pic command will show the node that was shown in before.
It will show the instruction number in format \"i:number\" that
\"record goto\" support.

If this patch get approved.  I will post patch for doc and NEWS.

Thanks,
Hui

2010-06-16  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.
	(node_list, edge_list): New struct.
	(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.


---
 record.c |  537 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 537 insertions(+)

--- a/record.c
+++ b/record.c
@@ -2545,6 +2545,487 @@ cmd_record_save (char *args, int from_tt
 		   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 node_list
+{
+  struct node_list *next;
+  int count;
+  CORE_ADDR addr;
+  int showall;
+  struct symtab *symtab;
+  int line;
+  struct minimal_symbol *function;
+};
+struct edge_list
+{
+  struct edge_list *next;
+  int count;
+  struct node_list *s;
+  struct node_list *t;
+  int frame_diff;
+  int is_return;
+};
+struct node_list *node_list = NULL;
+struct edge_list *edge_list = NULL;
+
+static void
+record_pic_cleanups (void *data)
+{
+  FILE *fp = data;
+  struct node_list *nl, *nl2;
+  struct edge_list *el, *el2;
+
+  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,
+              "nearedge: {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 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;
+
+  /* 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]\"}\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_nlp_real.addr = 0;
+  prev_nlp = &prev_nlp_real;
+
+  /* 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;
+
+                  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;
+
+                  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\"}\n", node);
+                      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\"}\n", node,
+		    nlp->count);
+          record_pic_fputs (fp, line);
+	}
+
+      record_pic_node (node, 256, gdbarch, set_record_pic_type, edge_list->t);
+      snprintf (line, 256,
+	        "nearedge: {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.  */
+  record_pic_fputs (fp, "node: {title: \"[END]\"}\n");
+  snprintf (line, 256,
+	    "nearedge: {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.  */
@@ -2730,4 +3211,60 @@ record/replay buffer.  Zero means unlimi
 Restore the program to its state at instruction number N.\n\
 Argument is instruction number, as shown by 'info record'."),
 	   &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 record pic command saved file."), _("\
+Show the type of record pic command saved file."), _("\
+When LINE, show each line of the inferior.\n\
+When FUNCTION, just show the each function."),
+			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 node that don't have function
name."), _("\
+Show whether record pic command hide the node that don't have
function name."), _("\
+Default is ON.\n\
+When ON, record pic command will hide the node that don't have\n\
+function name.\n\
+When OFF, record pic command will show the node that don't have\n\
+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 node that don't have source
message."), _("\
+Show whether record pic command hide the node that don't have source
message."), _("\
+Default is ON.\n\
+When ON, record pic command will hide the node that don't have\n\
+function name.\n\
+When OFF, record pic command will show the node that don't have\n\
+function name."),
+			   NULL, NULL,
+			   &set_record_pic_cmdlist, &show_record_pic_cmdlist);
+  add_setshow_boolean_cmd ("hide-same", no_class,
+			   &record_pic_hide_same, _("\
+Set whether record pic command hide the node that was shown in before."), _("\
+Show whether record pic command hide the node that was shown in before."), _("\
+Default is ON.\n\
+When ON, record pic command will hide the node that was shown in before.\n\
+It will show the execute count number of this line in format \"c:number\".\n\
+When OFF, record pic command will show the node that was shown in before.\n\
+It will show the instruction number in format \"i:number\"\n\
+that \"record goto\" support."),
+			   NULL, NULL,
+			   &set_record_pic_cmdlist, &show_record_pic_cmdlist);
 }

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] record.c: make prec can save the execution log to a pic file
  2010-06-15 17:13 [PATCH] record.c: make prec can save the execution log to a pic file Hui Zhu
@ 2010-06-16  0:42 ` Michael Snyder
  2010-06-16  4:46   ` Hui Zhu
  0 siblings, 1 reply; 11+ messages in thread
From: Michael Snyder @ 2010-06-16  0:42 UTC (permalink / raw)
  To: Hui Zhu; +Cc: gdb-patches ml

Hui Zhu wrote:
> Hi guys,
> 
> Before you read my introduce about this feature, please see the pic
> file in http://www.tuhigh.com/photo/p/1600958
> This is a inferior execute log pic file.  The [BEGIN] and [END] is the
> begin and the end this record.  The red line means call a function.
> The blue line means function return.  The black line means simple
> execute.
> This pic is convented from vcg file to jpg file by graph-easy
> (http://search.cpan.org/~tels/Graph-Easy/bin/graph-easy)
> To see the vcg file directly.  I suggest you to use vcgviewer
> (http://code.google.com/p/vcgviewer/).

You really want to have gdb generate a graphics file?

Seems like you could offload this task to a post-processor program,
if you just save the record log file.  Then you could do anything
you wanted to with the data, without having to add complexity and
user commands to gdb.

> 
> This patch add some new commands:
> record pic
> Save the execution log to a vcg file.
> 
> set record pic type line/function
> Set the type of record pic command saved file.
> When LINE, show each line of the inferior.
> When FUNCTION, just show the each function.
> 
> set record hide-nofunction on/off
> Set whether record pic command hide the node that don't have function name.
> Default is ON.
> When ON, record pic command will hide the node that don't have function name.
> When OFF, record pic command will show the node that don't have function name.
> 
> set record hide-nosource on/off
> Set whether record pic command hide the node that don't have source message.
> Default is ON.
> When ON, record pic command will hide the node that don't have function name.
> When OFF, record pic command will show the node that don't have function name.
> 
> set record hide-same on/off
> Set whether record pic command hide the node that was shown in before.
> Default is ON.
> When ON, record pic command will hide the node that was shown in before.
> It will show the execute count number of this line in format \"c:number\".
> When OFF, record pic command will show the node that was shown in before.
> It will show the instruction number in format \"i:number\" that
> \"record goto\" support.
> 
> If this patch get approved.  I will post patch for doc and NEWS.
> 
> Thanks,
> Hui
> 
> 2010-06-16  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.
>         (node_list, edge_list): New struct.
>         (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.
> 
> 
> ---
>  record.c |  537 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 537 insertions(+)
> 
> --- a/record.c
> +++ b/record.c
> @@ -2545,6 +2545,487 @@ cmd_record_save (char *args, int from_tt
>                    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 node_list
> +{
> +  struct node_list *next;
> +  int count;
> +  CORE_ADDR addr;
> +  int showall;
> +  struct symtab *symtab;
> +  int line;
> +  struct minimal_symbol *function;
> +};
> +struct edge_list
> +{
> +  struct edge_list *next;
> +  int count;
> +  struct node_list *s;
> +  struct node_list *t;
> +  int frame_diff;
> +  int is_return;
> +};
> +struct node_list *node_list = NULL;
> +struct edge_list *edge_list = NULL;
> +
> +static void
> +record_pic_cleanups (void *data)
> +{
> +  FILE *fp = data;
> +  struct node_list *nl, *nl2;
> +  struct edge_list *el, *el2;
> +
> +  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,
> +              "nearedge: {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 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;
> +
> +  /* 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]\"}\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_nlp_real.addr = 0;
> +  prev_nlp = &prev_nlp_real;
> +
> +  /* 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;
> +
> +                  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;
> +
> +                  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\"}\n", node);
> +                      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\"}\n", node,
> +                   nlp->count);
> +          record_pic_fputs (fp, line);
> +       }
> +
> +      record_pic_node (node, 256, gdbarch, set_record_pic_type, edge_list->t);
> +      snprintf (line, 256,
> +               "nearedge: {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.  */
> +  record_pic_fputs (fp, "node: {title: \"[END]\"}\n");
> +  snprintf (line, 256,
> +           "nearedge: {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.  */
> @@ -2730,4 +3211,60 @@ record/replay buffer.  Zero means unlimi
>  Restore the program to its state at instruction number N.\n\
>  Argument is instruction number, as shown by 'info record'."),
>            &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 record pic command saved file."), _("\
> +Show the type of record pic command saved file."), _("\
> +When LINE, show each line of the inferior.\n\
> +When FUNCTION, just show the each function."),
> +                       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 node that don't have function
> name."), _("\
> +Show whether record pic command hide the node that don't have
> function name."), _("\
> +Default is ON.\n\
> +When ON, record pic command will hide the node that don't have\n\
> +function name.\n\
> +When OFF, record pic command will show the node that don't have\n\
> +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 node that don't have source
> message."), _("\
> +Show whether record pic command hide the node that don't have source
> message."), _("\
> +Default is ON.\n\
> +When ON, record pic command will hide the node that don't have\n\
> +function name.\n\
> +When OFF, record pic command will show the node that don't have\n\
> +function name."),
> +                          NULL, NULL,
> +                          &set_record_pic_cmdlist, &show_record_pic_cmdlist);
> +  add_setshow_boolean_cmd ("hide-same", no_class,
> +                          &record_pic_hide_same, _("\
> +Set whether record pic command hide the node that was shown in before."), _("\
> +Show whether record pic command hide the node that was shown in before."), _("\
> +Default is ON.\n\
> +When ON, record pic command will hide the node that was shown in before.\n\
> +It will show the execute count number of this line in format \"c:number\".\n\
> +When OFF, record pic command will show the node that was shown in before.\n\
> +It will show the instruction number in format \"i:number\"\n\
> +that \"record goto\" support."),
> +                          NULL, NULL,
> +                          &set_record_pic_cmdlist, &show_record_pic_cmdlist);
>  }
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] record.c: make prec can save the execution log to a pic  file
  2010-06-16  0:42 ` Michael Snyder
@ 2010-06-16  4:46   ` Hui Zhu
  2010-06-16 13:51     ` Hui Zhu
  0 siblings, 1 reply; 11+ messages in thread
From: Hui Zhu @ 2010-06-16  4:46 UTC (permalink / raw)
  To: Michael Snyder; +Cc: gdb-patches ml

On Wed, Jun 16, 2010 at 08:42, Michael Snyder <msnyder@vmware.com> wrote:
> Hui Zhu wrote:
>>
>> Hi guys,
>>
>> Before you read my introduce about this feature, please see the pic
>> file in http://www.tuhigh.com/photo/p/1600958
>> This is a inferior execute log pic file.  The [BEGIN] and [END] is the
>> begin and the end this record.  The red line means call a function.
>> The blue line means function return.  The black line means simple
>> execute.
>> This pic is convented from vcg file to jpg file by graph-easy
>> (http://search.cpan.org/~tels/Graph-Easy/bin/graph-easy)
>> To see the vcg file directly.  I suggest you to use vcgviewer
>> (http://code.google.com/p/vcgviewer/).
>
> You really want to have gdb generate a graphics file?
>
> Seems like you could offload this task to a post-processor program,
> if you just save the record log file.  Then you could do anything
> you wanted to with the data, without having to add complexity and
> user commands to gdb.

It need a lot of frame message that get from gdb.  I don't think do it
with myself is very easy.

And vcg file is very speical. It's a text file.


Thanks,
Hui

>
>>
>> This patch add some new commands:
>> record pic
>> Save the execution log to a vcg file.
>>
>> set record pic type line/function
>> Set the type of record pic command saved file.
>> When LINE, show each line of the inferior.
>> When FUNCTION, just show the each function.
>>
>> set record hide-nofunction on/off
>> Set whether record pic command hide the node that don't have function
>> name.
>> Default is ON.
>> When ON, record pic command will hide the node that don't have function
>> name.
>> When OFF, record pic command will show the node that don't have function
>> name.
>>
>> set record hide-nosource on/off
>> Set whether record pic command hide the node that don't have source
>> message.
>> Default is ON.
>> When ON, record pic command will hide the node that don't have function
>> name.
>> When OFF, record pic command will show the node that don't have function
>> name.
>>
>> set record hide-same on/off
>> Set whether record pic command hide the node that was shown in before.
>> Default is ON.
>> When ON, record pic command will hide the node that was shown in before.
>> It will show the execute count number of this line in format \"c:number\".
>> When OFF, record pic command will show the node that was shown in before.
>> It will show the instruction number in format \"i:number\" that
>> \"record goto\" support.
>>
>> If this patch get approved.  I will post patch for doc and NEWS.
>>
>> Thanks,
>> Hui
>>
>> 2010-06-16  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.
>>        (node_list, edge_list): New struct.
>>        (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.
>>
>>
>> ---
>>  record.c |  537
>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 537 insertions(+)
>>
>> --- a/record.c
>> +++ b/record.c
>> @@ -2545,6 +2545,487 @@ cmd_record_save (char *args, int from_tt
>>                   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 node_list
>> +{
>> +  struct node_list *next;
>> +  int count;
>> +  CORE_ADDR addr;
>> +  int showall;
>> +  struct symtab *symtab;
>> +  int line;
>> +  struct minimal_symbol *function;
>> +};
>> +struct edge_list
>> +{
>> +  struct edge_list *next;
>> +  int count;
>> +  struct node_list *s;
>> +  struct node_list *t;
>> +  int frame_diff;
>> +  int is_return;
>> +};
>> +struct node_list *node_list = NULL;
>> +struct edge_list *edge_list = NULL;
>> +
>> +static void
>> +record_pic_cleanups (void *data)
>> +{
>> +  FILE *fp = data;
>> +  struct node_list *nl, *nl2;
>> +  struct edge_list *el, *el2;
>> +
>> +  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,
>> +              "nearedge: {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 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;
>> +
>> +  /* 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]\"}\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_nlp_real.addr = 0;
>> +  prev_nlp = &prev_nlp_real;
>> +
>> +  /* 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;
>> +
>> +                  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;
>> +
>> +                  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\"}\n",
>> node);
>> +                      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\"}\n", node,
>> +                   nlp->count);
>> +          record_pic_fputs (fp, line);
>> +       }
>> +
>> +      record_pic_node (node, 256, gdbarch, set_record_pic_type,
>> edge_list->t);
>> +      snprintf (line, 256,
>> +               "nearedge: {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.  */
>> +  record_pic_fputs (fp, "node: {title: \"[END]\"}\n");
>> +  snprintf (line, 256,
>> +           "nearedge: {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.  */
>> @@ -2730,4 +3211,60 @@ record/replay buffer.  Zero means unlimi
>>  Restore the program to its state at instruction number N.\n\
>>  Argument is instruction number, as shown by 'info record'."),
>>           &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 record pic command saved file."), _("\
>> +Show the type of record pic command saved file."), _("\
>> +When LINE, show each line of the inferior.\n\
>> +When FUNCTION, just show the each function."),
>> +                       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 node that don't have function
>> name."), _("\
>> +Show whether record pic command hide the node that don't have
>> function name."), _("\
>> +Default is ON.\n\
>> +When ON, record pic command will hide the node that don't have\n\
>> +function name.\n\
>> +When OFF, record pic command will show the node that don't have\n\
>> +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 node that don't have source
>> message."), _("\
>> +Show whether record pic command hide the node that don't have source
>> message."), _("\
>> +Default is ON.\n\
>> +When ON, record pic command will hide the node that don't have\n\
>> +function name.\n\
>> +When OFF, record pic command will show the node that don't have\n\
>> +function name."),
>> +                          NULL, NULL,
>> +                          &set_record_pic_cmdlist,
>> &show_record_pic_cmdlist);
>> +  add_setshow_boolean_cmd ("hide-same", no_class,
>> +                          &record_pic_hide_same, _("\
>> +Set whether record pic command hide the node that was shown in before."),
>> _("\
>> +Show whether record pic command hide the node that was shown in
>> before."), _("\
>> +Default is ON.\n\
>> +When ON, record pic command will hide the node that was shown in
>> before.\n\
>> +It will show the execute count number of this line in format
>> \"c:number\".\n\
>> +When OFF, record pic command will show the node that was shown in
>> before.\n\
>> +It will show the instruction number in format \"i:number\"\n\
>> +that \"record goto\" support."),
>> +                          NULL, NULL,
>> +                          &set_record_pic_cmdlist,
>> &show_record_pic_cmdlist);
>>  }
>>
>
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] record.c: make prec can save the execution log to a pic  file
  2010-06-16  4:46   ` Hui Zhu
@ 2010-06-16 13:51     ` Hui Zhu
  2010-06-18  7:31       ` Hui Zhu
  0 siblings, 1 reply; 11+ messages in thread
From: Hui Zhu @ 2010-06-16 13:51 UTC (permalink / raw)
  To: Michael Snyder; +Cc: gdb-patches ml

On Wed, Jun 16, 2010 at 12:46, Hui Zhu <teawater@gmail.com> wrote:
> On Wed, Jun 16, 2010 at 08:42, Michael Snyder <msnyder@vmware.com> wrote:
>> Hui Zhu wrote:
>>>
>>> Hi guys,
>>>
>>> Before you read my introduce about this feature, please see the pic
>>> file in http://www.tuhigh.com/photo/p/1600958
>>> This is a inferior execute log pic file.  The [BEGIN] and [END] is the
>>> begin and the end this record.  The red line means call a function.
>>> The blue line means function return.  The black line means simple
>>> execute.
>>> This pic is convented from vcg file to jpg file by graph-easy
>>> (http://search.cpan.org/~tels/Graph-Easy/bin/graph-easy)
>>> To see the vcg file directly.  I suggest you to use vcgviewer
>>> (http://code.google.com/p/vcgviewer/).
>>
>> You really want to have gdb generate a graphics file?
>>
>> Seems like you could offload this task to a post-processor program,
>> if you just save the record log file.  Then you could do anything
>> you wanted to with the data, without having to add complexity and
>> user commands to gdb.
>
> It need a lot of frame message that get from gdb.  I don't think do it
> with myself is very easy.
>
> And vcg file is very speical. It's a text file.
>
>
> Thanks,
> Hui

And another issue is:  "record save" cannot work OK with some target,
because it need this target support gcore.
But "record pic" doesn't have this limit.  It can work OK with "target
remote" that "record save" cannot work with it.

Thanks,
Hui
>
>>
>>>
>>> This patch add some new commands:
>>> record pic
>>> Save the execution log to a vcg file.
>>>
>>> set record pic type line/function
>>> Set the type of record pic command saved file.
>>> When LINE, show each line of the inferior.
>>> When FUNCTION, just show the each function.
>>>
>>> set record hide-nofunction on/off
>>> Set whether record pic command hide the node that don't have function
>>> name.
>>> Default is ON.
>>> When ON, record pic command will hide the node that don't have function
>>> name.
>>> When OFF, record pic command will show the node that don't have function
>>> name.
>>>
>>> set record hide-nosource on/off
>>> Set whether record pic command hide the node that don't have source
>>> message.
>>> Default is ON.
>>> When ON, record pic command will hide the node that don't have function
>>> name.
>>> When OFF, record pic command will show the node that don't have function
>>> name.
>>>
>>> set record hide-same on/off
>>> Set whether record pic command hide the node that was shown in before.
>>> Default is ON.
>>> When ON, record pic command will hide the node that was shown in before.
>>> It will show the execute count number of this line in format \"c:number\".
>>> When OFF, record pic command will show the node that was shown in before.
>>> It will show the instruction number in format \"i:number\" that
>>> \"record goto\" support.
>>>
>>> If this patch get approved.  I will post patch for doc and NEWS.
>>>
>>> Thanks,
>>> Hui
>>>
>>> 2010-06-16  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.
>>>        (node_list, edge_list): New struct.
>>>        (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.
>>>
>>>
>>> ---
>>>  record.c |  537
>>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  1 file changed, 537 insertions(+)
>>>
>>> --- a/record.c
>>> +++ b/record.c
>>> @@ -2545,6 +2545,487 @@ cmd_record_save (char *args, int from_tt
>>>                   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 node_list
>>> +{
>>> +  struct node_list *next;
>>> +  int count;
>>> +  CORE_ADDR addr;
>>> +  int showall;
>>> +  struct symtab *symtab;
>>> +  int line;
>>> +  struct minimal_symbol *function;
>>> +};
>>> +struct edge_list
>>> +{
>>> +  struct edge_list *next;
>>> +  int count;
>>> +  struct node_list *s;
>>> +  struct node_list *t;
>>> +  int frame_diff;
>>> +  int is_return;
>>> +};
>>> +struct node_list *node_list = NULL;
>>> +struct edge_list *edge_list = NULL;
>>> +
>>> +static void
>>> +record_pic_cleanups (void *data)
>>> +{
>>> +  FILE *fp = data;
>>> +  struct node_list *nl, *nl2;
>>> +  struct edge_list *el, *el2;
>>> +
>>> +  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,
>>> +              "nearedge: {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 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;
>>> +
>>> +  /* 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]\"}\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_nlp_real.addr = 0;
>>> +  prev_nlp = &prev_nlp_real;
>>> +
>>> +  /* 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;
>>> +
>>> +                  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;
>>> +
>>> +                  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\"}\n",
>>> node);
>>> +                      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\"}\n", node,
>>> +                   nlp->count);
>>> +          record_pic_fputs (fp, line);
>>> +       }
>>> +
>>> +      record_pic_node (node, 256, gdbarch, set_record_pic_type,
>>> edge_list->t);
>>> +      snprintf (line, 256,
>>> +               "nearedge: {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.  */
>>> +  record_pic_fputs (fp, "node: {title: \"[END]\"}\n");
>>> +  snprintf (line, 256,
>>> +           "nearedge: {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.  */
>>> @@ -2730,4 +3211,60 @@ record/replay buffer.  Zero means unlimi
>>>  Restore the program to its state at instruction number N.\n\
>>>  Argument is instruction number, as shown by 'info record'."),
>>>           &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 record pic command saved file."), _("\
>>> +Show the type of record pic command saved file."), _("\
>>> +When LINE, show each line of the inferior.\n\
>>> +When FUNCTION, just show the each function."),
>>> +                       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 node that don't have function
>>> name."), _("\
>>> +Show whether record pic command hide the node that don't have
>>> function name."), _("\
>>> +Default is ON.\n\
>>> +When ON, record pic command will hide the node that don't have\n\
>>> +function name.\n\
>>> +When OFF, record pic command will show the node that don't have\n\
>>> +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 node that don't have source
>>> message."), _("\
>>> +Show whether record pic command hide the node that don't have source
>>> message."), _("\
>>> +Default is ON.\n\
>>> +When ON, record pic command will hide the node that don't have\n\
>>> +function name.\n\
>>> +When OFF, record pic command will show the node that don't have\n\
>>> +function name."),
>>> +                          NULL, NULL,
>>> +                          &set_record_pic_cmdlist,
>>> &show_record_pic_cmdlist);
>>> +  add_setshow_boolean_cmd ("hide-same", no_class,
>>> +                          &record_pic_hide_same, _("\
>>> +Set whether record pic command hide the node that was shown in before."),
>>> _("\
>>> +Show whether record pic command hide the node that was shown in
>>> before."), _("\
>>> +Default is ON.\n\
>>> +When ON, record pic command will hide the node that was shown in
>>> before.\n\
>>> +It will show the execute count number of this line in format
>>> \"c:number\".\n\
>>> +When OFF, record pic command will show the node that was shown in
>>> before.\n\
>>> +It will show the instruction number in format \"i:number\"\n\
>>> +that \"record goto\" support."),
>>> +                          NULL, NULL,
>>> +                          &set_record_pic_cmdlist,
>>> &show_record_pic_cmdlist);
>>>  }
>>>
>>
>>
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] record.c: make prec can save the execution log to a pic  file
  2010-06-16 13:51     ` Hui Zhu
@ 2010-06-18  7:31       ` Hui Zhu
  2010-06-22  2:17         ` Hui Zhu
  2010-06-25  6:22         ` Hui Zhu
  0 siblings, 2 replies; 11+ messages in thread
From: Hui Zhu @ 2010-06-18  7:31 UTC (permalink / raw)
  To: gdb-patches ml; +Cc: Michael Snyder

[-- Attachment #1: Type: text/plain, Size: 5485 bytes --]

This is the new patch that just did some small words change.

Following is a vcg file that got from record pic:

graph: {title: "GDB process record"
node: {title: "[BEGIN]"}
node: {title: "1.c:21 main 0x80483c1 c:1"}
node: {title: "main 22 0x80483c8 c:1"}
node: {title: "main 25 0x80483cf c:1"}
node: {title: "main 26 0x80483f3 c:2"}
node: {title: "1.c:9 cool 0x8048391 c:1"}
node: {title: "cool 10 0x8048397 c:1"}
node: {title: "cool 13 0x80483a4 c:1"}
node: {title: "1.c:4 cool2 0x8048374 c:1"}
node: {title: "cool2 5 0x804837a c:1"}
node: {title: "cool2 6 0x804838f c:1"}
node: {title: "1.c:15 cool 0x80483a9 c:1"}
node: {title: "cool 16 0x80483ae c:1"}
node: {title: "main 27 0x80483fb c:1"}
node: {title: "main 30 0x804841f c:1"}
node: {title: "main 31 0x8048423 c:1"}
node: {title: "main 32 0x8048447 c:1"}
node: {title: "main 33 0x8048454 c:1"}
node: {title: "main 34 0x8048478 c:1"}
node: {title: "main 35 0x804847d c:1"}
node: {title: "/build/buildd/glibc-2.7/build-tree/i386-libc/csu/crti.S:41
_fini 0x804852c c:1"}
node: {title: "_fini 42 0x804852d c:1"}
node: {title: "_fini 43 0x804852f c:1"}
node: {title: "_fini 44 0x8048530 c:1"}
node: {title: "_fini 45 0x8048533 c:1"}
node: {title: "_fini 47 0x8048538 c:1"}
node: {title: "_fini 48 0x8048539 c:1"}
node: {title: "_fini 21 0x8048544 c:1"}
node: {title: "_fini 22 0x8048545 c:1"}
node: {title: "_fini 23 0x8048546 c:1"}
node: {title: "_fini 24 0x8048547 c:1"}
nearedge: {color:red sourcename: "[BEGIN]" targetname: "1.c:21 main
0x80483c1 c:1"}
nearedge: {sourcename: "1.c:21 main 0x80483c1 c:1" targetname: "main
22 0x80483c8 c:1" label: "c:1"}
nearedge: {sourcename: "main 22 0x80483c8 c:1" targetname: "main 25
0x80483cf c:1" label: "c:1"}
nearedge: {sourcename: "main 25 0x80483cf c:1" targetname: "main 26
0x80483f3 c:2" label: "c:1"}
edge: {color:red sourcename: "main 26 0x80483f3 c:2" targetname:
"1.c:9 cool 0x8048391 c:1" label: "c:1"}
nearedge: {sourcename: "1.c:9 cool 0x8048391 c:1" targetname: "cool 10
0x8048397 c:1" label: "c:1"}
nearedge: {sourcename: "cool 10 0x8048397 c:1" targetname: "cool 13
0x80483a4 c:1" label: "c:1"}
edge: {color:red sourcename: "cool 13 0x80483a4 c:1" targetname:
"1.c:4 cool2 0x8048374 c:1" label: "c:1"}
nearedge: {sourcename: "1.c:4 cool2 0x8048374 c:1" targetname: "cool2
5 0x804837a c:1" label: "c:1"}
nearedge: {sourcename: "cool2 5 0x804837a c:1" targetname: "cool2 6
0x804838f c:1" label: "c:1"}
edge: {color:blue sourcename: "cool2 6 0x804838f c:1" targetname:
"1.c:15 cool 0x80483a9 c:1" label: "c:1"}
nearedge: {sourcename: "1.c:15 cool 0x80483a9 c:1" targetname: "cool
16 0x80483ae c:1" label: "c:1"}
edge: {color:blue sourcename: "cool 16 0x80483ae c:1" targetname:
"main 26 0x80483f3 c:2" label: "c:1"}
nearedge: {sourcename: "main 26 0x80483f3 c:2" targetname: "main 27
0x80483fb c:1" label: "c:1"}
nearedge: {sourcename: "main 27 0x80483fb c:1" targetname: "main 30
0x804841f c:1" label: "c:1"}
nearedge: {sourcename: "main 30 0x804841f c:1" targetname: "main 31
0x8048423 c:1" label: "c:1"}
nearedge: {sourcename: "main 31 0x8048423 c:1" targetname: "main 32
0x8048447 c:1" label: "c:1"}
nearedge: {sourcename: "main 32 0x8048447 c:1" targetname: "main 33
0x8048454 c:1" label: "c:1"}
nearedge: {sourcename: "main 33 0x8048454 c:1" targetname: "main 34
0x8048478 c:1" label: "c:1"}
nearedge: {sourcename: "main 34 0x8048478 c:1" targetname: "main 35
0x804847d c:1" label: "c:1"}
edge: {color:red sourcename: "main 35 0x804847d c:1" targetname:
"/build/buildd/glibc-2.7/build-tree/i386-libc/csu/crti.S:41 _fini
0x804852c c:1" label: "c:1"}
nearedge: {sourcename:
"/build/buildd/glibc-2.7/build-tree/i386-libc/csu/crti.S:41 _fini
0x804852c c:1" targetname: "_fini 42 0x804852d c:1" label: "c:1"}
nearedge: {sourcename: "_fini 42 0x804852d c:1" targetname: "_fini 43
0x804852f c:1" label: "c:1"}
nearedge: {sourcename: "_fini 43 0x804852f c:1" targetname: "_fini 44
0x8048530 c:1" label: "c:1"}
nearedge: {sourcename: "_fini 44 0x8048530 c:1" targetname: "_fini 45
0x8048533 c:1" label: "c:1"}
nearedge: {sourcename: "_fini 45 0x8048533 c:1" targetname: "_fini 47
0x8048538 c:1" label: "c:1"}
nearedge: {sourcename: "_fini 47 0x8048538 c:1" targetname: "_fini 48
0x8048539 c:1" label: "c:1"}
nearedge: {sourcename: "_fini 48 0x8048539 c:1" targetname: "_fini 21
0x8048544 c:1" label: "c:1"}
nearedge: {sourcename: "_fini 21 0x8048544 c:1" targetname: "_fini 22
0x8048545 c:1" label: "c:1"}
nearedge: {sourcename: "_fini 22 0x8048545 c:1" targetname: "_fini 23
0x8048546 c:1" label: "c:1"}
nearedge: {sourcename: "_fini 23 0x8048546 c:1" targetname: "_fini 24
0x8048547 c:1" label: "c:1"}
node: {title: "[END]"}
nearedge: {color:red sourcename: "_fini 23 0x8048546 c:1" targetname: "[END]" }
}


Thanks,
Hui

2010-06-18  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.
	(node_list, edge_list): New struct.
	(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-18  Hui Zhu  <teawater@gmail.com>

	* gdb.texinfo: (Process Record and Replay): Add documentation
	for command "record pic".

[-- Attachment #2: prec-pic.txt --]
[-- Type: text/plain, Size: 18284 bytes --]

---
 record.c |  542 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 542 insertions(+)

--- a/record.c
+++ b/record.c
@@ -2545,6 +2545,487 @@ cmd_record_save (char *args, int from_tt
 		   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 node_list
+{
+  struct node_list *next;
+  int count;
+  CORE_ADDR addr;
+  int showall;
+  struct symtab *symtab;
+  int line;
+  struct minimal_symbol *function;
+};
+struct edge_list
+{
+  struct edge_list *next;
+  int count;
+  struct node_list *s;
+  struct node_list *t;
+  int frame_diff;
+  int is_return;
+};
+struct node_list *node_list = NULL;
+struct edge_list *edge_list = NULL;
+
+static void
+record_pic_cleanups (void *data)
+{
+  FILE *fp = data;
+  struct node_list *nl, *nl2;
+  struct edge_list *el, *el2;
+
+  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,
+              "nearedge: {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 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;
+
+  /* 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]\"}\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_nlp_real.addr = 0;
+  prev_nlp = &prev_nlp_real;
+
+  /* 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;
+
+                  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;
+
+                  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\"}\n", node);
+                      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\"}\n", node,
+		    nlp->count);
+          record_pic_fputs (fp, line);
+	}
+
+      record_pic_node (node, 256, gdbarch, set_record_pic_type, edge_list->t);
+      snprintf (line, 256,
+	        "nearedge: {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.  */
+  record_pic_fputs (fp, "node: {title: \"[END]\"}\n");
+  snprintf (line, 256,
+	    "nearedge: {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.  */
@@ -2730,4 +3211,65 @@ record/replay buffer.  Zero means unlimi
 Restore the program to its state at instruction number N.\n\
 Argument is instruction number, as shown by 'info record'."),
 	   &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);
 }

[-- Attachment #3: prec-pic-doc.txt --]
[-- Type: text/plain, Size: 3517 bytes --]

---
 NEWS            |   18 ++++++++++++++++
 doc/gdb.texinfo |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

--- a/NEWS
+++ b/NEWS
@@ -84,6 +84,24 @@ qRelocInsn
 
 * New commands
 
+record pic [<FILENAME>]
+  Save the execution log to a vcg file.
+
+set record pic type line|function
+  Set or show the type of the nodes that `record pic' saved.
+
+set record pic hide-nofunction on|off
+  Set or show whether `record pic' hide the nodes that don't have
+  the function name.
+
+set record pic hide-nosource on|off
+  Set or show whether `record pic' hide the nodes that don't have
+  the source message.
+
+set record pic hide-sameaddr on|off
+  Set or show whether `record pic' hide the nodes that have the
+  same address node in vcg file.
+
 set target-file-system-kind unix|dos-based|auto
 show target-file-system-kind
   Set or show the assumed file system kind for target reported file
--- a/doc/gdb.texinfo
+++ b/doc/gdb.texinfo
@@ -5639,6 +5639,67 @@ usual ``live'' debugging of the process 
 When the inferior process exits, or @value{GDBN} detaches from it,
 process record and replay target will automatically stop itself.
 
+@kindex record pic
+@item record pic @var{filename}
+Save the execution log to a vcg file @file{@var{filename}}.
+Default filename is 'gdb_record_<process_id>.vcg'.
+
+@kindex set record pic type
+@item set record pic type @var{type}
+Set the type of the nodes that @code{record pic} saved.
+
+When @var{type} is set to @code{line} (the default), each node of vcg
+file that @code{record pic} saved will be a line of the inferior.
+
+When @var{type} is set to @code{function}, each node of vcg file that
+@code{record pic} saved will be a function of the inferior.
+
+@kindex show record pic type
+@item show record pic type
+Show the current setting of @code{pic type}.
+
+@kindex set record pic hide-nofunction
+@item set record pic hide-nofunction
+Set whether @code{record pic} hide the nodes that don't have
+the function name.
+
+If ON (the default), @code{record pic} will hide the nodes that don't
+have the function name.
+
+@kindex show record pic hide-nofunction
+@item show record pic hide-nofunction
+Show the current setting of @code{pic hide-nofunction}.
+
+@kindex set record pic hide-nosource
+@item set record pic hide-nosource
+Set whether @code{record pic} hide the nodes that don't have
+the source message.
+
+If ON (the default), @code{record pic} will hide the nodes that
+don't have the source message.
+
+@kindex show record pic hide-nosource
+@item show record pic hide-nosource
+Show the current setting of @code{pic hide-nosource}.
+
+@kindex set record pic hide-sameaddr
+@item set record pic hide-sameaddr
+Set whether @code{record pic} hide the nodes that have the same
+address node in vcg file.
+
+If ON (the default), @code{record pic} will hide the nodes that have
+the same address node in vcg file.  And @code{record pic} will show
+the execute count number of this node in format @code{c:number}
+
+If OFF, @code{record pic} will show the nodes that have the same
+address node in vcg file.  And @code{record pic} will show the
+instruction number in format @code{i:number} that
+@value{record goto} support.
+
+@kindex show record pic hide-same
+@item show record pic hide-same
+Show the current setting of @code{pic hide-same}.
+
 @kindex set record insn-number-max
 @item set record insn-number-max @var{limit}
 Set the limit of instructions to be recorded.  Default value is 200000.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] record.c: make prec can save the execution log to a pic  file
  2010-06-18  7:31       ` Hui Zhu
@ 2010-06-22  2:17         ` Hui Zhu
  2010-06-25  6:22         ` Hui Zhu
  1 sibling, 0 replies; 11+ messages in thread
From: Hui Zhu @ 2010-06-22  2:17 UTC (permalink / raw)
  To: gdb-patches ml; +Cc: Michael Snyder

Checked in.

On Fri, Jun 18, 2010 at 15:30, Hui Zhu <teawater@gmail.com> wrote:
> This is the new patch that just did some small words change.
>
> Following is a vcg file that got from record pic:
>
> graph: {title: "GDB process record"
> node: {title: "[BEGIN]"}
> node: {title: "1.c:21 main 0x80483c1 c:1"}
> node: {title: "main 22 0x80483c8 c:1"}
> node: {title: "main 25 0x80483cf c:1"}
> node: {title: "main 26 0x80483f3 c:2"}
> node: {title: "1.c:9 cool 0x8048391 c:1"}
> node: {title: "cool 10 0x8048397 c:1"}
> node: {title: "cool 13 0x80483a4 c:1"}
> node: {title: "1.c:4 cool2 0x8048374 c:1"}
> node: {title: "cool2 5 0x804837a c:1"}
> node: {title: "cool2 6 0x804838f c:1"}
> node: {title: "1.c:15 cool 0x80483a9 c:1"}
> node: {title: "cool 16 0x80483ae c:1"}
> node: {title: "main 27 0x80483fb c:1"}
> node: {title: "main 30 0x804841f c:1"}
> node: {title: "main 31 0x8048423 c:1"}
> node: {title: "main 32 0x8048447 c:1"}
> node: {title: "main 33 0x8048454 c:1"}
> node: {title: "main 34 0x8048478 c:1"}
> node: {title: "main 35 0x804847d c:1"}
> node: {title: "/build/buildd/glibc-2.7/build-tree/i386-libc/csu/crti.S:41
> _fini 0x804852c c:1"}
> node: {title: "_fini 42 0x804852d c:1"}
> node: {title: "_fini 43 0x804852f c:1"}
> node: {title: "_fini 44 0x8048530 c:1"}
> node: {title: "_fini 45 0x8048533 c:1"}
> node: {title: "_fini 47 0x8048538 c:1"}
> node: {title: "_fini 48 0x8048539 c:1"}
> node: {title: "_fini 21 0x8048544 c:1"}
> node: {title: "_fini 22 0x8048545 c:1"}
> node: {title: "_fini 23 0x8048546 c:1"}
> node: {title: "_fini 24 0x8048547 c:1"}
> nearedge: {color:red sourcename: "[BEGIN]" targetname: "1.c:21 main
> 0x80483c1 c:1"}
> nearedge: {sourcename: "1.c:21 main 0x80483c1 c:1" targetname: "main
> 22 0x80483c8 c:1" label: "c:1"}
> nearedge: {sourcename: "main 22 0x80483c8 c:1" targetname: "main 25
> 0x80483cf c:1" label: "c:1"}
> nearedge: {sourcename: "main 25 0x80483cf c:1" targetname: "main 26
> 0x80483f3 c:2" label: "c:1"}
> edge: {color:red sourcename: "main 26 0x80483f3 c:2" targetname:
> "1.c:9 cool 0x8048391 c:1" label: "c:1"}
> nearedge: {sourcename: "1.c:9 cool 0x8048391 c:1" targetname: "cool 10
> 0x8048397 c:1" label: "c:1"}
> nearedge: {sourcename: "cool 10 0x8048397 c:1" targetname: "cool 13
> 0x80483a4 c:1" label: "c:1"}
> edge: {color:red sourcename: "cool 13 0x80483a4 c:1" targetname:
> "1.c:4 cool2 0x8048374 c:1" label: "c:1"}
> nearedge: {sourcename: "1.c:4 cool2 0x8048374 c:1" targetname: "cool2
> 5 0x804837a c:1" label: "c:1"}
> nearedge: {sourcename: "cool2 5 0x804837a c:1" targetname: "cool2 6
> 0x804838f c:1" label: "c:1"}
> edge: {color:blue sourcename: "cool2 6 0x804838f c:1" targetname:
> "1.c:15 cool 0x80483a9 c:1" label: "c:1"}
> nearedge: {sourcename: "1.c:15 cool 0x80483a9 c:1" targetname: "cool
> 16 0x80483ae c:1" label: "c:1"}
> edge: {color:blue sourcename: "cool 16 0x80483ae c:1" targetname:
> "main 26 0x80483f3 c:2" label: "c:1"}
> nearedge: {sourcename: "main 26 0x80483f3 c:2" targetname: "main 27
> 0x80483fb c:1" label: "c:1"}
> nearedge: {sourcename: "main 27 0x80483fb c:1" targetname: "main 30
> 0x804841f c:1" label: "c:1"}
> nearedge: {sourcename: "main 30 0x804841f c:1" targetname: "main 31
> 0x8048423 c:1" label: "c:1"}
> nearedge: {sourcename: "main 31 0x8048423 c:1" targetname: "main 32
> 0x8048447 c:1" label: "c:1"}
> nearedge: {sourcename: "main 32 0x8048447 c:1" targetname: "main 33
> 0x8048454 c:1" label: "c:1"}
> nearedge: {sourcename: "main 33 0x8048454 c:1" targetname: "main 34
> 0x8048478 c:1" label: "c:1"}
> nearedge: {sourcename: "main 34 0x8048478 c:1" targetname: "main 35
> 0x804847d c:1" label: "c:1"}
> edge: {color:red sourcename: "main 35 0x804847d c:1" targetname:
> "/build/buildd/glibc-2.7/build-tree/i386-libc/csu/crti.S:41 _fini
> 0x804852c c:1" label: "c:1"}
> nearedge: {sourcename:
> "/build/buildd/glibc-2.7/build-tree/i386-libc/csu/crti.S:41 _fini
> 0x804852c c:1" targetname: "_fini 42 0x804852d c:1" label: "c:1"}
> nearedge: {sourcename: "_fini 42 0x804852d c:1" targetname: "_fini 43
> 0x804852f c:1" label: "c:1"}
> nearedge: {sourcename: "_fini 43 0x804852f c:1" targetname: "_fini 44
> 0x8048530 c:1" label: "c:1"}
> nearedge: {sourcename: "_fini 44 0x8048530 c:1" targetname: "_fini 45
> 0x8048533 c:1" label: "c:1"}
> nearedge: {sourcename: "_fini 45 0x8048533 c:1" targetname: "_fini 47
> 0x8048538 c:1" label: "c:1"}
> nearedge: {sourcename: "_fini 47 0x8048538 c:1" targetname: "_fini 48
> 0x8048539 c:1" label: "c:1"}
> nearedge: {sourcename: "_fini 48 0x8048539 c:1" targetname: "_fini 21
> 0x8048544 c:1" label: "c:1"}
> nearedge: {sourcename: "_fini 21 0x8048544 c:1" targetname: "_fini 22
> 0x8048545 c:1" label: "c:1"}
> nearedge: {sourcename: "_fini 22 0x8048545 c:1" targetname: "_fini 23
> 0x8048546 c:1" label: "c:1"}
> nearedge: {sourcename: "_fini 23 0x8048546 c:1" targetname: "_fini 24
> 0x8048547 c:1" label: "c:1"}
> node: {title: "[END]"}
> nearedge: {color:red sourcename: "_fini 23 0x8048546 c:1" targetname: "[END]" }
> }
>
>
> Thanks,
> Hui
>
> 2010-06-18  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.
>        (node_list, edge_list): New struct.
>        (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-18  Hui Zhu  <teawater@gmail.com>
>
>        * gdb.texinfo: (Process Record and Replay): Add documentation
>        for command "record pic".
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] record.c: make prec can save the execution log to a pic  file
  2010-06-18  7:31       ` Hui Zhu
  2010-06-22  2:17         ` Hui Zhu
@ 2010-06-25  6:22         ` Hui Zhu
  2010-09-02  1:04           ` Joel Brobecker
  1 sibling, 1 reply; 11+ messages in thread
From: Hui Zhu @ 2010-06-25  6:22 UTC (permalink / raw)
  To: gdb-patches ml

Update follow cvs-head and make the vcg file more better.

Thanks,
Hui

2010-06-25  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.

---
 record.c |  610 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 610 insertions(+)

--- a/record.c
+++ b/record.c
@@ -2549,6 +2549,555 @@ cmd_record_save (char *args, int from_tt
 		   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);
 }

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] record.c: make prec can save the execution log to a pic  file
  2010-06-25  6:22         ` Hui Zhu
@ 2010-09-02  1:04           ` Joel Brobecker
  2010-09-02  1:55             ` Michael Snyder
  2010-09-03  1:20             ` Joel Brobecker
  0 siblings, 2 replies; 11+ messages in thread
From: Joel Brobecker @ 2010-09-02  1:04 UTC (permalink / raw)
  To: Hui Zhu; +Cc: gdb-patches ml

Hui, Global Maintainers,

> 2010-06-25  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.

I recommend that this patch be backed out of the GDB sources, from
both the HEAD and the 7.2 branch, for the following reasons:

 (1) The implementation can be improved: Clearly document the new
     functions and types introduced by this patch, at a minimum.
     Unnecessary use of lablels and associated gotos, better error
     messages, confusing implementation...

 (2) But more importantly, I think that the contents of the graph,
     or rather the contents of each node in the graph being produced
     needs to be discussed and unified. For a short description of
     the contents of that graph:
     http://www.sourceware.org/ml/gdb-patches/2010-09/msg00070.html

     Just using one of Hui's example output, we see:

     | node: {title: "1.c:21 main 0x80483c1 c:1"}
     | node: {title: "main 22 0x80483c8 c:1"}
     | node: {title: "main 25 0x80483cf c:1"}

     In the first node, the line number is at the beginning of the
     title, together with the filename. In the second one, the line
     number is after.

 (3) Perhaps we might also want to discuss the actual commands
     that this patch introduces.

I don't see any of these issues as big issues, and I can live with
us keeping it. Reworking the syntax followed by the titles will cause
a user-visible change, but nothing considered incompatible. Cleaning
up the code can be done as followup patches. Changing the commands
themselves, however, would probably be a problem.  In terms of the
7.2 release which is being held up, I can produce the missing
documentation patch within a day or two.

However, I still believe that it is better to back it out for now.
First of all, I've already suggested that the code in record.c be
at least properly documented, but this never happened. Second of all,
I think that the current format used in the nodes titles is inconsistent
and makes the resulting graph less useful. What I believe we should do,
for this feature, is first go to the drawing board to describe precisely
what we want, and only then implement it.

-- 
Joel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] record.c: make prec can save the execution log to a pic  file
  2010-09-02  1:04           ` Joel Brobecker
@ 2010-09-02  1:55             ` Michael Snyder
  2010-09-02 13:12               ` Eli Zaretskii
  2010-09-03  1:20             ` Joel Brobecker
  1 sibling, 1 reply; 11+ messages in thread
From: Michael Snyder @ 2010-09-02  1:55 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Hui Zhu, gdb-patches ml

Joel Brobecker wrote:
> Hui, Global Maintainers,
> 
>> 2010-06-25  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.
> 
> I recommend that this patch be backed out of the GDB sources, from
> both the HEAD and the 7.2 branch, for the following reasons:
> 
>  (1) The implementation can be improved: Clearly document the new
>      functions and types introduced by this patch, at a minimum.
>      Unnecessary use of lablels and associated gotos, better error
>      messages, confusing implementation...
> 
>  (2) But more importantly, I think that the contents of the graph,
>      or rather the contents of each node in the graph being produced
>      needs to be discussed and unified. For a short description of
>      the contents of that graph:
>      http://www.sourceware.org/ml/gdb-patches/2010-09/msg00070.html
> 
>      Just using one of Hui's example output, we see:
> 
>      | node: {title: "1.c:21 main 0x80483c1 c:1"}
>      | node: {title: "main 22 0x80483c8 c:1"}
>      | node: {title: "main 25 0x80483cf c:1"}
> 
>      In the first node, the line number is at the beginning of the
>      title, together with the filename. In the second one, the line
>      number is after.
> 
>  (3) Perhaps we might also want to discuss the actual commands
>      that this patch introduces.
> 
> I don't see any of these issues as big issues, and I can live with
> us keeping it. Reworking the syntax followed by the titles will cause
> a user-visible change, but nothing considered incompatible. Cleaning
> up the code can be done as followup patches. Changing the commands
> themselves, however, would probably be a problem.  In terms of the
> 7.2 release which is being held up, I can produce the missing
> documentation patch within a day or two.
> 
> However, I still believe that it is better to back it out for now.
> First of all, I've already suggested that the code in record.c be
> at least properly documented, but this never happened. Second of all,
> I think that the current format used in the nodes titles is inconsistent
> and makes the resulting graph less useful. What I believe we should do,
> for this feature, is first go to the drawing board to describe precisely
> what we want, and only then implement it.

I agree.  It needs more discussion.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] record.c: make prec can save the execution log to a pic  file
  2010-09-02  1:55             ` Michael Snyder
@ 2010-09-02 13:12               ` Eli Zaretskii
  0 siblings, 0 replies; 11+ messages in thread
From: Eli Zaretskii @ 2010-09-02 13:12 UTC (permalink / raw)
  To: Michael Snyder; +Cc: brobecker, teawater, gdb-patches

> Date: Wed, 01 Sep 2010 16:19:21 -0700
> From: Michael Snyder <msnyder@vmware.com>
> CC: Hui Zhu <teawater@gmail.com>,  gdb-patches ml <gdb-patches@sourceware.org>
> > However, I still believe that it is better to back it out for now.
> > First of all, I've already suggested that the code in record.c be
> > at least properly documented, but this never happened. Second of all,
> > I think that the current format used in the nodes titles is inconsistent
> > and makes the resulting graph less useful. What I believe we should do,
> > for this feature, is first go to the drawing board to describe precisely
> > what we want, and only then implement it.
> 
> I agree.  It needs more discussion.

I will go with whatever you decide.  Given the clear description by
Joel of how it works (thanks!), I will be able to rewrite the manual
sections, after a few followup questions.  So if the decision is to
keep the patch, I can fix the docs quite quickly.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] record.c: make prec can save the execution log to a pic  file
  2010-09-02  1:04           ` Joel Brobecker
  2010-09-02  1:55             ` Michael Snyder
@ 2010-09-03  1:20             ` Joel Brobecker
  1 sibling, 0 replies; 11+ messages in thread
From: Joel Brobecker @ 2010-09-03  1:20 UTC (permalink / raw)
  To: Hui Zhu; +Cc: gdb-patches ml

> > 2010-06-25  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.

Based on the feedback, I have now reverted this patch, head and branch.

-- 
Joel

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2010-09-02 23:20 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-15 17:13 [PATCH] record.c: make prec can save the execution log to a pic file Hui Zhu
2010-06-16  0:42 ` Michael Snyder
2010-06-16  4:46   ` Hui Zhu
2010-06-16 13:51     ` Hui Zhu
2010-06-18  7:31       ` Hui Zhu
2010-06-22  2:17         ` Hui Zhu
2010-06-25  6:22         ` Hui Zhu
2010-09-02  1:04           ` Joel Brobecker
2010-09-02  1:55             ` Michael Snyder
2010-09-02 13:12               ` Eli Zaretskii
2010-09-03  1:20             ` Joel Brobecker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).