From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4820 invoked by alias); 8 Feb 2013 15:30:54 -0000 Received: (qmail 4774 invoked by uid 22791); 8 Feb 2013 15:30:52 -0000 X-SWARE-Spam-Status: No, hits=-7.7 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,KHOP_SPAMHAUS_DROP,KHOP_THREADED,RCVD_IN_DNSWL_HI,RCVD_IN_HOSTKARMA_W,RP_MATCHES_RCVD,TW_EG X-Spam-Check-By: sourceware.org Received: from mga11.intel.com (HELO mga11.intel.com) (192.55.52.93) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 08 Feb 2013 15:30:42 +0000 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 08 Feb 2013 07:30:41 -0800 X-ExtLoop1: 1 Received: from swsutil001.isw.intel.com ([10.237.237.11]) by fmsmga002.fm.intel.com with ESMTP; 08 Feb 2013 07:30:39 -0800 Received: from ulslx001.iul.intel.com (ulslx001.iul.intel.com [172.28.207.63]) by swsutil001.isw.intel.com (8.13.6/8.13.6/MailSET/Hub) with ESMTP id r18FUc7G002913; Fri, 8 Feb 2013 15:30:38 GMT Received: from ulslx001.iul.intel.com (localhost [127.0.0.1]) by ulslx001.iul.intel.com with ESMTP id r18FUbmU027160; Fri, 8 Feb 2013 16:30:37 +0100 Received: (from mmetzger@localhost) by ulslx001.iul.intel.com with id r18FUbdg027156; Fri, 8 Feb 2013 16:30:37 +0100 From: markus.t.metzger@intel.com To: jan.kratochvil@redhat.com Cc: gdb-patches@sourceware.org, markus.t.metzger@gmail.com, Markus Metzger Subject: [rfc 5/5] record, disas: add record disassemble command Date: Fri, 08 Feb 2013 15:30:00 -0000 Message-Id: <1360337423-27095-6-git-send-email-markus.t.metzger@intel.com> In-Reply-To: <1360337423-27095-1-git-send-email-markus.t.metzger@intel.com> References: <1360337423-27095-1-git-send-email-markus.t.metzger@intel.com> 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: 2013-02/txt/msg00214.txt.bz2 From: Markus Metzger Add a command to provide a disassembly of the execution trace log. 2013-02-08 Markus Metzger * target.h (target_ops): Add to_disas_record and to_disas_record_range fields. (target_disas_record): New. (target_disas_record_range): New. * target.c (target_disas_record): New. (target_disas_record_range): New. * record.c: Include cli/cli-utils.h, disasm.h, ctype.h. (record_disas_size): New. (get_insn_number): New. (get_disas_modifiers): New. (cmd_record_disas): New. (_initialize_record): Add "set/show record disas-size" command. Add "record disassemble" command. --- gdb/record.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/target.c | 34 +++++++++++++ gdb/target.h | 12 +++++ 3 files changed, 196 insertions(+), 0 deletions(-) diff --git a/gdb/record.c b/gdb/record.c index 7f26b41..e081110 100644 --- a/gdb/record.c +++ b/gdb/record.c @@ -23,10 +23,17 @@ #include "record.h" #include "observer.h" #include "inferior.h" +#include "cli/cli-utils.h" +#include "disasm.h" + +#include /* This is the debug switch for process record. */ unsigned int record_debug = 0; +/* The number of instructions to disassemble in "record disas". */ +static unsigned int record_disas_size = 10; + struct cmd_list_element *record_cmdlist = NULL; struct cmd_list_element *set_record_cmdlist = NULL; struct cmd_list_element *show_record_cmdlist = NULL; @@ -271,6 +278,127 @@ cmd_record_goto (char *arg, int from_tty) } } +/* Read an instruction number from an argument string. */ + +static ULONGEST +get_insn_number (char **arg) +{ + ULONGEST number; + const char *begin, *end, *pos; + + begin = *arg; + pos = skip_spaces_const (begin); + + if (!isdigit (*pos)) + error (_("Expected positive number, got: %s."), pos); + + number = strtoulst (pos, &end, 10); + + *arg += (end - begin); + + return number; +} + +/* Read disassembly modifiers from an argument string. */ + +static int +get_disas_modifiers (char **arg) +{ + int modifiers; + char *args; + + modifiers = 0; + args = *arg; + + if (args == NULL) + return 0; + + while (*args == '/') + { + ++args; + + if (*args == '\0') + error (_("Missing modifier.")); + + for (; *args; ++args) + { + if (isspace (*args)) + break; + + if (*args == '/') + continue; + + switch (*args) + { + case 'm': + modifiers |= DISASSEMBLY_SOURCE; + modifiers |= DISASSEMBLY_FILENAME; + break; + case 'r': + modifiers |= DISASSEMBLY_RAW_INSN; + break; + default: + error (_("Invalid modifier: %c."), *args); + } + } + + args = skip_spaces (args); + } + + /* Update the argument string. */ + *arg = args; + + return modifiers; +} + +/* The "record disassemble" command. */ + +static void +cmd_record_disas (char *arg, int from_tty) +{ + int flags; + + require_record_target (); + + flags = get_disas_modifiers (&arg); + + if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) + target_disas_record ((int) record_disas_size, flags); + else if (strcmp (arg, "-") == 0) + target_disas_record (- (int) record_disas_size, flags); + else + { + ULONGEST begin, end; + + begin = get_insn_number (&arg); + + if (*arg == ',') + { + ++arg; + end = get_insn_number (&arg); + } + else + { + ULONGEST before; + + /* If the execution log does not start at zero, we might not + disassemble the entire record_disas_size instructions. */ + + before = record_disas_size / 2; + if (begin < before) + before = begin; + + begin -= before; + end = begin + record_disas_size; + } + + if (*arg != 0) + error (_("Junk after argument: %s."), arg); + + target_disas_record_range (begin, end, flags); + } +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_record; @@ -287,6 +415,12 @@ _initialize_record (void) NULL, show_record_debug, &setdebuglist, &showdebuglist); + add_setshow_uinteger_cmd ("disas-size", no_class, &record_disas_size, _("\ +Set number of instructions to print in \"record disassemble\"."), _("\ +Show number of instructions to print in \"record disassemble\"."), + NULL, NULL, NULL, &set_record_cmdlist, + &show_record_cmdlist); + c = add_prefix_cmd ("record", class_obscure, cmd_record_start, _("Start recording."), &record_cmdlist, "record ", 0, &cmdlist); @@ -328,4 +462,20 @@ Default filename is 'gdb_record.'."), Restore the program to its state at instruction number N.\n\ Argument is instruction number, as shown by 'info record'."), &record_cmdlist); + + add_cmd ("disassemble", class_obscure, cmd_record_disas, _("\ +Disassemble a section of the execution log.\n\ +With a /m modifier, source lines are included (if available).\n\ +With a /r modifier, raw instructions in hex are included.\n\ +With no argument, disassembles ten more instructions after or around the \ +previous disassembly.\n\ +\"disassemble -\" disassembles ten instructions before a previous ten-line \ +disassembly.\n\ +One argument specifies an instruction, and ten instructions are disassembled \ +around that instruction.\n\ +Two arguments with comma between specify starting and ending instructions to \ +disassemble.\n\ +The number of instructions to disassemble can be defined with \"set record \ +disas-size\"."), + &record_cmdlist); } diff --git a/gdb/target.c b/gdb/target.c index e71ab96..6b65ef5 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -4361,6 +4361,40 @@ target_goto_record (ULONGEST insn) tcomplain (); } +/* See target.h. */ + +void +target_disas_record (int size, int flags) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_disas_record != NULL) + { + t->to_disas_record (size, flags); + return; + } + + tcomplain (); +} + +/* See target.h. */ + +void +target_disas_record_range (ULONGEST begin, ULONGEST end, int flags) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_disas_record_range != NULL) + { + t->to_disas_record_range (begin, end, flags); + return; + } + + tcomplain (); +} + static void debug_to_prepare_to_store (struct regcache *regcache) { diff --git a/gdb/target.h b/gdb/target.h index e4fe5da..bf0d825 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -897,6 +897,12 @@ struct target_ops /* Go to a specific location in the recorded execution trace. */ void (*to_goto_record) (ULONGEST); + /* Disassemble the recorded execution trace. */ + void (*to_disas_record) (int size, int flags); + + /* Disassemble a section of the recorded execution trace. */ + void (*to_disas_record_range) (ULONGEST begin, ULONGEST end, int flags); + int to_magic; /* Need sub-structure for target machine related rather than comm related? */ @@ -1983,4 +1989,10 @@ extern void target_goto_record_end (void); /* Go to a specific location in the recorded execution trace. */ extern void target_goto_record (ULONGEST); +/* Disassemble the recorded execution trace. */ +extern void target_disas_record (int size, int flags); + +/* Disassemble a section of the recorded execution trace. */ +extern void target_disas_record_range (ULONGEST begin, ULONGEST end, int flags); + #endif /* !defined (TARGET_H) */ -- 1.7.0.7