From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21022 invoked by alias); 8 Mar 2013 09:17:10 -0000 Received: (qmail 20928 invoked by uid 22791); 8 Mar 2013 09:17:06 -0000 X-SWARE-Spam-Status: No, hits=-8.0 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 mga09.intel.com (HELO mga09.intel.com) (134.134.136.24) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 08 Mar 2013 09:16:21 +0000 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga102.jf.intel.com with ESMTP; 08 Mar 2013 01:14:51 -0800 X-ExtLoop1: 1 Received: from swsutil001.isw.intel.com ([10.237.237.11]) by orsmga002.jf.intel.com with ESMTP; 08 Mar 2013 01:16:17 -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 r289GETX022914; Fri, 8 Mar 2013 09:16:14 GMT Received: from ulslx001.iul.intel.com (localhost [127.0.0.1]) by ulslx001.iul.intel.com with ESMTP id r289GEjf002115; Fri, 8 Mar 2013 10:16:14 +0100 Received: (from mmetzger@localhost) by ulslx001.iul.intel.com with id r289GE1S002111; Fri, 8 Mar 2013 10:16:14 +0100 From: Markus Metzger To: jan.kratochvil@redhat.com Cc: gdb-patches@sourceware.org, markus.t.metzger@gmail.com Subject: [patch v10 16/21] record: add "record function-call-history" command Date: Fri, 08 Mar 2013 09:17:00 -0000 Message-Id: <1362734168-1725-17-git-send-email-markus.t.metzger@intel.com> In-Reply-To: <1362734168-1725-1-git-send-email-markus.t.metzger@intel.com> References: <1362734168-1725-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-03/txt/msg00328.txt.bz2 Add command to print the function names from recorded instructions. 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 at function granularity without having to reverse-step. Doc approved by Eli Zaretskii. Approved by Jan Kratochvil. 2013-03-08 Markus Metzger * target.c (target_call_history, target_call_history_from, target_call_history_range): New. * target.h (target_ops) : New fields. (target_call_history, target_call_history_from, target_call_history_range): New declaration. * record.c (get_call_history_modifiers, cmd_record_call_history, record_call_history_size): New. (_initialize_record): Add the "record function-call-history" command. Add "set/show record function-call-history-size" commands. * record.h (record_print_flag): New. --- gdb/record.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/record.h | 10 ++++ gdb/target.c | 51 ++++++++++++++++++++ gdb/target.h | 24 +++++++++ 4 files changed, 234 insertions(+), 0 deletions(-) diff --git a/gdb/record.c b/gdb/record.c index c71842f..12ab179 100644 --- a/gdb/record.c +++ b/gdb/record.c @@ -35,6 +35,9 @@ unsigned int record_debug = 0; /* The number of instructions to print in "record instruction-history". */ static unsigned int record_insn_history_size = 10; +/* The number of functions to print in "record function-call-history". */ +static unsigned int record_call_history_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; @@ -466,6 +469,126 @@ cmd_record_insn_history (char *arg, int from_tty) } } +/* Read function-call-history modifiers from an argument string. */ + +static int +get_call_history_modifiers (char **arg) +{ + int modifiers; + char *args; + + modifiers = 0; + args = *arg; + + if (args == NULL) + return modifiers; + + while (*args == '/') + { + ++args; + + if (*args == '\0') + error (_("Missing modifier.")); + + for (; *args; ++args) + { + if (isspace (*args)) + break; + + if (*args == '/') + continue; + + switch (*args) + { + case 'l': + modifiers |= record_print_src_line; + break; + case 'i': + modifiers |= record_print_insn_range; + break; + default: + error (_("Invalid modifier: %c."), *args); + } + } + + args = skip_spaces (args); + } + + /* Update the argument string. */ + *arg = args; + + return modifiers; +} + +/* The "record function-call-history" command. */ + +static void +cmd_record_call_history (char *arg, int from_tty) +{ + int flags, size; + + require_record_target (); + + flags = get_call_history_modifiers (&arg); + + /* We use a signed size to also indicate the direction. Make sure that + unlimited remains unlimited. */ + size = (int) record_call_history_size; + if (size < 0) + size = INT_MAX; + + if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) + target_call_history (size, flags); + else if (strcmp (arg, "-") == 0) + target_call_history (-size, flags); + else + { + ULONGEST begin, end; + + begin = get_insn_number (&arg); + + if (*arg == ',') + { + arg = skip_spaces (++arg); + + if (*arg == '+') + { + arg += 1; + size = get_context_size (&arg); + + no_chunk (arg); + + target_call_history_from (begin, size, flags); + } + else if (*arg == '-') + { + arg += 1; + size = get_context_size (&arg); + + no_chunk (arg); + + target_call_history_from (begin, -size, flags); + } + else + { + end = get_insn_number (&arg); + + no_chunk (arg); + + target_call_history_range (begin, end, flags); + } + } + else + { + no_chunk (arg); + + target_call_history_from (begin, size, flags); + } + + dont_repeat (); + } +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_record; @@ -489,6 +612,13 @@ Show number of instructions to print in \"record instruction-history\"."), NULL, NULL, NULL, &set_record_cmdlist, &show_record_cmdlist); + add_setshow_uinteger_cmd ("function-call-history-size", no_class, + &record_call_history_size, _("\ +Set number of function to print in \"record function-call-history\"."), _("\ +Show number of functions to print in \"record function-call-history\"."), + 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); @@ -549,4 +679,23 @@ from the first argument.\n\ The number of instructions to disassemble can be defined with \"set record \ instruction-history-size\"."), &record_cmdlist); + + add_cmd ("function-call-history", class_obscure, cmd_record_call_history, _("\ +Prints the execution history at function granularity.\n\ +It prints one line for each sequence of instructions that belong to the same \ +function.\n\ +Without modifiers, it prints the function name.\n\ +With a /l modifier, the source file and line number range is included.\n\ +With a /i modifier, the instruction number range is included.\n\ +With no argument, prints ten more lines after the previous ten-line print.\n\ +\"record function-call-history -\" prints ten lines before a previous ten-line \ +print.\n\ +One argument specifies a function number as shown by 'info record', and \ +ten lines are printed after that function.\n\ +Two arguments with comma between them specify a range of functions to print.\n\ +If the second argument is preceded by '+' or '-', it specifies the distance \ +from the first argument.\n\ +The number of functions to print can be defined with \"set record \ +function-call-history-size\"."), + &record_cmdlist); } diff --git a/gdb/record.h b/gdb/record.h index 04d6b4a..86e6bc6 100644 --- a/gdb/record.h +++ b/gdb/record.h @@ -32,6 +32,16 @@ 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), + + /* Print the instruction number range (if applicable). */ + record_print_insn_range = (1 << 1), +}; + /* 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 797163f..5b5f784 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -4404,6 +4404,57 @@ target_insn_history_range (ULONGEST begin, ULONGEST end, int flags) tcomplain (); } +/* See target.h. */ + +void +target_call_history (int size, int flags) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_call_history != NULL) + { + t->to_call_history (size, flags); + return; + } + + tcomplain (); +} + +/* See target.h. */ + +void +target_call_history_from (ULONGEST begin, int size, int flags) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_call_history_from != NULL) + { + t->to_call_history_from (begin, size, flags); + return; + } + + tcomplain (); +} + +/* See target.h. */ + +void +target_call_history_range (ULONGEST begin, ULONGEST end, int flags) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_call_history_range != NULL) + { + t->to_call_history_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 47fa6a3..7403221 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -911,6 +911,21 @@ struct target_ops BEGIN (inclusive) to instruction END (exclusive). */ void (*to_insn_history_range) (ULONGEST begin, ULONGEST end, int flags); + /* Print a function trace of the recorded execution trace. + If SIZE < 0, print abs (SIZE) preceding functions; otherwise, print SIZE + succeeding functions. */ + void (*to_call_history) (int size, int flags); + + /* Print a function trace of the recorded execution trace starting + at function FROM. + If SIZE < 0, print abs (SIZE) functions before FROM; otherwise, print + SIZE functions after FROM. */ + void (*to_call_history_from) (ULONGEST begin, int size, int flags); + + /* Print a function trace of an execution trace section from function BEGIN + (inclusive) to function END (exclusive). */ + void (*to_call_history_range) (ULONGEST begin, ULONGEST end, int flags); + int to_magic; /* Need sub-structure for target machine related rather than comm related? */ @@ -2004,4 +2019,13 @@ extern void target_insn_history_from (ULONGEST from, int size, int flags); /* See to_insn_history_range. */ extern void target_insn_history_range (ULONGEST begin, ULONGEST end, int flags); +/* See to_call_history. */ +extern void target_call_history (int size, int flags); + +/* See to_call_history_from. */ +extern void target_call_history_from (ULONGEST begin, int size, int flags); + +/* See to_call_history_range. */ +extern void target_call_history_range (ULONGEST begin, ULONGEST end, int flags); + #endif /* !defined (TARGET_H) */ -- 1.7.1