From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12691 invoked by alias); 14 Feb 2013 16:30:17 -0000 Received: (qmail 12622 invoked by uid 22791); 14 Feb 2013 16:30:15 -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 mga14.intel.com (HELO mga14.intel.com) (143.182.124.37) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 14 Feb 2013 16:30:04 +0000 Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga102.ch.intel.com with ESMTP; 14 Feb 2013 08:30:04 -0800 X-ExtLoop1: 1 Received: from swsutil001.isw.intel.com ([10.237.237.11]) by azsmga001.ch.intel.com with ESMTP; 14 Feb 2013 08:29:49 -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 r1EGTMYN019680; Thu, 14 Feb 2013 16:29:26 GMT Received: from ulslx001.iul.intel.com (localhost [127.0.0.1]) by ulslx001.iul.intel.com with ESMTP id r1EGTLUs030683; Thu, 14 Feb 2013 17:29:21 +0100 Received: (from mmetzger@localhost) by ulslx001.iul.intel.com with id r1EGTLnI030679; Thu, 14 Feb 2013 17:29:21 +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/8] record: add "record disassemble" command Date: Thu, 14 Feb 2013 16:30:00 -0000 Message-Id: <1360859352-30399-6-git-send-email-markus.t.metzger@intel.com> In-Reply-To: <1360859352-30399-1-git-send-email-markus.t.metzger@intel.com> References: <1360859352-30399-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/msg00353.txt.bz2 From: Markus Metzger Add a command to provide a disassembly of the execution trace log. Approved by Jan Kratochvil. 2013-02-14 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 abd8216..4f848ce 100644 --- a/gdb/record.c +++ b/gdb/record.c @@ -24,10 +24,17 @@ #include "observer.h" #include "inferior.h" #include "common/common-utils.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; @@ -289,6 +296,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; @@ -305,6 +433,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); @@ -346,4 +480,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 868ff63..3a03f69 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -4360,6 +4360,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 d416193..4100bb9 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 insn); + /* 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); /* See to_goto_record in struct target_ops. */ extern void target_goto_record (ULONGEST insn); +/* See to_disas_record. */ +extern void target_disas_record (int size, int flags); + +/* See to_disas_record_range. */ +extern void target_disas_record_range (ULONGEST begin, ULONGEST end, int flags); + #endif /* !defined (TARGET_H) */ -- 1.7.1