Change `GDBRegisterWithValue >> #value` to return numeric value
authorJan Vrany <jan.vrany@labware.com>
Fri, 10 Sep 2021 22:12:22 +0100
changeset 237 81a18c404314
parent 236 e36e28215fd9
child 238 bdf011a6482b
Change `GDBRegisterWithValue >> #value` to return numeric value ...rather than string. In case of 'composite' registers (such as FPRs that can hold both IEEE 754 float and double values or vector registers) it returns a dictionary with components.
GDBMIParser.st
GDBRegisterWithValue.st
tests/GDBMIParserTests.st
--- a/GDBMIParser.st	Fri Sep 10 20:25:06 2021 +0100
+++ b/GDBMIParser.st	Fri Sep 10 22:12:22 2021 +0100
@@ -269,6 +269,56 @@
     "Created: / 18-06-2014 / 07:17:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+parseInteger
+    ^ self parseIntegerAndText: false
+
+    "Created: / 10-09-2021 / 14:36:11 / Jan Vrany <jan.vrany@labware.com>"
+    "Modified: / 10-09-2021 / 22:03:27 / Jan Vrany <jan.vrany@labware.com>"
+!
+
+parseIntegerAndText: returnAlsoString
+    "Parse decimal, hex or octal integer and return
+     either the integer value (if `returnAlsoString` is `false`)
+     or pair #(<value> <text>) where <text> is the literal string
+     if (if `returnAlsoString` is `true`).
+
+     The next character in input is known to be a digit.
+    "
+    | c v s |
+
+    c := self next.
+    returnAlsoString ifTrue:[ 
+        s := String new writeStream.
+        s nextPut: c.
+    ].
+    (c == $0 and:[ self peek == $x ]) ifTrue:[ 
+        "/ Find 0x prefix, parse hex number (address or alike)
+        returnAlsoString ifTrue:[ s nextPut: self peek].
+        self next. "/ eat $x
+        v := 0.                  
+        [ c := self peek.
+          c notNil and:[ c isHexDigit] ] whileTrue:[ 
+            returnAlsoString ifTrue:[ s nextPut: self peek].
+            self next.
+            v := (v << 4) + (c digitValue).
+        ].
+    ] ifFalse:[
+        "/ Parse decimal number
+        v := c digitValue.
+        [ c := self peek.
+          c notNil and:[ c isDigit] ] whileTrue:[ 
+            returnAlsoString ifTrue:[ s nextPut: self peek].
+            self next.
+            v := (v * 10) + (c digitValue).
+        ].
+    ].      
+    ^ returnAlsoString 
+        ifTrue:[ Array with: v with: s contents ]
+        ifFalse:[ v ].
+
+    "Created: / 10-09-2021 / 22:02:26 / Jan Vrany <jan.vrany@labware.com>"
+!
+
 parseNl
     | c |
 
@@ -732,6 +782,34 @@
     "Created: / 30-05-2014 / 10:36:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+parseInteger
+    "Parse input containing (MI) printed register value"
+    | c v |
+
+    c := self next.
+    (c == $0 and:[ self peek == $x ]) ifTrue:[ 
+        "/ Find 0x prefix, parse hex number (address or alike)
+        self next. "/ eat $x
+        v := 0.                  
+        [ c := self peek.
+          c notNil and:[ c isHexDigit] ] whileTrue:[ 
+            self next.
+            v := (v << 4) + (c digitValue).
+        ].
+    ] ifFalse:[
+        "/ Parse decimal number
+        v := c digitValue.
+        [ c := self peek.
+          c notNil and:[ c isDigit] ] whileTrue:[ 
+            self next.
+            v := (v * 10) + (c digitValue).
+        ].
+    ].          
+    ^ v
+
+    "Created: / 10-09-2021 / 14:36:11 / Jan Vrany <jan.vrany@labware.com>"
+!
+
 parseList
     "
     list → '[]' | '[' value ( ',' value )* ']' | '[' result ( ',' result )* ']'
@@ -801,13 +879,19 @@
     dict := Dictionary new.
     self peek ~~ $} ifTrue:[
         name := self parseVariable.
+        self skipSeparators.
         self expect: $=.
+        self skipSeparators.
         value := self parseValue.
+        self skipSeparators.   
         dict at: name put: value.
         [ self peek == $, ] whileTrue:[
             self next.
+            self skipSeparators.
             name := self parseVariable.
+            self skipSeparators.   
             self expect: $=.
+            self skipSeparators.   
             value := self parseValue.
             dict at: name put: value.
         ].
@@ -816,25 +900,30 @@
 
     "Created: / 14-06-2014 / 02:19:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 06-07-2017 / 08:25:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 10-09-2021 / 14:50:55 / Jan Vrany <jan.vrany@labware.com>"
 !
 
 parseValue
     "
-    value → const | tuple | list
+    value → const | tuple | list | integer
     "
 
     self peek == $" ifTrue:[
-	^ self parseConst
+        ^ self parseConst
     ].
     self peek == ${ ifTrue:[
-	^ self parseTuple.
+        ^ self parseTuple.
     ].
     self peek == $[ ifTrue:[
-	^ self parseList
+        ^ self parseList
+    ].
+    self peek isDigit ifTrue: [ 
+        ^ self parseInteger
     ].
     self error:'Invalid value'
 
     "Created: / 30-05-2014 / 10:31:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 10-09-2021 / 14:35:02 / Jan Vrany <jan.vrany@labware.com>"
 ! !
 
 !GDBMIParser methodsFor:'parsing-values-typed'!
@@ -946,36 +1035,22 @@
         | c v |
 
         self expect: $".
-        c := self next.
-        v := 0.
-        c isDigit ifTrue:[
-            (c == $0 and:[ self peek == $x ]) ifTrue:[ 
-                "/ Find 0x prefix, parse hex number (address or alike)
-                self next. "/ eat $x
-                c := self next.
-                [ c isHexDigit ] whileTrue:[ 
-                    v := (v << 4) + (c digitValue).
-                    c := self next.
-                ].
-            ] ifFalse:[
-                "/ Parse decimal number
-                [ c isDigit ] whileTrue:[ 
-                    v := (v * 10) + (c digitValue).
-                    c := self next.
-                ].
-            ].
-            c == $" ifTrue:[ 
-                ^ v
+        self peek isDigit ifTrue:[
+            v := self parseIntegerAndText: true.
+            self peek == $" ifTrue:[ 
+                self next. "/ eat $"
+                ^ v first
             ] ifFalse:[ 
-                ^ self parseCStringRest:v printString , c  
+                ^ self parseCStringRest:v second
             ].
         ].
-        ^ self parseCStringRest: c asString
+        ^ self parseCStringRest: ''
     ].
     ^ self parseValue
 
     "Created: / 18-06-2014 / 07:39:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 03-07-2018 / 14:50:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 10-09-2021 / 22:07:34 / Jan Vrany <jan.vrany@labware.com>"
 !
 
 parseValueAsListElementDescribedBy:descriptor
--- a/GDBRegisterWithValue.st	Fri Sep 10 20:25:06 2021 +0100
+++ b/GDBRegisterWithValue.st	Fri Sep 10 22:12:22 2021 +0100
@@ -89,10 +89,35 @@
 !
 
 value
-    changed value.
+    "Return the value of the register. The returned value is either
+
+       * an integer in case the register is integer register - GPRs and so on)
+       * a dictionary in case of 'composite' registers - for example a value
+         of FPR might be returned as '{float = 0xABCDDCBA, double = 0xA...B}'
+         Similarly for vector registers (SSE / SSE2 regs on x86, VSRs on POWER)
+    "
+    ^ (GDBMIParser on: self valueString) parseValue
+
+    "Modified: / 27-09-2018 / 15:26:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 10-09-2021 / 14:58:56 / Jan Vrany <jan.vrany@labware.com>"
+    "Modified (comment): / 10-09-2021 / 20:00:13 / Jan Vrany <jan.vrany@labware.com>"
+!
+
+valueString
+    value isNil ifTrue: [
+        | result registers |
+        result := debugger send: (GDBMI_data_list_register_values new arguments: (Array with: '--thread' with: frame thread id with: '--frame' with: frame level with: 'r' with: register number)).
+        registers := result propertyAt: #'register-values'.     
+        self assert: registers size == 1.
+        self assert: registers first register = register number.
+        value := registers first valueString.
+    ] ifFalse: [
+        changed value.
+    ].
     ^ value
 
-    "Modified: / 27-09-2018 / 15:26:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Created: / 10-09-2021 / 14:14:14 / Jan Vrany <jan.vrany@labware.com>"
+    "Modified: / 10-09-2021 / 15:58:15 / Jan Vrany <jan.vrany@labware.com>"
 ! !
 
 !GDBRegisterWithValue methodsFor:'initialization'!
--- a/tests/GDBMIParserTests.st	Fri Sep 10 20:25:06 2021 +0100
+++ b/tests/GDBMIParserTests.st	Fri Sep 10 22:12:22 2021 +0100
@@ -1,7 +1,7 @@
 "
 jv:libgdbs - GNU Debugger Interface Library
 Copyright (C) 2015-now Jan Vrany
-Copyright (C) 2020 LabWare
+Copyright (C) 2020-2021 LabWare
 
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
@@ -34,7 +34,7 @@
 "
 jv:libgdbs - GNU Debugger Interface Library
 Copyright (C) 2015-now Jan Vrany
-Copyright (C) 2020 LabWare
+Copyright (C) 2020-2021 LabWare
 
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
@@ -790,6 +790,54 @@
     "Created: / 06-07-2017 / 08:21:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
+!GDBMIParserTests methodsFor:'tests - values - registers'!
+
+test_registers_01
+    | value |
+
+    value := (GDBMIParser on:'0x00000000000717fc') parseValue.
+    self assert:value isInteger.
+    self assert:value = 16r00000000000717fc
+
+    "Created: / 10-09-2021 / 14:28:27 / Jan Vrany <jan.vrany@labware.com>"
+!
+
+test_registers_02
+    | value |
+
+    value := (GDBMIParser on:'{float = 0x00000000, double = 0x0000000000000000}') parseValue.
+    self assert:value isDictionary.
+    self assert:(value includesKey: 'float').
+    self assert:(value at: 'float') = 0.
+    self assert:(value includesKey: 'double').
+    self assert:(value at: 'double') = 0.
+
+    "Created: / 10-09-2021 / 14:31:00 / Jan Vrany <jan.vrany@labware.com>"
+!
+
+test_registers_03
+    | value |
+
+    value := (GDBMIParser on:'{x = 00000000, y = 1}') parseValue.
+    self assert:value isDictionary.
+    self assert:(value includesKey: 'x').
+    self assert:(value at: 'x') = 0.
+    self assert:(value includesKey: 'y').
+    self assert:(value at: 'y') = 1.
+
+    "Created: / 10-09-2021 / 14:52:54 / Jan Vrany <jan.vrany@labware.com>"
+!
+
+test_registers_04
+    | value |
+
+    value := (GDBMIParser on:'10') parseValue.
+    self assert:value isInteger.
+    self assert:value = 10
+
+    "Created: / 10-09-2021 / 14:56:17 / Jan Vrany <jan.vrany@labware.com>"
+! !
+
 !GDBMIParserTests methodsFor:'tests - values - typed'!
 
 test_typed_boolean