Add block['var'] accessor
authorChristian Biesinger <cbiesinger@google.com>
Thu, 1 Aug 2019 22:22:28 +0000 (17:22 -0500)
committerChristian Biesinger <cbiesinger@google.com>
Mon, 5 Aug 2019 18:06:18 +0000 (13:06 -0500)
Currently we support iteration on blocks; this patch extends that to make
subscript access work as well.

gdb/ChangeLog:

2019-08-05  Christian Biesinger  <cbiesinger@google.com>

* NEWS: Mention dictionary access on blocks.
* python/py-block.c (blpy_getitem): New function.
(block_object_as_mapping): New struct.
(block_object_type): Use new struct for tp_as_mapping field.

gdb/doc/ChangeLog:

2019-08-05  Christian Biesinger  <cbiesinger@google.com>

* python.texi (Blocks In Python): Document dictionary access on blocks.

gdb/testsuite/ChangeLog:

2019-08-05  Christian Biesinger  <cbiesinger@google.com>

* gdb.python/py-block.exp: Test dictionary access on blocks.

gdb/ChangeLog
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/python.texi
gdb/python/py-block.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.python/py-block.exp

index da1d636..b17b252 100644 (file)
@@ -1,5 +1,12 @@
 2019-08-05  Christian Biesinger  <cbiesinger@google.com>
 
+       * NEWS: Mention dictionary access on blocks.
+       * python/py-block.c (blpy_getitem): New function.
+       (block_object_as_mapping): New struct.
+       (block_object_type): Use new struct for tp_as_mapping field.
+
+2019-08-05  Christian Biesinger  <cbiesinger@google.com>
+
        * objfiles.h (objfile): Add a comment describing partial symbols.
 
 2019-08-05  Tom Tromey  <tromey@adacore.com>
index da641cb..b4c59e4 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -47,6 +47,9 @@
   ** gdb.Objfile has new methods 'lookup_global_symbol' and
      'lookup_static_symbol' to lookup a symbol from this objfile only.
 
+  ** gdb.Block now supports the dictionary syntax for accessing symbols in
+     this block (e.g. block['local_variable']).
+
 * New commands
 
 | [COMMAND] | SHELL_COMMAND
index 95fd22c..6faf5f3 100644 (file)
@@ -1,3 +1,7 @@
+2019-08-05  Christian Biesinger  <cbiesinger@google.com>
+
+       * python.texi (Blocks In Python): Document dictionary access on blocks.
+
 2019-08-03  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
 
         * gdb.texinfo (Symbols): Document new args -dirname and -basename
index 3fdccd5..832283d 100644 (file)
@@ -4722,7 +4722,12 @@ A @code{gdb.Block} is iterable.  The iterator returns the symbols
 should not assume that a specific block object will always contain a
 given symbol, since changes in @value{GDBN} features and
 infrastructure may cause symbols move across blocks in a symbol
-table.
+table.  You can also use Python's @dfn{dictionary syntax} to access
+variables in this block, e.g.:
+
+@smallexample
+symbol = some_block['variable']  # symbol is of type gdb.Symbol
+@end smallexample
 
 The following block-related functions are available in the @code{gdb}
 module:
index 90140eb..4dc47ff 100644 (file)
@@ -224,6 +224,43 @@ blpy_is_static (PyObject *self, void *closure)
   Py_RETURN_FALSE;
 }
 
+/* Given a string, returns the gdb.Symbol representing that symbol in this
+   block.  If such a symbol does not exist, returns NULL with a Python
+   exception.  */
+
+static PyObject *
+blpy_getitem (PyObject *self, PyObject *key)
+{
+  const struct block *block;
+
+  BLPY_REQUIRE_VALID (self, block);
+
+  gdb::unique_xmalloc_ptr<char> name = python_string_to_host_string (key);
+  if (name == nullptr)
+    return nullptr;
+
+  lookup_name_info lookup_name (name.get(), symbol_name_match_type::FULL);
+
+  /* We use ALL_BLOCK_SYMBOLS_WITH_NAME instead of block_lookup_symbol so
+     that we can look up symbols irrespective of the domain, matching the
+     iterator. It would be confusing if the iterator returns symbols you
+     can't find via getitem.  */
+  struct block_iterator iter;
+  struct symbol *sym = nullptr;
+  ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym)
+    {
+      /* Just stop at the first match */
+      break;
+    }
+
+  if (sym == nullptr)
+    {
+      PyErr_SetObject (PyExc_KeyError, key);
+      return nullptr;
+    }
+  return symbol_to_symbol_object (sym);
+}
+
 static void
 blpy_dealloc (PyObject *obj)
 {
@@ -440,6 +477,12 @@ static gdb_PyGetSetDef block_object_getset[] = {
   { NULL }  /* Sentinel */
 };
 
+static PyMappingMethods block_object_as_mapping = {
+  NULL,
+  blpy_getitem,
+  NULL
+};
+
 PyTypeObject block_object_type = {
   PyVarObject_HEAD_INIT (NULL, 0)
   "gdb.Block",                   /*tp_name*/
@@ -453,7 +496,7 @@ PyTypeObject block_object_type = {
   0,                             /*tp_repr*/
   0,                             /*tp_as_number*/
   0,                             /*tp_as_sequence*/
-  0,                             /*tp_as_mapping*/
+  &block_object_as_mapping,      /*tp_as_mapping*/
   0,                             /*tp_hash */
   0,                             /*tp_call*/
   0,                             /*tp_str*/
index 236c0e2..1a2cb0b 100644 (file)
@@ -1,3 +1,7 @@
+2019-08-05  Christian Biesinger  <cbiesinger@google.com>
+
+       * gdb.python/py-block.exp: Test dictionary access on blocks.
+
 2019-08-05  Simon Marchi  <simon.marchi@efficios.com>
 
        PR gdb/24863
index 20d3968..6be1abe 100644 (file)
@@ -43,6 +43,11 @@ gdb_test "python print (block)" "<gdb.Block object at $hex>" "check block not No
 gdb_test "python print (block.function)" "None" "first anonymous block"
 gdb_test "python print (block.start)" "${decimal}" "check start not None"
 gdb_test "python print (block.end)" "${decimal}" "check end not None"
+gdb_test "python print (block\['f'\].name == 'f')" "True" "check variable access"
+gdb_test "python print (block\['nonexistent'\])" ".*KeyError: 'nonexistent'.*" \
+         "check nonexistent variable"
+gdb_test "python print (block\[42\])" ".*TypeError: Expected a string.*" \
+         "check non-string key"
 
 # Test global/static blocks
 gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0