From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 497 invoked by alias); 16 Jun 2010 04:46:45 -0000 Received: (qmail 486 invoked by uid 22791); 16 Jun 2010 04:46:42 -0000 X-SWARE-Spam-Status: No, hits=-0.9 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,KAM_STOCKGEN,RCVD_IN_DNSWL_NONE,TW_CG,TW_CP,TW_EG,TW_VC X-Spam-Check-By: sourceware.org Received: from mail-pw0-f41.google.com (HELO mail-pw0-f41.google.com) (209.85.160.41) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 16 Jun 2010 04:46:35 +0000 Received: by pwi7 with SMTP id 7so8686138pwi.0 for ; Tue, 15 Jun 2010 21:46:34 -0700 (PDT) Received: by 10.142.151.5 with SMTP id y5mr6031273wfd.190.1276663594130; Tue, 15 Jun 2010 21:46:34 -0700 (PDT) MIME-Version: 1.0 Received: by 10.143.33.14 with HTTP; Tue, 15 Jun 2010 21:46:14 -0700 (PDT) In-Reply-To: <4C181DF2.7030604@vmware.com> References: <4C181DF2.7030604@vmware.com> From: Hui Zhu Date: Wed, 16 Jun 2010 04:46:00 -0000 Message-ID: Subject: Re: [PATCH] record.c: make prec can save the execution log to a pic file To: Michael Snyder Cc: gdb-patches ml Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-06/txt/msg00360.txt.bz2 On Wed, Jun 16, 2010 at 08:42, Michael Snyder 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. =A0The [BEGIN] and [END] is the >> begin and the end this record. =A0The red line means call a function. >> The blue line means function return. =A0The 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. =A0I 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. =A0Then 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. =A0I will post patch for doc and NEWS. >> >> Thanks, >> Hui >> >> 2010-06-16 =A0Hui Zhu =A0 >> >> =A0 =A0 =A0 =A0* record.c (set_record_pic_cmdlist, >> =A0 =A0 =A0 =A0show_record_pic_cmdlist): New variables. >> =A0 =A0 =A0 =A0(set_record_pic_command, >> =A0 =A0 =A0 =A0show_record_pic_command): New functions. >> =A0 =A0 =A0 =A0(record_pic_function, record_pic_line, record_pic_enum, >> =A0 =A0 =A0 =A0set_record_pic_type, record_pic_hide_nofunction, >> =A0 =A0 =A0 =A0record_pic_hide_nosource, record_pic_hide_same): New vari= ables. >> =A0 =A0 =A0 =A0(record_pic_fputs): New function. >> =A0 =A0 =A0 =A0(node_list, edge_list): New struct. >> =A0 =A0 =A0 =A0(node_list, edge_list): New variables. >> =A0 =A0 =A0 =A0(record_pic_cleanups, record_pic_node, >> =A0 =A0 =A0 =A0record_pic_edge, cmd_record_pic): New functions. >> =A0 =A0 =A0 =A0(_initialize_record): Add new commands for record pic. >> >> >> --- >> =A0record.c | =A0537 >> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> =A01 file changed, 537 insertions(+) >> >> --- a/record.c >> +++ b/record.c >> @@ -2545,6 +2545,487 @@ cmd_record_save (char *args, int from_tt >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 recfilename); >> =A0} >> >> +/* For "record pic" command. =A0*/ >> + >> +static struct cmd_list_element *set_record_pic_cmdlist, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *show_reco= rd_pic_cmdlist; >> + >> +static void >> +set_record_pic_command (char *args, int from_tty) >> +{ >> + =A0printf_unfiltered (_("\ >> +\"set record pic\" must be followed by an apporpriate subcommand.\n")); >> + =A0help_list (set_record_cmdlist, "set record pic ", all_commands, >> gdb_stdout); >> +} >> + >> +static void >> +show_record_pic_command (char *args, int from_tty) >> +{ >> + =A0cmd_show_list (show_record_pic_cmdlist, from_tty, ""); >> +} >> + >> +static const char record_pic_function[] =3D "function"; >> +static const char record_pic_line[] =3D "line"; >> +static const char *record_pic_enum[] =3D >> +{ >> + =A0record_pic_function, >> + =A0record_pic_line, >> + =A0NULL, >> +}; >> +static const char *set_record_pic_type =3D record_pic_line; >> + >> +static int record_pic_hide_nofunction =3D 1; >> +static int record_pic_hide_nosource =3D 1; >> +static int =A0record_pic_hide_same =3D 1; >> + >> +static void >> +record_pic_fputs (FILE *fp, const char *buf) >> +{ >> + =A0if (fputs (buf, fp) =3D=3D EOF) >> + =A0 =A0error (_("Write to file error.")); >> +} >> + >> +struct node_list >> +{ >> + =A0struct node_list *next; >> + =A0int count; >> + =A0CORE_ADDR addr; >> + =A0int showall; >> + =A0struct symtab *symtab; >> + =A0int line; >> + =A0struct minimal_symbol *function; >> +}; >> +struct edge_list >> +{ >> + =A0struct edge_list *next; >> + =A0int count; >> + =A0struct node_list *s; >> + =A0struct node_list *t; >> + =A0int frame_diff; >> + =A0int is_return; >> +}; >> +struct node_list *node_list =3D NULL; >> +struct edge_list *edge_list =3D NULL; >> + >> +static void >> +record_pic_cleanups (void *data) >> +{ >> + =A0FILE *fp =3D data; >> + =A0struct node_list *nl, *nl2; >> + =A0struct edge_list *el, *el2; >> + >> + =A0nl =3D node_list; >> + =A0while (nl) >> + =A0 =A0{ >> + =A0 =A0 =A0nl2 =3D nl; >> + =A0 =A0 =A0nl =3D nl->next; >> + =A0 =A0 =A0xfree (nl2); >> + =A0 =A0} >> + =A0node_list =3D NULL; >> + >> + =A0el =3D edge_list; >> + =A0while (el) >> + =A0 =A0{ >> + =A0 =A0 =A0el2 =3D el; >> + =A0 =A0 =A0el =3D el->next; >> + =A0 =A0 =A0xfree (el2); >> + =A0 =A0} >> + =A0edge_list =3D NULL; >> + >> + =A0fclose (fp); >> +} >> + >> +static void >> +record_pic_node (char *buf, int buf_max, struct gdbarch *gdbarch, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 const char *type, struct node_list *nl= p) >> +{ >> + =A0if (type =3D=3D record_pic_function) >> + =A0 =A0{ >> + =A0 =A0 =A0snprintf (buf, buf_max, "%s %s %s", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 (nlp->symtab) ? nlp->symtab->filename : "", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(nlp->function) ? SYMBOL_LINKAGE_NAME (= nlp->function) : >> "", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(!nlp->function) ? paddress (gdbarch, n= lp->addr) : ""); >> + =A0 =A0} >> + =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0if (nlp->showall) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 snprintf (buf, buf_max, "%s:%d %s %s", nlp->symtab->fi= lename, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nlp->line, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(nlp->function) ? SYMBOL_LINKAG= E_NAME (nlp->function) >> : "", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0paddress (gdbarch, nlp->addr)); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0if (nlp->symtab) >> + =A0 =A0 =A0 =A0 =A0 snprintf (buf, buf_max, "%s %d %s", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(nlp->function) ? SYMBOL_LI= NKAGE_NAME >> (nlp->function) : "", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nlp->line, paddress (gdbarc= h, nlp->addr)); >> + =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0snprintf (buf, buf_max, "%s %s", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(nlp->function) ? SYMBOL_LI= NKAGE_NAME >> (nlp->function) : "", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0paddress (gdbarch, nlp->add= r)); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> +} >> + >> +static void >> +record_pic_edge (char *buf, int buf_max, struct edge_list *elp, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0char *node, char *prev_node) >> +{ >> + =A0if (elp->frame_diff) >> + =A0 =A0{ >> + =A0 =A0 =A0if (elp->is_return) >> + =A0 =A0 =A0 =A0snprintf (buf, buf_max, "edge: {color:blue sourcename: = \"%s\" " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"target= name: \"%s\"", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 prev_node, node); >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0snprintf (buf, buf_max, "edge: {color:red sourcename: \= "%s\" " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"target= name: \"%s\"", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 prev_node, node); >> + =A0 =A0} >> + =A0else >> + =A0 =A0snprintf (buf, buf_max, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0"nearedge: {sourcename: \"%s\" targetname: = \"%s\"", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0prev_node, node); >> +} >> + >> +/* Save the execution log to a vcg file. =A0*/ >> + >> +static void >> +cmd_record_pic (char *args, int from_tty) >> +{ >> + =A0char *recfilename, recfilename_buffer[40]; >> + =A0FILE *fp; >> + =A0struct cleanup *old_cleanups, *set_cleanups; >> + =A0struct regcache *regcache; >> + =A0struct gdbarch *gdbarch; >> + =A0struct record_entry *cur_record_list; >> + =A0char prev_node[256], line[256]; >> + =A0CORE_ADDR prev_addr; >> + =A0struct frame_id fi, caller_fi, prev_fi, prev_caller_fi; >> + =A0struct edge_list *edge_list_tail =3D NULL; >> + =A0struct node_list *node_list_tail =3D NULL; >> + =A0struct symtab_and_line sal, prev_sal; >> + =A0struct node_list *prev_nlp; >> + =A0struct node_list prev_nlp_real; >> + >> + =A0/* Check if record target is running. =A0*/ >> + =A0if (current_target.to_stratum !=3D record_stratum) >> + =A0 =A0error (_("This command can only be used with target 'record' \ >> +or target 'record-core'.")); >> + >> + =A0if (args && *args) >> + =A0 =A0recfilename =3D args; >> + =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0/* Default recfile name is "gdb_record_PID.vcg". =A0*/ >> + =A0 =A0 =A0snprintf (recfilename_buffer, sizeof (recfilename_buffer), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"gdb_record_%d.vcg", PIDGET (inferior_p= tid)); >> + =A0 =A0 =A0recfilename =3D recfilename_buffer; >> + =A0 =A0} >> + >> + =A0/* Open the output file. =A0*/ >> + =A0fp =3D fopen (recfilename, "wb"); >> + =A0if (!fp) >> + =A0 =A0error (_("Unable to open file '%s'"), recfilename); >> + >> + =A0old_cleanups =3D make_cleanup (record_pic_cleanups, fp); >> + >> + =A0/* Save the current record entry to "cur_record_list". =A0*/ >> + =A0cur_record_list =3D record_list; >> + >> + =A0/* Get the values of regcache and gdbarch. =A0*/ >> + =A0regcache =3D get_current_regcache (); >> + =A0gdbarch =3D get_regcache_arch (regcache); >> + >> + =A0/* Disable the GDB operation record. =A0*/ >> + =A0set_cleanups =3D record_gdb_operation_disable_set (); >> + >> + =A0/* Reverse execute to the begin of record list. =A0*/ >> + =A0while (1) >> + =A0 =A0{ >> + =A0 =A0 =A0/* Check for beginning and end of log. =A0*/ >> + =A0 =A0 =A0if (record_list =3D=3D &record_first) >> + =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0record_exec_insn (regcache, gdbarch, record_list); >> + >> + =A0 =A0 =A0if (record_list->prev) >> + =A0 =A0 =A0 =A0record_list =3D record_list->prev; >> + =A0 =A0} >> + >> + =A0/* Write out the record log. =A0*/ >> + =A0/* Write the head. =A0*/ >> + =A0record_pic_fputs (fp, "graph: {title: \"GDB process record\"\n"); >> + >> + =A0/* Write the first node. =A0*/ >> + =A0record_pic_fputs (fp, "node: {title: \"[BEGIN]\"}\n"); >> + >> + =A0/* Initialization. =A0*/ >> + =A0snprintf (prev_node, 256, "[BEGIN]"); >> + =A0prev_fi =3D null_frame_id; >> + =A0prev_caller_fi =3D null_frame_id; >> + =A0prev_addr =3D 0; >> + =A0prev_sal.symtab =3D NULL; >> + =A0prev_nlp_real.addr =3D 0; >> + =A0prev_nlp =3D &prev_nlp_real; >> + >> + =A0/* Save the entries to fp and forward execute to the end of >> + =A0 =A0 record list. =A0*/ >> + =A0record_list =3D &record_first; >> + =A0while (1) >> + =A0 =A0{ >> + =A0 =A0 =A0if (record_list->type =3D=3D record_end) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0int frame_diff =3D 0; >> + =A0 =A0 =A0 =A0 =A0CORE_ADDR addr =3D regcache_read_pc (regcache); >> + >> + =A0 =A0 =A0 =A0 =A0/* Check if the ADDR is stil in the same line with = the >> + =A0 =A0 =A0 =A0 =A0 =A0 prev cycle. =A0*/ >> + =A0 =A0 =A0 =A0 =A0if (prev_sal.symtab >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0&& addr >=3D prev_sal.pc && addr < prev_sal= .end) >> + =A0 =A0 =A0 =A0 =A0 =A0goto exec; >> + =A0 =A0 =A0 =A0 =A0sal =3D find_pc_line (addr, 0); >> + >> + =A0 =A0 =A0 =A0 =A0if (record_pic_hide_nosource && !sal.symtab) >> + =A0 =A0 =A0 =A0 =A0 =A0goto exec; >> + >> + =A0 =A0 =A0 =A0 =A0/* Check if the inferior is in same frame with prev= cycle. >> + =A0 =A0 =A0 =A0 =A0 =A0 Check both the current fi and caller fi becaus= e the last >> + =A0 =A0 =A0 =A0 =A0 =A0 addr of function is different with current fun= ction. =A0*/ >> + =A0 =A0 =A0 =A0 =A0reinit_frame_cache (); >> + =A0 =A0 =A0 =A0 =A0fi =3D get_frame_id (get_current_frame ()); >> + =A0 =A0 =A0 =A0 =A0caller_fi =3D frame_unwind_caller_id (get_current_f= rame ()); >> + =A0 =A0 =A0 =A0 =A0if (!frame_id_eq (prev_fi, fi) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0&& !frame_id_eq (prev_caller_fi, caller_fi)) >> + =A0 =A0 =A0 =A0 =A0 =A0frame_diff =3D 1; >> + >> + =A0 =A0 =A0 =A0 =A0if (set_record_pic_type =3D=3D record_pic_line || f= rame_diff) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0int is_return =3D 0; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0struct node_list *nlp =3D NULL; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0struct edge_list *elp =3D NULL; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0char node[256]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0struct minimal_symbol *function; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 /* Get the node addr. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (set_record_pic_type =3D=3D record_pic_f= unction) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Get the start addr of function. = =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0addr =3D get_pc_function_start (add= r); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (addr =3D=3D 0) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_pic_hide_nofunct= ion) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto exec; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0addr =3D regcache_read_pc (= regcache); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Get the start addr of line. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (sal.symtab) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0addr =3D sal.pc; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0function =3D lookup_minimal_symbol_by_pc (a= ddr); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (!function && record_pic_hide_nofunction) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto exec; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (frame_id_eq (fi, prev_caller_fi)) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0is_return =3D 1; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_pic_hide_same) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Check if addr in node_list. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0for (nlp =3D node_list; nlp; nlp = =3D nlp->next) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (nlp->addr =3D=3D addr) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!is_return >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 || set_record_= pic_type !=3D >> record_pic_function) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nlp->count ++; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Check if prev_addr and addr in e= dge_list. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (nlp) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0for (elp =3D edge_list; elp= ; elp =3D elp->next) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (elp->s->addr = =3D=3D prev_addr && >> elp->t->addr =3D=3D addr) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0elp->count = ++; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (!nlp) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct node_list nl; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nl.addr =3D addr; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (frame_diff && sal.symtab) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nl.showall =3D 1; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nl.showall =3D 0; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nl.symtab =3D sal.symtab; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nl.line =3D sal.line; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nl.function =3D function; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_pic_hide_same) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nlp =3D xmalloc (sizeof (st= ruct node_list)); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*nlp =3D nl; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nlp->count =3D 1; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Add node to node_list. = =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0nlp->next =3D NULL; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (node_list_tail) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0node_list_tail->next = =3D nlp; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (node_list =3D=3D NULL) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 node_list =3D nlp; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0node_list_tail =3D nlp; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Draw the node. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_pic_node (node, 256,= gdbarch, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 set_record_pic_type, &nl); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 snprintf (line, 256, "%s i:%s"= , node, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pulongest = (record_list->u.end.insn_num)); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 strcpy (node, line); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0snprintf (line, 256, "node:= {title: \"%s\"}\n", >> node); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_pic_fputs (fp, line); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (!elp) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct edge_list el; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0el.is_return =3D is_return; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0el.frame_diff =3D frame_diff; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_pic_hide_same) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0elp =3D xmalloc (sizeof (st= ruct edge_list)); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*elp =3D el; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 elp->s =3D prev_nlp; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0elp->t =3D nlp; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0elp->count =3D 1; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Add edge to edge_list. = =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0elp->next =3D NULL; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (edge_list_tail) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0edge_list_tail->next = =3D elp; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (edge_list =3D=3D NULL) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 edge_list =3D elp; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0edge_list_tail =3D elp; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Draw the edge. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_pic_edge (line, 256,= &el, node, prev_node); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_pic_fputs (fp, line); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_pic_fputs (fp, " }\n"); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_pic_hide_same) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0prev_nlp =3D nlp; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0snprintf (prev_node, 256, "%s", node); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0prev_addr =3D addr; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0prev_sal =3D sal; >> + =A0 =A0 =A0 =A0 =A0prev_fi =3D fi; >> + =A0 =A0 =A0 =A0 =A0prev_caller_fi =3D caller_fi; >> + =A0 =A0 =A0 =A0} >> + >> +exec: >> + =A0 =A0 =A0/* Execute entry. =A0*/ >> + =A0 =A0 =A0record_exec_insn (regcache, gdbarch, record_list); >> + >> + =A0 =A0 =A0if (record_list->next) >> + =A0 =A0 =A0 =A0record_list =3D record_list->next; >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0break; >> + =A0 =A0} >> + >> + =A0if (record_pic_hide_same) >> + =A0 =A0{ >> + =A0 =A0 =A0struct node_list *nlp =3D NULL; >> + =A0 =A0 =A0struct edge_list *elp =3D NULL; >> + =A0 =A0 =A0char node[256]; >> + >> + =A0 =A0 =A0for (nlp =3D node_list; nlp; nlp =3D nlp->next) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0/* Draw the node. =A0*/ >> + =A0 =A0 =A0 =A0 =A0record_pic_node (node, 256, gdbarch, set_record_pic= _type, nlp); >> + =A0 =A0 =A0 =A0 =A0snprintf (line, 256, "node: {title: \"%s c:%d\"}\n"= , node, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 nlp->count); >> + =A0 =A0 =A0 =A0 =A0record_pic_fputs (fp, line); >> + =A0 =A0 =A0 } >> + >> + =A0 =A0 =A0record_pic_node (node, 256, gdbarch, set_record_pic_type, >> edge_list->t); >> + =A0 =A0 =A0snprintf (line, 256, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 "nearedge: {color:red sourcename: \"[BEGIN= ]\" targetname: >> \"%s c:%d\"}\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 node, edge_list->count); >> + =A0 =A0 =A0record_pic_fputs (fp, line); >> + =A0 =A0 =A0for (elp =3D edge_list->next; elp; elp =3D elp->next) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0/* Draw the edge. =A0*/ >> + =A0 =A0 =A0 =A0 record_pic_node (prev_node, 256, gdbarch, set_record_p= ic_type, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0elp->s); >> + =A0 =A0 =A0 =A0 snprintf (line, 256, "%s c:%d", prev_node, elp->s->cou= nt); >> + =A0 =A0 =A0 =A0 strcpy (prev_node, line); >> + =A0 =A0 =A0 =A0 record_pic_node (node, 256, gdbarch, set_record_pic_ty= pe, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0elp->t); >> + =A0 =A0 =A0 =A0 snprintf (line, 256, "%s c:%d", node, elp->t->count); >> + =A0 =A0 =A0 =A0 strcpy (node, line); >> + =A0 =A0 =A0 =A0 =A0record_pic_edge (line, 256, elp, node, prev_node); >> + =A0 =A0 =A0 =A0 =A0record_pic_fputs (fp, line); >> + =A0 =A0 =A0 =A0 =A0snprintf (line, 256, " label: \"c:%d\"}\n", elp->co= unt); >> + =A0 =A0 =A0 =A0 record_pic_fputs (fp, line); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + =A0/* Write the last node. =A0*/ >> + =A0record_pic_fputs (fp, "node: {title: \"[END]\"}\n"); >> + =A0snprintf (line, 256, >> + =A0 =A0 =A0 =A0 =A0 "nearedge: {color:red sourcename: \"%s\" targetnam= e: \"[END]\" >> }\n", >> + =A0 =A0 =A0 =A0 =A0 prev_node); >> + =A0record_pic_fputs (fp, line); >> + >> + =A0/* Write the tail. =A0*/ >> + =A0record_pic_fputs (fp, "}\n"); >> + >> + =A0/* Reverse execute to cur_record_list. =A0*/ >> + =A0while (1) >> + =A0 =A0{ >> + =A0 =A0 =A0/* Check for beginning and end of log. =A0*/ >> + =A0 =A0 =A0if (record_list =3D=3D cur_record_list) >> + =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0record_exec_insn (regcache, gdbarch, record_list); >> + >> + =A0 =A0 =A0if (record_list->prev) >> + =A0 =A0 =A0 =A0record_list =3D record_list->prev; >> + =A0 =A0} >> + >> + =A0do_cleanups (set_cleanups); >> + =A0do_cleanups (old_cleanups); >> + >> + =A0/* Succeeded. =A0*/ >> + =A0printf_filtered (_("Saved file %s with execution log.\n"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0recfilename); >> +} >> + >> =A0/* record_goto_insn -- rewind the record log (forward or backward, >> =A0 =A0depending on DIR) to the given entry, changing the program state >> =A0 =A0correspondingly. =A0*/ >> @@ -2730,4 +3211,60 @@ record/replay buffer. =A0Zero means unlimi >> =A0Restore the program to its state at instruction number N.\n\ >> =A0Argument is instruction number, as shown by 'info record'."), >> =A0 =A0 =A0 =A0 =A0 &record_cmdlist); >> + >> + =A0/* For "record pic" command. =A0*/ >> + =A0c =3D add_cmd ("pic", class_obscure, cmd_record_pic, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Save the execution log to a vcg file.\n\ >> +Argument is optional filename.\n\ >> +Default filename is 'gdb_record_.vcg'."), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0&record_cmdlist); >> + =A0set_cmd_completer (c, filename_completer); >> + =A0add_prefix_cmd ("pic", class_support, set_record_pic_command, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set record pic options"), &set_reco= rd_pic_cmdlist, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "set record pic ", 0, &set_record_cmdl= ist); >> + =A0add_prefix_cmd ("pic", class_support, show_record_pic_command, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Show record pic options"), &show_re= cord_pic_cmdlist, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "show record pic ", 0, &show_record_cm= dlist); >> + =A0add_setshow_enum_cmd ("type", no_class, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_pic_enum, &set_reco= rd_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."), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NULL, NULL, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &set_record_pic_cmdlist, >> &show_record_pic_cmdlist); >> + =A0add_setshow_boolean_cmd ("hide-nofunction", no_class, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&record_pic_hide_no= function, _("\ >> +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."), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0NULL, NULL, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&set_record_pic_cmd= list, >> &show_record_pic_cmdlist); >> + =A0add_setshow_boolean_cmd ("hide-nosource", no_class, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&record_pic_hide_no= source, _("\ >> +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."), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0NULL, NULL, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&set_record_pic_cmd= list, >> &show_record_pic_cmdlist); >> + =A0add_setshow_boolean_cmd ("hide-same", no_class, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&record_pic_hide_sa= me, _("\ >> +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."), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0NULL, NULL, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&set_record_pic_cmd= list, >> &show_record_pic_cmdlist); >> =A0} >> > >