Added support for dynamic varobjs
authorJan Vrany <jan.vrany@fit.cvut.cz>
Mon, 04 Jun 2018 14:34:44 +0100
changeset 122 c939f8a4c3cd
parent 121 c99479329a46
child 123 1e2c548b0cde
Added support for dynamic varobjs
GDBMI_break_enable.st
GDBVariableObject.st
tests/GDBDebuggeesResource.st
tests/GDBDebuggerTestsR.st
tests/c/py-varobj.c
tests/c/py-varobj.py
--- a/GDBMI_break_enable.st	Mon May 28 23:18:45 2018 +0100
+++ b/GDBMI_break_enable.st	Mon Jun 04 14:34:44 2018 +0100
@@ -97,3 +97,10 @@
 	^ 'break-enable'
 ! !
 
+!GDBMI_break_enable class methodsFor:'documentation'!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
+! !
+
--- a/GDBVariableObject.st	Mon May 28 23:18:45 2018 +0100
+++ b/GDBVariableObject.st	Mon Jun 04 14:34:44 2018 +0100
@@ -24,7 +24,7 @@
 
 GDBDebuggerObject subclass:#GDBVariableObject
 	instanceVariableNames:'parent name exp path thread frame value type numchild has_more
-		children changed inScope visualizer'
+		children changed inScope visualizer dynamic'
 	classVariableNames:''
 	poolDictionaries:''
 	category:'GDB-Core'
@@ -84,11 +84,11 @@
 children
     self isValid ifFalse:[ ^ #() ].
     children isNil ifTrue:[ 
-        (self isValid and:[numchild isNil or:[numchild > 0]]) ifTrue:[
+        (self isValid and:[has_more or:[ numchild isNil or:[numchild > 0]]]) ifTrue:[
             | result |
 
             result := debugger send: (GDBMI_var_list_children arguments: (Array with: '--all-values' with: name)).
-            children := result propertyAt: #children.   
+            children := (result propertyAt: #children) ? #().
             children do:[:each | each setDebugger: debugger; setParent: self ].
             numchild := children size.
         ] ifFalse:[ 
@@ -98,7 +98,7 @@
     ^ children
 
     "Created: / 27-01-2018 / 22:53:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 19-02-2018 / 15:49:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 04-06-2018 / 10:57:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 expression
@@ -180,6 +180,23 @@
         p expression '/ -> 'y'
 
     "
+
+    "/ Raise an error early when #path is requested for a child of dynamic
+    "/ varobj. Thie is not supported by GDB.
+    "/ 
+    "/ Although GDB should report an error [1], dur to a bug it report
+    "/ either wrong (nonsense) value or crashes. A patch has been send
+    "/ to the upstream [2], but meanwhile, check here as well in case someone
+    "/ uses this with older / not yet patches version of GDB.
+    "/ 
+    "/ [1]: https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Variable-Objects.html
+    "/ [2]: https://sourceware.org/ml/gdb-patches/2018-06/msg00058.html
+    "/ 
+    (parent notNil and:[parent isDynamic]) ifTrue:[ 
+        GDBError raiseErrorString: 'Invalid varobj, #path is not supported for children of a dynamic varobjs'.
+        ^ self
+    ].
+
     path isNil ifTrue:[ 
         | result |
 
@@ -189,6 +206,8 @@
     ^ path
 
     "Created: / 05-02-2018 / 21:16:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 01-06-2018 / 16:31:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified (comment): / 04-06-2018 / 14:19:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 thread
@@ -323,11 +342,13 @@
 
 duplicate
     "Create and returns a duplicate of the receiver, representing
-     the same value. Other than thatm the eturned duplicate is completely 
+     the same value. Other than that the returned duplicate is completely 
      independent"
+
     ^ debugger evaluate: self path in: self frame
 
     "Created: / 13-02-2018 / 22:17:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified (format): / 04-06-2018 / 14:23:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !GDBVariableObject methodsFor:'displaying'!
@@ -380,8 +401,10 @@
 
     super initialize.
     inScope := true.
+    dynamic := false.
+    has_more := true.
 
-    "Modified: / 13-02-2018 / 23:51:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 04-06-2018 / 10:55:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 release
@@ -514,6 +537,14 @@
     "Created: / 12-02-2018 / 21:56:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+isDynamic
+    "Return true, if this varobj is a dynamic varobj, false otherwise"
+
+    ^ dynamic
+
+    "Created: / 01-06-2018 / 16:29:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 isValid
     changed value. "/ to force update if necessary
     ^ debugger notNil
--- a/tests/GDBDebuggeesResource.st	Mon May 28 23:18:45 2018 +0100
+++ b/tests/GDBDebuggeesResource.st	Mon Jun 04 14:34:44 2018 +0100
@@ -91,6 +91,12 @@
     "Modified: / 12-01-2018 / 12:43:55 / jv"
 !
 
+binaryPyVarobj
+    ^ self binary: 'py-varobj'
+
+    "Created: / 01-06-2018 / 16:25:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 binaryVariables1
     ^ self binary: 'variables1'
 
--- a/tests/GDBDebuggerTestsR.st	Mon May 28 23:18:45 2018 +0100
+++ b/tests/GDBDebuggerTestsR.st	Mon Jun 04 14:34:44 2018 +0100
@@ -808,6 +808,47 @@
     debugger send: 'quit' andWait: false.
 
     "Created: / 20-03-2018 / 22:32:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+test_variables_08
+    "
+    This tests -var-info-path-expression on dynamic varobjs.
+    "
+
+    | c1 c1_cdr c1_cdr_cdr |
+
+    debugger := GDBDebugger new.
+    self assert: debugger isConnected.
+
+    debugger executable: GDBDebuggeesResource current binaryPyVarobj.
+    self assert: debugger breakpoints isEmpty.
+
+    debugger send: 'source ', ((Smalltalk getPackageDirectoryForPackage:self class package)
+            / 'c' / 'py-varobj.py') pathName.
+    debugger enablePrettyPrinting.
+    debugger send: 'b py-varobj.c:22'.
+    debugger send: 'r'.
+
+    c1 := debugger evaluate: '&c1'.
+    self assert: c1 isDynamic.
+    self assert: c1 path = '&c1'.
+
+    c1_cdr := c1 children second.
+    self assert: c1_cdr expression = 'cdr'.
+    self assert: c1_cdr isDynamic.
+    self assert: c1_cdr parent == c1.
+    self should: [ c1_cdr path ] raise: GDBError.
+
+    c1_cdr_cdr := c1_cdr children second.
+    self assert: c1_cdr_cdr expression = 'cdr'.
+    self assert: c1_cdr_cdr isDynamic.
+    self assert: c1_cdr_cdr parent == c1_cdr.
+    self should: [ c1_cdr_cdr path ] raise: GDBError.      
+
+    debugger send: 'quit' andWait: false.
+
+    "Created: / 01-06-2018 / 16:27:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified (comment): / 04-06-2018 / 11:02:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !GDBDebuggerTestsR class methodsFor:'documentation'!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/c/py-varobj.c	Mon Jun 04 14:34:44 2018 +0100
@@ -0,0 +1,23 @@
+struct _cons
+{
+  struct _cons *slots[2];
+};
+
+#define nil ((struct _cons*)0);
+
+int
+main (int argc, char **argv)
+{
+  struct _cons c1, c2, c3;
+
+  c1.slots[0] = nil;
+  c1.slots[1] = &c2;
+
+  c2.slots[0] = nil;
+  c2.slots[1] = &c3;
+
+  c3.slots[0] = nil;
+  c3.slots[1] = nil;
+
+  return 0;			/* next line */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/c/py-varobj.py	Mon Jun 04 14:34:44 2018 +0100
@@ -0,0 +1,35 @@
+import gdb
+import gdb.types
+import sys
+
+if sys.version_info[0] > 2:
+    long = int
+    imap = map
+
+class cons_pp(object):
+  def __init__(self, val):
+    self._val = val
+
+  def to_string(self):
+    if long(self._val) == 0:
+      return "nil"
+    else:
+      return "(...)"
+
+  def children(self):
+    if long(self._val) == 0:
+      return []
+    else:
+      return [
+        ('car' , self._val["slots"][0]),
+        ('cdr' , self._val["slots"][1])
+      ]
+
+def cons_pp_lookup(val):
+  if str(val.type) == 'struct _cons *':
+    return cons_pp(val)
+  else:
+    return None
+
+del gdb.pretty_printers[1:]
+gdb.pretty_printers.append(cons_pp_lookup)
\ No newline at end of file