[RFC - Python Scripting] Extend Value.dereference to dereference C++ reference values

Siva Chandra
2012-03-12T05:33:17Z

[-- Attachment #1: Type: text/plain, Size: 1514 bytes --]

Hi all,

In an other thread, I have sent a patch for a new 'explore' command
implemented in Python as well as in C. For the Python implementation,
I wanted something which can 'dereference' a C++ reference value.
Unless I am missing something, I couldn't find anything which can do
this in the Python API. Attached is a patch which extends the Python
API method Value.dereference to 'dereference' C++ reference values as
well. I am probably overloading the term 'dereference' as used in the
normal (pointer dereferencing) sense.

Code Changelog:

2012-03-12 Siva Chandra <sivachandra@google.com>

Python scripting: Extend the functionality of the method
Value.dereference to dereference C++ reference values.
* NEWS: Add entry under 'Python scripting' about the extended
functionality of the method Value.dereference.
* python/py-value.c (valpy_dereference): Extend to dereference
values of type TYPE_CODE_REF.
* testsuite/gdb.python/py-value.cc: Add new test case for
testing the methodology exposing C++ values to Python.
* testsuite/gdb.python/py-value-cc.exp: Add tests testing the
methodology exposing C++ values to Python.
* testsuite/gdb.python/Makefile.in: Add py-value-cc to
EXECUTABLES.

Docs Changelog:

2012-03-12 Siva Chandra <sivachandra@google.com>

* gdb.texinfo (Python API/Values From Inferior): Document
extended functionality of the method Value.dereference.

Thanks,
Siva Chandra

[-- Attachment #2: value_dereference_patch_v1.txt --]
[-- Type: text/plain, Size: 7112 bytes --]

diff -rupN src/gdb/doc/gdb.texinfo src_ref/gdb/doc/gdb.texinfo
--- src/gdb/doc/gdb.texinfo 2012-03-08 00:55:37.000000000 +0530
+++ src_ref/gdb/doc/gdb.texinfo 2012-03-11 11:40:51.180932690 +0530
@@ -22137,6 +22137,26 @@ bar = foo.dereference ()

The result @code{bar} will be a @code{gdb.Value} object holding the
value pointed to by @code{foo}.
+
+For C++ reference values, this method returns a new @code{gdb.Value}
+object whose contents is the object referenced by the reference value.
+For example, if @code{int_ref} is a reference to value of type
+ @code{int}, declared in your C++ program as
+
+@smallexample
+int int_val = 10;
+int &int_ref = int_val;
+@end smallexample
+
+then you can use the corresponding @code{gdb.Value} to access what
+@code{int_ref} references to like this:
+
+@smallexample
+deref_val = int_ref.dereference ()
+@end smallexample
+
+The result @code{deref_val} will be a @code{gdb.Value} object whose
+contents are the same as that corresponding to @code{int_val}.
@end defun

@defun Value.dynamic_cast (type)
diff -rupN src/gdb/NEWS src_ref/gdb/NEWS
--- src/gdb/NEWS 2012-03-08 00:55:36.000000000 +0530
+++ src_ref/gdb/NEWS 2012-03-10 17:19:01.452162794 +0530
@@ -23,6 +23,9 @@
frame in order to compute its value, and the latter computes the
symbol's value.

+ ** The method 'dereference' on gdb.Value objects can now dereference
+ C++ reference values.
+
* GDBserver now supports stdio connections.
E.g. (gdb) target remote | ssh myhost gdbserver - hello

diff -rupN src/gdb/python/py-value.c src_ref/gdb/python/py-value.c
--- src/gdb/python/py-value.c 2012-03-02 02:36:54.000000000 +0530
+++ src_ref/gdb/python/py-value.c 2012-03-11 23:21:42.431888816 +0530
@@ -171,7 +171,8 @@ preserve_python_values (struct objfile *
preserve_one_value (iter->value, objfile, copied_types);
}

-/* Given a value of a pointer type, apply the C unary * operator to it. */
+/* If given a value of a pointer type, then apply the C unary * operator to it.
+ If given a value of reference type (C++), then get the value referenced. */
static PyObject *
valpy_dereference (PyObject *self, PyObject *args)
{
@@ -180,10 +181,23 @@ valpy_dereference (PyObject *self, PyObj

TRY_CATCH (except, RETURN_MASK_ALL)
{
- struct value *res_val;
+ struct value *res_val, *self_val;
struct cleanup *cleanup = make_cleanup_value_free_to_mark (value_mark ());

- res_val = value_ind (((value_object *) self)->value);
+ self_val = ((value_object *) self)->value;
+ switch (TYPE_CODE (value_type (self_val)))
+ {
+ case TYPE_CODE_PTR:
+ res_val = value_ind (self_val);
+ break;
+ case TYPE_CODE_REF:
+ res_val = coerce_ref (self_val);
+ break;
+ default:
+ error (_("Attempting to deference a value which is neither a "
+ "pointer, nor a reference."));
+ }
+
result = value_to_value_object (res_val);
do_cleanups (cleanup);
}
diff -rupN src/gdb/testsuite/gdb.python/Makefile.in src_ref/gdb/testsuite/gdb.python/Makefile.in
--- src/gdb/testsuite/gdb.python/Makefile.in 2011-12-23 22:36:16.000000000 +0530
+++ src_ref/gdb/testsuite/gdb.python/Makefile.in 2012-03-11 00:40:36.902953529 +0530
@@ -5,7 +5,7 @@ EXECUTABLES = py-type py-value py-pretty
py-symbol py-mi py-breakpoint py-inferior py-infthread \
py-shared python lib-types py-events py-evthreads py-frame \
py-mi py-pp-maint py-progspace py-section-script py-objfile \
- py-finish-breakpoint py-finish-breakpoint2
+ py-finish-breakpoint py-finish-breakpoint2 py-value-cc

MISCELLANEOUS = py-shared-sl.sl py-events-shlib.so py-events-shlib-nodebug.so

diff -rupN src/gdb/testsuite/gdb.python/py-value.cc src_ref/gdb/testsuite/gdb.python/py-value.cc
--- src/gdb/testsuite/gdb.python/py-value.cc 1970-01-01 05:30:00.000000000 +0530
+++ src_ref/gdb/testsuite/gdb.python/py-value.cc 2012-03-11 11:50:35.980973966 +0530
@@ -0,0 +1,34 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+class A {
+};
+
+int
+func (const A &a)
+{
+ int int_val = 10;
+ int &int_ref = int_val;
+ return 0; /* Break here. */
+}
+
+int
+main ()
+{
+ A obj;
+ return func (obj);
+}
diff -rupN src/gdb/testsuite/gdb.python/py-value-cc.exp src_ref/gdb/testsuite/gdb.python/py-value-cc.exp
--- src/gdb/testsuite/gdb.python/py-value-cc.exp 1970-01-01 05:30:00.000000000 +0530
+++ src_ref/gdb/testsuite/gdb.python/py-value-cc.exp 2012-03-11 11:50:34.810932230 +0530
@@ -0,0 +1,51 @@
+# Copyright (C) 2012 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite. It tests the mechanism
+# exposing values to Python.
+
+if { [skip_cplus_tests] } { continue }
+
+set testfile "py-value"
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \
+ {debug c++}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+gdb_load ${binfile}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here."]
+gdb_continue_to_breakpoint "Break here" ".*Break here.*"
+
+gdb_test "python print str(gdb.parse_and_eval(\"a\").type)" "const A &"
+gdb_test "python print str(gdb.parse_and_eval(\"a\").dereference().type)" "const A"
+gdb_test "python print str(gdb.parse_and_eval(\"int_ref\").type)" "int &"
+gdb_test "python print str(gdb.parse_and_eval(\"int_ref\").dereference().type)" "int"
+gdb_test "python print str(gdb.parse_and_eval(\"int_ref\").dereference())" "10"