From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12877 invoked by alias); 14 Feb 2013 16:30:24 -0000 Received: (qmail 12707 invoked by uid 22791); 14 Feb 2013 16:30:19 -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:00 +0000 Received: from azsmga002.ch.intel.com ([10.2.17.35]) by azsmga102.ch.intel.com with ESMTP; 14 Feb 2013 08:29:57 -0800 X-ExtLoop1: 1 Received: from swsutil001.isw.intel.com ([10.237.237.11]) by AZSMGA002.ch.intel.com with ESMTP; 14 Feb 2013 08:29:55 -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 r1EGTMQj019682; 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 r1EGTMx9030697; Thu, 14 Feb 2013 17:29:22 +0100 Received: (from mmetzger@localhost) by ulslx001.iul.intel.com with id r1EGTLrP030693; 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 7/8] record: add "record backtrace" command Date: Thu, 14 Feb 2013 16:30:00 -0000 Message-Id: <1360859352-30399-8-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/msg00352.txt.bz2 From: Markus Metzger Add a "record backtrace" command to print a backtrace of recorded functions. The command supports iterating over the execution log similar to the "list" command. This command provides a quick high-level overview over the recorded execution log without having to reverse-step. 2013-02-14 Markus Metzger * target.c (target_backtrace_record): New. (target_backtrace_record_range): New. * target.h (target_ops) : New fields. (target_disas_record, target_disas_record_range): New declaration. * record.c (get_insn_range, get_backtrace_modifiers, cmd_record_backtrace, record_backtrace_size): New. (_initialize_record): Add the "record backtrace" command. Add an alias "record bt" to it. Add "set/show record backtrace-size" commands. * record.h (record_print_flag): New. --- gdb/record.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++------- gdb/record.h | 7 +++ gdb/target.c | 34 ++++++++++++++ gdb/target.h | 13 +++++ 4 files changed, 181 insertions(+), 18 deletions(-) diff --git a/gdb/record.c b/gdb/record.c index 3ac4765..925e4c1 100644 --- a/gdb/record.c +++ b/gdb/record.c @@ -35,6 +35,9 @@ unsigned int record_debug = 0; /* The number of instructions to disassemble in "record disas". */ static unsigned int record_disas_size = 10; +/* The number of functions to print in "record backtrace". */ +static unsigned int record_backtrace_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; @@ -317,6 +320,42 @@ get_insn_number (char **arg) return number; } +/* Read an instruction range from an argument string. */ + +static void +get_insn_range (char **arg, unsigned int context, + ULONGEST *pbegin, ULONGEST *pend) +{ + ULONGEST begin, end; + + begin = get_insn_number (arg); + + if (**arg == ',') + { + *arg += 1; + end = get_insn_number (arg); + } + else + { + ULONGEST before; + + /* If the execution log does not start at zero, we might not + cover the entire context. */ + before = context / 2; + if (begin < before) + before = begin; + + begin -= before; + end = begin + context; + } + + if (**arg != 0) + error (_("Junk after argument: %s."), *arg); + + *pbegin = begin; + *pend = end; +} + /* Read disassembly modifiers from an argument string. */ static int @@ -396,32 +435,80 @@ cmd_record_disas (char *arg, int from_tty) { ULONGEST begin, end; - begin = get_insn_number (&arg); + get_insn_range (&arg, record_disas_size, &begin, &end); + target_disas_record_range (begin, end, flags); + } +} + +/* Read backtrace modifiers from an argument string. */ + +static int +get_backtrace_modifiers (char **arg) +{ + int modifiers; + char *args; + + modifiers = 0; + args = *arg; + + if (args == NULL) + return modifiers; + + while (*args == '/') + { + ++args; - if (*arg == ',') + if (*args == '\0') + error (_("Missing modifier.")); + + for (; *args; ++args) { - ++arg; - end = get_insn_number (&arg); + if (isspace (*args)) + break; + + if (*args == '/') + continue; + + switch (*args) + { + case 'l': + modifiers |= record_print_src_line; + break; + default: + error (_("Invalid modifier: %c."), *args); + } } - else - { - ULONGEST before; - /* If the execution log does not start at zero, we might not - disassemble the entire record_disas_size instructions. */ + args = skip_spaces (args); + } - before = record_disas_size / 2; - if (begin < before) - before = begin; + /* Update the argument string. */ + *arg = args; - begin -= before; - end = begin + record_disas_size; - } + return modifiers; +} - if (*arg != 0) - error (_("Junk after argument: %s."), arg); +/* The "record backtrace" command. */ - target_disas_record_range (begin, end, flags); +static void +cmd_record_backtrace (char *arg, int from_tty) +{ + int flags; + + require_record_target (); + + flags = get_backtrace_modifiers (&arg); + + if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) + target_backtrace_record ((int) record_backtrace_size, flags); + else if (strcmp (arg, "-") == 0) + target_backtrace_record (- (int) record_backtrace_size, flags); + else + { + ULONGEST begin, end; + + get_insn_range (&arg, record_backtrace_size, &begin, &end); + target_backtrace_record_range (begin, end, flags); } } @@ -447,6 +534,13 @@ Show number of instructions to print in \"record disassemble\"."), NULL, NULL, NULL, &set_record_cmdlist, &show_record_cmdlist); + add_setshow_uinteger_cmd ("backtrace-size", no_class, + &record_backtrace_size, _("\ +Set number of function to print in \"record backtrace\"."), _("\ +Show number of functions to print in \"record backtrace\"."), + 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); @@ -505,4 +599,19 @@ disassemble.\n\ The number of instructions to disassemble can be defined with \"set record \ disas-size\"."), &record_cmdlist); + + add_cmd ("backtrace", class_obscure, cmd_record_backtrace, _("\ +Print a backtrace of recorded functions.\n\ +With a /l modifier, the source file and line number is included.\n\ +With no argument, prints ten more functions after or around the previous \ +backtrace.\n\ +\"backtrace -\" prints ten functions before a previous ten-line backtrace.\n\ +One argument specifies an instruction, and a ten function backtrace is \ +printed starting at that instruction.\n\ +Two arguments with comma between specify starting and ending instructions. \ +Prints all functions in this range.\n\ +The number of functions to print can be defined with \"set record \ +backtrace-size\"."), + &record_cmdlist); + add_alias_cmd ("bt", "backtrace", class_obscure, 1, &record_cmdlist); } diff --git a/gdb/record.h b/gdb/record.h index 04d6b4a..e9d4bcd 100644 --- a/gdb/record.h +++ b/gdb/record.h @@ -32,6 +32,13 @@ extern struct cmd_list_element *set_record_cmdlist; extern struct cmd_list_element *show_record_cmdlist; extern struct cmd_list_element *info_record_cmdlist; +/* A list of flags specifying what record target methods should print. */ +enum record_print_flag + { + /* Print the source file and line (if applicable). */ + record_print_src_line = (1 << 0) + }; + /* Wrapper for target_read_memory that prints a debug message if reading memory fails. */ extern int record_read_memory (struct gdbarch *gdbarch, diff --git a/gdb/target.c b/gdb/target.c index 3a03f69..940e6b8 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -4394,6 +4394,40 @@ target_disas_record_range (ULONGEST begin, ULONGEST end, int flags) tcomplain (); } +/* See target.h. */ + +void +target_backtrace_record (int size, int flags) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_backtrace_record != NULL) + { + t->to_backtrace_record (size, flags); + return; + } + + tcomplain (); +} + +/* See target.h. */ + +void +target_backtrace_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_backtrace_record_range != NULL) + { + t->to_backtrace_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 4100bb9..b670660 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -903,6 +903,12 @@ struct target_ops /* Disassemble a section of the recorded execution trace. */ void (*to_disas_record_range) (ULONGEST begin, ULONGEST end, int flags); + /* Print a function trace of the recorded execution trace. */ + void (*to_backtrace_record) (int size, int flags); + + /* Print a function trace of an execution trace section. */ + void (*to_backtrace_record_range) (ULONGEST begin, ULONGEST end, int flags); + int to_magic; /* Need sub-structure for target machine related rather than comm related? */ @@ -1995,4 +2001,11 @@ 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); +/* See to_backtrace_record. */ +extern void target_backtrace_record (int size, int flags); + +/* See to_backtrace_record_range. */ +extern void target_backtrace_record_range (ULONGEST begin, ULONGEST end, + int flags); + #endif /* !defined (TARGET_H) */ -- 1.7.1