From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28654 invoked by alias); 15 Dec 2006 02:41:11 -0000 Received: (qmail 28592 invoked by uid 22791); 15 Dec 2006 02:41:09 -0000 X-Spam-Check-By: sourceware.org Received: from mx2.netapp.com (HELO mx2.netapp.com) (216.240.18.37) by sourceware.org (qpsmtpd/0.31) with ESMTP; Fri, 15 Dec 2006 02:40:54 +0000 Received: from smtp2.corp.netapp.com ([10.57.159.114]) by mx2.netapp.com with ESMTP; 14 Dec 2006 18:40:51 -0800 X-IronPort-AV: i="4.12,171,1165219200"; d="scan'208"; a="11934933:sNHT28501298" Received: from linden.eng.netapp.com (linden-fe.eng.netapp.com [10.56.10.191]) by smtp2.corp.netapp.com (8.13.1/8.13.1/NTAP-1.6) with ESMTP id kBF2epWZ024558; Thu, 14 Dec 2006 18:40:51 -0800 (PST) Received: (from steverod@localhost) by linden.eng.netapp.com (8.11.7p1+Sun/8.11.6) id kBF2epw10531; Thu, 14 Dec 2006 18:40:51 -0800 (PST) Date: Fri, 15 Dec 2006 02:41:00 -0000 From: Steve Rodrigues To: gdb-patches@sources.redhat.com Cc: Steve Rodrigues Subject: [patch] Indirect access to GDB history variables Message-ID: <20061215024050.GA8750@linden.netapp.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="qDbXVdCdHGoSgWSk" Content-Disposition: inline User-Agent: Mutt/1.4.2.1i 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: 2006-12/txt/msg00194.txt.bz2 --qDbXVdCdHGoSgWSk Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 2883 New Feature for GDB: Programmatic access to the value history. Problem Description: Our company has a wide variety of GDB scripts used to analyze problems within core files. Many of these scripts will generate values that are useful to probe into later; however, the scripts will generate a LOT of values, or values that aren't in sequential order (you care about, say, every third value). GDB only lets you reference previous history value either with absolute numbers ($10, $236) or with reference to the most recently printed value ($$, $$9, etc). It sure would be nice if there was a way to be able to access the value history by indirecting through a variable. Feature: This patch enables users to programmatcially access the value history through a GDB variable, by overloading the "$$" construct to contain a variable name. For example, if my script had printed out values $10-$27, but only every 3rd one was interesting (it was a pointer I wished to examine further), I could do the following: set $i=10 while ($i < 28) p *$$i set $i+= 3 end ... and I'd see values of $10, $13, $16 and so on. This makes it easier to compose scripts together when debugging. Implementation: The meat of the change is in parse.c (write_dollar_variable) and eval.c (evaluate_subexp_standard). I introduced a new operand type, OP_LAST_INTERNALVAR, which is emitted by write_dollar_variable (parse.c) when it sees a "$$" that is NOT followed by digits (and not alone, which is already an OP_LAST operand). OP_LAST_INTERNALVAR should always be followed by an OP_INTERNALVAR operand, pointing to the GDB variable which we will indirect through. When evaluate_subexp_standard (eval.c) sees an OP_LAST_INTERNALVAR, we just need to evaluate the following OP_INTERNALVAR expression and take the value_contents of that expression, passing the results into access_value_history. We have been using this modification internally for over a year on gdb 6.2 with no problems. The patch has been verified on gdb-6.6.50.20061212 (most recent weekly build) on Linux and on gdb-6.6.50.20061127 on Solaris 5.8 (couldn't get 20061212 to build). Testing: This has been tested by hand. I've been trying to write a test case but have been having no luck getting the test suite to run (due to old versions of Tcl/expect on the systems this was developed on). Future Directions: The obvious next step for this is to add a variable ($#?) which indicates the current history value count, which makes this amenable to full scripting rather than use by hand. ChangeLog and Patch are attached. --Steve -- Steven Rodrigues | Lost, yesterday, somewhere between sunrise and Member of Technical Staff | sunset, two golden hours, each set with sixty Network Appliance Corp. | diamond minutes. No reward is offered, for they steverod@netapp.com | are gone forever. -- Horace Mann --qDbXVdCdHGoSgWSk Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=ChangeLog Content-length: 568 2006-10-17 Steve Rodrigues * expression.h (enum exp_opcode): Add OP_LAST_INTERNALVAR opcode. * eval.c (evaluate_subexp_standard): Process a OP_LAST_INTERNALVAR operand to indirectly access the value history. * ada-lang.c (resolve_subexp): Support OP_LAST_INTERNALVAR. * expprint.c (print_subexp_standard): Support OP_LAST_INTERNALVAR. (op_name_standard): Support OP_LAST_INTERNALVAR. (dump_subexp_body_standard): Support OP_LAST_INTERNALVAR. * parse.c (write_dollar_variable): Support '$$' to be treated as an OP_LAST_INTERNALVAR. --qDbXVdCdHGoSgWSk Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="gdb66.diffs" Content-length: 4291 --- ./gdb/ada-lang.c.orig Thu Nov 30 16:32:29 2006 +++ ./gdb/ada-lang.c Thu Dec 14 18:01:00 2006 @@ -2728,6 +2728,11 @@ resolve_subexp (struct expression **expp *pos += 3; break; + case OP_LAST_INTERNALVAR: + *pos ++; + nargs = 1; + break; + case UNOP_MEMVAL: *pos += 3; nargs = 1; --- ./gdb/eval.c.orig Mon Oct 9 20:17:53 2006 +++ ./gdb/eval.c Thu Dec 14 18:01:00 2006 @@ -473,6 +473,12 @@ evaluate_subexp_standard (struct type *e return access_value_history (longest_to_int (exp->elts[pc + 1].longconst)); + case OP_LAST_INTERNALVAR: + { + arg1 = evaluate_subexp(NULL_TYPE, exp, pos, noside); + return access_value_history(*(int*)value_contents(arg1)); + } + case OP_REGISTER: { int regno = longest_to_int (exp->elts[pc + 1].longconst); --- ./gdb/expprint.c.orig Mon Oct 9 20:17:53 2006 +++ ./gdb/expprint.c Thu Dec 14 18:01:00 2006 @@ -151,6 +151,12 @@ print_subexp_standard (struct expression internalvar_name (exp->elts[pc + 1].internalvar)); return; + case OP_LAST_INTERNALVAR: + (*pos) += 2; + fprintf_filtered (stream, "$$%s", + internalvar_name (exp->elts[pc + 1].internalvar)); + return; + case OP_FUNCALL: (*pos) += 2; nargs = longest_to_int (exp->elts[pc + 1].longconst); @@ -695,6 +701,8 @@ op_name_standard (enum exp_opcode opcode return "OP_REGISTER"; case OP_INTERNALVAR: return "OP_INTERNALVAR"; + case OP_LAST_INTERNALVAR: + return "OP_LAST_INTERNALVAR"; case OP_FUNCALL: return "OP_FUNCALL"; case OP_STRING: @@ -976,6 +984,9 @@ dump_subexp_body_standard (struct expres fprintf_filtered (stream, " (%s)", exp->elts[elt].internalvar->name); elt += 2; + break; + case OP_LAST_INTERNALVAR: + fprintf_filtered (stream, "History element from Internal var"); break; case OP_FUNCALL: { --- ./gdb/expression.h.orig Mon Oct 9 20:17:53 2006 +++ ./gdb/expression.h Thu Dec 14 18:01:00 2006 @@ -174,6 +174,12 @@ enum exp_opcode /* OP_INTERNALVAR is followed by an internalvar ptr in the next exp_element. With another OP_INTERNALVAR at the end, this makes three exp_elements. */ OP_INTERNALVAR, + + /* OP_LAST_INTERNALVAR is used for accessing the history programmatically. + It is followed by an internalvar ptr in the next exp_element. + With another OP_LAST_INTERNALVAR at the end, this makes three + exp_elements. */ + OP_LAST_INTERNALVAR, /* OP_FUNCALL is followed by an integer in the next exp_element. The integer is the number of args to the function call. --- ./gdb/parse.c.orig Sat Nov 18 15:54:32 2006 +++ ./gdb/parse.c Thu Dec 14 18:01:00 2006 @@ -476,6 +476,7 @@ write_dollar_variable (struct stoken str { struct symbol *sym = NULL; struct minimal_symbol *msym = NULL; + int stroff = 1; /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) and $$digits (equivalent to $<-digits> if you could type that). */ @@ -487,7 +488,7 @@ write_dollar_variable (struct stoken str if (str.length >= 2 && str.ptr[1] == '$') { negate = 1; - i = 2; + i = stroff = 2; } if (i == str.length) { @@ -536,11 +537,17 @@ write_dollar_variable (struct stoken str return; } - /* Any other names starting in $ are debugger internal variables. */ + /* Any other names starting in $ are debugger internal variables. + A 'negated' internal variable should be treated as an indirect + history reference, which adds another LAST_INTERNALVAR opcode */ write_exp_elt_opcode (OP_INTERNALVAR); - write_exp_elt_intern (lookup_internalvar (copy_name (str) + 1)); + write_exp_elt_intern (lookup_internalvar (copy_name (str) + stroff)); write_exp_elt_opcode (OP_INTERNALVAR); + + if (negate) + write_exp_elt_opcode (OP_LAST_INTERNALVAR); + return; handle_last: write_exp_elt_opcode (OP_LAST); @@ -904,6 +911,10 @@ operator_length_standard (struct express oplen = 3; break; + case OP_LAST_INTERNALVAR: + oplen = 1; + args = 1; + break; case OP_COMPLEX: oplen = 1; args = 2; --qDbXVdCdHGoSgWSk--