Add model for machine registers
authorJan Vrany <jan.vrany@fit.cvut.cz>
Wed, 26 Sep 2018 11:16:56 +0100
changeset 144 342b6dfe3a6f
parent 143 883c830472cb
child 145 1256a03213cf
Add model for machine registers To access machine registers and their values, a new API method `GDBFrame >> registersWithValues` is intruced in this commit.
GDBDebugger.st
GDBEventSetProcessingStarted.st
GDBFrame.st
GDBMI_data_list_changed_registers.st
GDBMI_data_list_register_values.st
GDBRegister.st
GDBRegisterWithValue.st
GDBThreadGroup.st
Make.proto
Make.spec
abbrev.stc
bc.mak
jv_libgdbs.st
libInit.cc
tests/GDBDebuggerTestsR.st
--- a/GDBDebugger.st	Wed Sep 26 13:25:40 2018 +0100
+++ b/GDBDebugger.st	Wed Sep 26 11:16:56 2018 +0100
@@ -906,12 +906,13 @@
     | inferior |
 
     inferior := self inferiorForId:aGDBThreadGroupStartedEvent threadGroupId.
+    inferior reset.
     inferior setPid:aGDBThreadGroupStartedEvent pid.
     aGDBThreadGroupStartedEvent setThreadGroup:inferior.
 
     "Created: / 06-09-2014 / 02:37:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified (comment): / 07-02-2018 / 12:50:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 26-03-2018 / 21:33:11 / jv"
+    "Modified: / 26-09-2018 / 10:57:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 onThreadSelectedEvent: aGDBThreadSelectedEvent 
--- a/GDBEventSetProcessingStarted.st	Wed Sep 26 13:25:40 2018 +0100
+++ b/GDBEventSetProcessingStarted.st	Wed Sep 26 11:16:56 2018 +0100
@@ -50,3 +50,10 @@
 "
 ! !
 
+!GDBEventSetProcessingStarted class methodsFor:'documentation'!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
+! !
+
--- a/GDBFrame.st	Wed Sep 26 13:25:40 2018 +0100
+++ b/GDBFrame.st	Wed Sep 26 11:16:56 2018 +0100
@@ -21,7 +21,8 @@
 "{ NameSpace: Smalltalk }"
 
 GDBDebuggerObject subclass:#GDBFrame
-	instanceVariableNames:'thread level addr func file fullname line arch from variables'
+	instanceVariableNames:'thread level addr func file fullname line arch from variables
+		registers registersChanges'
 	classVariableNames:''
 	poolDictionaries:''
 	category:'GDB-Core'
@@ -174,6 +175,45 @@
     ^ line
 !
 
+registers
+    "Return a list of mchine registers and their correcponsing
+     values in this frame (as list of GDBRegisterWithValue)"
+
+    registers isNil ifTrue:[
+        | registersSet result |
+
+        "/ First, retrieve a list of register available in this
+        "/ frame.
+        "/
+        "/ To reduce MI communication overhead, registers are cached
+        "/ in shared cache kept in process group (inferior). Caching is 
+        "/ based on an assumption that while each frame may have different 
+        "/ architecture, it is unlikely that  different frames with same 
+        "/ architecture would have different set of registers.
+        registersSet := self thread group registersMap at: self arch ifAbsentPut:[ 
+            result := debugger send: (GDBMI_data_list_register_names arguments: (Array with: '--thread' with: self thread id with: '--frame' with: self level)).
+            registersSet := Dictionary new.
+            (result propertyAt: 'register-names') withIndexDo:[ :name :number | 
+                name notEmpty ifTrue:[
+                    "/ Note, that GDB register indices starts with 0 (zero) like in C!!
+                    registersSet at: number - 1 put: (GDBRegister new setNumber: number - 1; setName: name)
+                ].
+            ].
+            registersSet
+        ].
+
+        "/ Second, fetch values and populate a collection of registers (as `GDBRegisterWithValue`). This is done
+        "/ onlt once, later on, the value of registers is updated automagically (see `GDBRegisterWithValue >> value`).
+        result := debugger send: (GDBMI_data_list_register_values new arguments: (Array with: '--thread' with: thread id with: '--frame' with: level with: 'r')).
+        registers := result propertyAt: #'register-values'.
+        registers do:[:value | value setFrame: self; setRegisterFrom: registersSet ].
+    ].
+    ^ registers value
+
+    "Created: / 26-09-2018 / 09:51:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 27-09-2018 / 11:17:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 thread
     ^ thread
 !
@@ -292,6 +332,38 @@
     "Modified: / 27-02-2015 / 15:21:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
+!GDBFrame methodsFor:'private'!
+
+registersChanges
+    registersChanges isNil ifTrue:[ 
+        self isValid ifTrue:[
+            registersChanges := GDBTransientDataHolder debugger: debugger factory: [ :old |
+                old isNil ifTrue:[ 
+                    #()
+                ] ifFalse:[
+                    | result changed |
+
+                    result := debugger send: (GDBMI_data_list_changed_registers new arguments: (Array with: '--thread' with: thread id with: '--frame' with: level)).
+                    changed := result propertyAt: #'changed-registers'.
+
+                    changed notEmptyOrNil ifTrue:[ 
+                        result := debugger send: (GDBMI_data_list_register_values new arguments: (Array with: '--thread' with: thread id with: '--frame' with: level with: 'r') , changed).
+                        (result propertyAt: #'register-values') asSet.
+                    ] ifFalse:[ 
+                        #()
+                    ].
+                ].
+            ].
+        ] ifFalse:[ 
+            registersChanges := #().
+        ].
+    ].
+    ^ registersChanges value
+
+    "Created: / 26-09-2018 / 22:35:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 27-09-2018 / 10:18:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !GDBFrame methodsFor:'testing'!
 
 isValid
--- a/GDBMI_data_list_changed_registers.st	Wed Sep 26 13:25:40 2018 +0100
+++ b/GDBMI_data_list_changed_registers.st	Wed Sep 26 11:16:56 2018 +0100
@@ -98,6 +98,17 @@
 	^ 'data-list-changed-registers'
 ! !
 
+!GDBMI_data_list_changed_registers methodsFor:'accessing-descriptors'!
+
+resultDescription
+    ^ (super resultDescription)
+        define:#'changed-registers' as:Array of: Integer; 
+        yourself
+
+    "Created: / 26-09-2018 / 10:37:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 26-09-2018 / 22:34:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !GDBMI_data_list_changed_registers class methodsFor:'documentation'!
 
 version_HG
--- a/GDBMI_data_list_register_values.st	Wed Sep 26 13:25:40 2018 +0100
+++ b/GDBMI_data_list_register_values.st	Wed Sep 26 11:16:56 2018 +0100
@@ -154,6 +154,16 @@
 	^ 'data-list-register-values'
 ! !
 
+!GDBMI_data_list_register_values methodsFor:'accessing-descriptors'!
+
+resultDescription
+    ^ (super resultDescription)
+        define:#'register-values' as:Array of:GDBRegisterWithValue; 
+        yourself
+
+    "Created: / 26-09-2018 / 10:37:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !GDBMI_data_list_register_values class methodsFor:'documentation'!
 
 version_HG
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GDBRegister.st	Wed Sep 26 11:16:56 2018 +0100
@@ -0,0 +1,112 @@
+"
+jv:libgdbs - GNU Debugger Interface Library
+Copyright (C) 2015-now Jan Vrany
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License. 
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+"
+"{ Package: 'jv:libgdbs' }"
+
+"{ NameSpace: Smalltalk }"
+
+GDBObject subclass:#GDBRegister
+	instanceVariableNames:'number name'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'GDB-Core'
+!
+
+!GDBRegister class methodsFor:'documentation'!
+
+copyright
+"
+jv:libgdbs - GNU Debugger Interface Library
+Copyright (C) 2015-now Jan Vrany
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License. 
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+"
+!
+
+documentation
+"
+    a `GDBRegister` instance represent a single machine 
+    register. 
+
+    It does not hold a value - value is held in 
+    `GDBRegisterWithValue`
+
+
+    [author:]
+        Jan Vrany <jan.vrany@fit.cvut.cz>
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+        GDNRegisterWithValue
+        GDBFrame >> registers
+
+"
+! !
+
+!GDBRegister methodsFor:'accessing'!
+
+name
+    ^ name
+!
+
+number
+    ^ number
+! !
+
+!GDBRegister methodsFor:'initialization'!
+
+setName: aString
+    name := aString
+
+    "Created: / 26-09-2018 / 10:06:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+setNumber: aNumber
+    number := aNumber
+
+    "Created: / 26-09-2018 / 10:06:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBRegister methodsFor:'printing & storing'!
+
+printOn:aStream
+    "append a printed representation of the receiver to the argument, aStream"
+
+    super printOn:aStream.
+    aStream nextPut:$(.
+    name printOn:aStream.
+    aStream nextPut:$).
+
+    "Modified: / 26-09-2018 / 10:10:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GDBRegisterWithValue.st	Wed Sep 26 11:16:56 2018 +0100
@@ -0,0 +1,174 @@
+"
+jv:libgdbs - GNU Debugger Interface Library
+Copyright (C) 2015-now Jan Vrany
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License. 
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+"
+"{ Package: 'jv:libgdbs' }"
+
+"{ NameSpace: Smalltalk }"
+
+GDBDebuggerObject subclass:#GDBRegisterWithValue
+	instanceVariableNames:'register frame value changed'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'GDB-Core'
+!
+
+!GDBRegisterWithValue class methodsFor:'documentation'!
+
+copyright
+"
+jv:libgdbs - GNU Debugger Interface Library
+Copyright (C) 2015-now Jan Vrany
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License. 
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+"
+! !
+
+!GDBRegisterWithValue class methodsFor:'accessing-magritte'!
+
+descriptionContainer
+    ^ super descriptionContainer
+        define: #number as: Integer;
+        define: #value as: String;
+        yourself
+
+    "Created: / 26-09-2018 / 10:38:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBRegisterWithValue methodsFor:'accessing'!
+
+name
+    ^  register name
+
+    "Created: / 27-09-2018 / 10:06:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+number
+    ^ register isInteger ifTrue:[
+        register
+    ] ifFalse:[
+        register number
+    ]
+
+    "Created: / 27-09-2018 / 09:56:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+value
+    changed value.
+    ^ value
+
+    "Modified: / 27-09-2018 / 15:26:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBRegisterWithValue methodsFor:'initialization'!
+
+setDebugger: aGDBDebugger
+    super setDebugger: aGDBDebugger.
+    changed := GDBTransientDataHolder debugger: debugger factory: [
+        (frame notNil and:[frame isValid]) ifTrue:[
+            | changes change |
+
+            changes := frame registersChanges.
+            change := changes detect:[:each | each number = self number ] ifNone:[ nil ].
+            (change notNil and:[change value ~= value]) ifTrue:[ 
+                value := change value.
+                true
+            ] ifFalse:[ 
+                false
+            ].
+        ] ifFalse:[ 
+            false
+        ].
+    ].
+
+    "Created: / 27-09-2018 / 15:11:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+setFrame: aGDBFrame
+    self setDebugger: aGDBFrame debugger.
+    frame := aGDBFrame.
+
+    "Created: / 26-09-2018 / 22:25:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 27-09-2018 / 15:31:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+setRegisterFrom: aDictionary
+    self assert: register isInteger.
+    self assert: (aDictionary includesKey: register).
+
+    register := aDictionary at: register.
+
+    "Created: / 26-09-2018 / 10:41:47 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBRegisterWithValue methodsFor:'printing & storing'!
+
+printOn:aStream
+    "append a printed representation of the receiver to the argument, aStream"
+
+    super printOn:aStream.
+    aStream nextPut:$(.
+    register isInteger ifTrue:[
+        register printOn:aStream.
+    ] ifFalse:[ 
+        register name printOn:aStream.    
+    ].
+    aStream nextPutAll: ': '.
+    value printOn: aStream.
+    aStream nextPut:$).
+
+    "Modified: / 26-09-2018 / 10:48:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBRegisterWithValue methodsFor:'private'!
+
+_number: anInteger
+    register := anInteger
+
+    "Created: / 26-09-2018 / 10:39:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBRegisterWithValue methodsFor:'queries'!
+
+hasChanged
+    "Return true, if the value of this register has changed since last
+     'stop', false otherwise (i.e., when unchanged)"
+
+    ^ changed value
+
+    "Created: / 27-09-2018 / 16:01:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!GDBRegisterWithValue class methodsFor:'documentation'!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
+! !
+
--- a/GDBThreadGroup.st	Wed Sep 26 13:25:40 2018 +0100
+++ b/GDBThreadGroup.st	Wed Sep 26 11:16:56 2018 +0100
@@ -23,7 +23,7 @@
 "{ NameSpace: Smalltalk }"
 
 GDBDebuggerObject subclass:#GDBThreadGroup
-	instanceVariableNames:'id type executable running pid exit_code threads'
+	instanceVariableNames:'id type executable running pid exit_code threads registersMap'
 	classVariableNames:'ExecutableSentinel'
 	poolDictionaries:'GDBCommandStatus'
 	category:'GDB-Core'
@@ -227,8 +227,19 @@
     "Invoked when a new instance is created."
 
     running := false.
+    registersMap := Dictionary new.
 
-    "Modified: / 06-06-2017 / 00:25:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 26-09-2018 / 09:53:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+reset
+    "Reset all internal caches. Invoked bu debugger when an inferior
+     starts. This is necessary since GDB recycles inferors and so we
+     do."
+
+    registersMap := Dictionary new.
+
+    "Created: / 26-09-2018 / 10:58:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 setExitCode: anInteger
@@ -273,6 +284,12 @@
 
 !GDBThreadGroup methodsFor:'private'!
 
+registersMap
+    ^ registersMap
+
+    "Created: / 26-09-2018 / 10:01:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 threadAdd: aGDBThread
     self threads add: aGDBThread
 
--- a/Make.proto	Wed Sep 26 13:25:40 2018 +0100
+++ b/Make.proto	Wed Sep 26 11:16:56 2018 +0100
@@ -172,6 +172,7 @@
 $(OUTDIR)GDBMITracer.$(O) GDBMITracer.$(C) GDBMITracer.$(H): GDBMITracer.st $(INCLUDE_TOP)/jv/libgdbs/GDBDebugFlags.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBMemoryDump.$(O) GDBMemoryDump.$(C) GDBMemoryDump.$(H): GDBMemoryDump.st $(INCLUDE_TOP)/jv/libgdbs/GDBObject.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBMemoryDumpRow.$(O) GDBMemoryDumpRow.$(C) GDBMemoryDumpRow.$(H): GDBMemoryDumpRow.st $(INCLUDE_TOP)/jv/libgdbs/GDBObject.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
+$(OUTDIR)GDBRegister.$(O) GDBRegister.$(C) GDBRegister.$(H): GDBRegister.st $(INCLUDE_TOP)/jv/libgdbs/GDBObject.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBStreamOutputEvent.$(O) GDBStreamOutputEvent.$(C) GDBStreamOutputEvent.$(H): GDBStreamOutputEvent.st $(INCLUDE_TOP)/jv/libgdbs/GDBEvent.$(H) $(INCLUDE_TOP)/stx/goodies/announcements/Announcement.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBThreadGroupTypeProcess.$(O) GDBThreadGroupTypeProcess.$(C) GDBThreadGroupTypeProcess.$(H): GDBThreadGroupTypeProcess.st $(INCLUDE_TOP)/jv/libgdbs/GDBThreadGroupType.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBThreadInfo.$(O) GDBThreadInfo.$(C) GDBThreadInfo.$(H): GDBThreadInfo.st $(INCLUDE_TOP)/jv/libgdbs/GDBObject.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
@@ -301,6 +302,7 @@
 $(OUTDIR)GDBMI_var_show_format.$(O) GDBMI_var_show_format.$(C) GDBMI_var_show_format.$(H): GDBMI_var_show_format.st $(INCLUDE_TOP)/jv/libgdbs/GDBCommand.$(H) $(INCLUDE_TOP)/jv/libgdbs/GDBMICommand.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBMI_var_update.$(O) GDBMI_var_update.$(C) GDBMI_var_update.$(H): GDBMI_var_update.st $(INCLUDE_TOP)/jv/libgdbs/GDBCommand.$(H) $(INCLUDE_TOP)/jv/libgdbs/GDBMICommand.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBNotificationEvent.$(O) GDBNotificationEvent.$(C) GDBNotificationEvent.$(H): GDBNotificationEvent.st $(INCLUDE_TOP)/jv/libgdbs/GDBAsyncEvent.$(H) $(INCLUDE_TOP)/jv/libgdbs/GDBEvent.$(H) $(INCLUDE_TOP)/stx/goodies/announcements/Announcement.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
+$(OUTDIR)GDBRegisterWithValue.$(O) GDBRegisterWithValue.$(C) GDBRegisterWithValue.$(H): GDBRegisterWithValue.st $(INCLUDE_TOP)/jv/libgdbs/GDBDebuggerObject.$(H) $(INCLUDE_TOP)/jv/libgdbs/GDBObject.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBSelectedFrameChangedEvent.$(O) GDBSelectedFrameChangedEvent.$(C) GDBSelectedFrameChangedEvent.$(H): GDBSelectedFrameChangedEvent.st $(INCLUDE_TOP)/jv/libgdbs/GDBEvent.$(H) $(INCLUDE_TOP)/jv/libgdbs/GDBInternalEvent.$(H) $(INCLUDE_TOP)/stx/goodies/announcements/Announcement.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBStatusEvent.$(O) GDBStatusEvent.$(C) GDBStatusEvent.$(H): GDBStatusEvent.st $(INCLUDE_TOP)/jv/libgdbs/GDBAsyncEvent.$(H) $(INCLUDE_TOP)/jv/libgdbs/GDBEvent.$(H) $(INCLUDE_TOP)/stx/goodies/announcements/Announcement.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)GDBTargetOutputEvent.$(O) GDBTargetOutputEvent.$(C) GDBTargetOutputEvent.$(H): GDBTargetOutputEvent.st $(INCLUDE_TOP)/jv/libgdbs/GDBEvent.$(H) $(INCLUDE_TOP)/jv/libgdbs/GDBStreamOutputEvent.$(H) $(INCLUDE_TOP)/stx/goodies/announcements/Announcement.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
--- a/Make.spec	Wed Sep 26 13:25:40 2018 +0100
+++ b/Make.spec	Wed Sep 26 11:16:56 2018 +0100
@@ -96,6 +96,7 @@
 	GDBMITracer \
 	GDBMemoryDump \
 	GDBMemoryDumpRow \
+	GDBRegister \
 	GDBStreamOutputEvent \
 	GDBThreadGroupTypeProcess \
 	GDBThreadInfo \
@@ -225,6 +226,7 @@
 	GDBMI_var_show_format \
 	GDBMI_var_update \
 	GDBNotificationEvent \
+	GDBRegisterWithValue \
 	GDBSelectedFrameChangedEvent \
 	GDBStatusEvent \
 	GDBTargetOutputEvent \
@@ -304,6 +306,7 @@
     $(OUTDIR)GDBMITracer.$(O) \
     $(OUTDIR)GDBMemoryDump.$(O) \
     $(OUTDIR)GDBMemoryDumpRow.$(O) \
+    $(OUTDIR)GDBRegister.$(O) \
     $(OUTDIR)GDBStreamOutputEvent.$(O) \
     $(OUTDIR)GDBThreadGroupTypeProcess.$(O) \
     $(OUTDIR)GDBThreadInfo.$(O) \
@@ -433,6 +436,7 @@
     $(OUTDIR)GDBMI_var_show_format.$(O) \
     $(OUTDIR)GDBMI_var_update.$(O) \
     $(OUTDIR)GDBNotificationEvent.$(O) \
+    $(OUTDIR)GDBRegisterWithValue.$(O) \
     $(OUTDIR)GDBSelectedFrameChangedEvent.$(O) \
     $(OUTDIR)GDBStatusEvent.$(O) \
     $(OUTDIR)GDBTargetOutputEvent.$(O) \
--- a/abbrev.stc	Wed Sep 26 13:25:40 2018 +0100
+++ b/abbrev.stc	Wed Sep 26 11:16:56 2018 +0100
@@ -46,6 +46,8 @@
 GDBMITracer GDBMITracer jv:libgdbs 'GDB-Private-MI Trace' 0
 GDBMemoryDump GDBMemoryDump jv:libgdbs 'GDB-Core' 0
 GDBMemoryDumpRow GDBMemoryDumpRow jv:libgdbs 'GDB-Core' 0
+GDBRegister GDBRegister jv:libgdbs 'GDB-Core' 0
+GDBRegisterWithValue GDBRegisterWithValue jv:libgdbs 'GDB-Core' 0
 GDBStreamOutputEvent GDBStreamOutputEvent jv:libgdbs 'GDB-Core-Events' 0
 GDBThreadGroupTypeProcess GDBThreadGroupTypeProcess jv:libgdbs 'GDB-Core' 1
 GDBThreadInfo GDBThreadInfo jv:libgdbs 'GDB-Private' 0
--- a/bc.mak	Wed Sep 26 13:25:40 2018 +0100
+++ b/bc.mak	Wed Sep 26 11:16:56 2018 +0100
@@ -119,6 +119,7 @@
 $(OUTDIR)GDBMITracer.$(O) GDBMITracer.$(C) GDBMITracer.$(H): GDBMITracer.st $(INCLUDE_TOP)\jv\libgdbs\GDBDebugFlags.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBMemoryDump.$(O) GDBMemoryDump.$(C) GDBMemoryDump.$(H): GDBMemoryDump.st $(INCLUDE_TOP)\jv\libgdbs\GDBObject.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBMemoryDumpRow.$(O) GDBMemoryDumpRow.$(C) GDBMemoryDumpRow.$(H): GDBMemoryDumpRow.st $(INCLUDE_TOP)\jv\libgdbs\GDBObject.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
+$(OUTDIR)GDBRegister.$(O) GDBRegister.$(C) GDBRegister.$(H): GDBRegister.st $(INCLUDE_TOP)\jv\libgdbs\GDBObject.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBStreamOutputEvent.$(O) GDBStreamOutputEvent.$(C) GDBStreamOutputEvent.$(H): GDBStreamOutputEvent.st $(INCLUDE_TOP)\jv\libgdbs\GDBEvent.$(H) $(INCLUDE_TOP)\stx\goodies\announcements\Announcement.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBThreadGroupTypeProcess.$(O) GDBThreadGroupTypeProcess.$(C) GDBThreadGroupTypeProcess.$(H): GDBThreadGroupTypeProcess.st $(INCLUDE_TOP)\jv\libgdbs\GDBThreadGroupType.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBThreadInfo.$(O) GDBThreadInfo.$(C) GDBThreadInfo.$(H): GDBThreadInfo.st $(INCLUDE_TOP)\jv\libgdbs\GDBObject.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
@@ -248,6 +249,7 @@
 $(OUTDIR)GDBMI_var_show_format.$(O) GDBMI_var_show_format.$(C) GDBMI_var_show_format.$(H): GDBMI_var_show_format.st $(INCLUDE_TOP)\jv\libgdbs\GDBCommand.$(H) $(INCLUDE_TOP)\jv\libgdbs\GDBMICommand.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBMI_var_update.$(O) GDBMI_var_update.$(C) GDBMI_var_update.$(H): GDBMI_var_update.st $(INCLUDE_TOP)\jv\libgdbs\GDBCommand.$(H) $(INCLUDE_TOP)\jv\libgdbs\GDBMICommand.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBNotificationEvent.$(O) GDBNotificationEvent.$(C) GDBNotificationEvent.$(H): GDBNotificationEvent.st $(INCLUDE_TOP)\jv\libgdbs\GDBAsyncEvent.$(H) $(INCLUDE_TOP)\jv\libgdbs\GDBEvent.$(H) $(INCLUDE_TOP)\stx\goodies\announcements\Announcement.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
+$(OUTDIR)GDBRegisterWithValue.$(O) GDBRegisterWithValue.$(C) GDBRegisterWithValue.$(H): GDBRegisterWithValue.st $(INCLUDE_TOP)\jv\libgdbs\GDBDebuggerObject.$(H) $(INCLUDE_TOP)\jv\libgdbs\GDBObject.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBSelectedFrameChangedEvent.$(O) GDBSelectedFrameChangedEvent.$(C) GDBSelectedFrameChangedEvent.$(H): GDBSelectedFrameChangedEvent.st $(INCLUDE_TOP)\jv\libgdbs\GDBEvent.$(H) $(INCLUDE_TOP)\jv\libgdbs\GDBInternalEvent.$(H) $(INCLUDE_TOP)\stx\goodies\announcements\Announcement.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBStatusEvent.$(O) GDBStatusEvent.$(C) GDBStatusEvent.$(H): GDBStatusEvent.st $(INCLUDE_TOP)\jv\libgdbs\GDBAsyncEvent.$(H) $(INCLUDE_TOP)\jv\libgdbs\GDBEvent.$(H) $(INCLUDE_TOP)\stx\goodies\announcements\Announcement.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)GDBTargetOutputEvent.$(O) GDBTargetOutputEvent.$(C) GDBTargetOutputEvent.$(H): GDBTargetOutputEvent.st $(INCLUDE_TOP)\jv\libgdbs\GDBEvent.$(H) $(INCLUDE_TOP)\jv\libgdbs\GDBStreamOutputEvent.$(H) $(INCLUDE_TOP)\stx\goodies\announcements\Announcement.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
--- a/jv_libgdbs.st	Wed Sep 26 13:25:40 2018 +0100
+++ b/jv_libgdbs.st	Wed Sep 26 11:16:56 2018 +0100
@@ -161,6 +161,8 @@
         GDBMITracer
         GDBMemoryDump
         GDBMemoryDumpRow
+        GDBRegister
+        GDBRegisterWithValue
         GDBStreamOutputEvent
         GDBThreadGroupTypeProcess
         GDBThreadInfo
--- a/libInit.cc	Wed Sep 26 13:25:40 2018 +0100
+++ b/libInit.cc	Wed Sep 26 11:16:56 2018 +0100
@@ -61,6 +61,7 @@
 extern void _GDBMITracer_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBMemoryDump_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBMemoryDumpRow_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
+extern void _GDBRegister_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBStreamOutputEvent_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBThreadGroupTypeProcess_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBThreadInfo_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
@@ -190,6 +191,7 @@
 extern void _GDBMI_137var_137show_137format_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBMI_137var_137update_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBNotificationEvent_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
+extern void _GDBRegisterWithValue_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBSelectedFrameChangedEvent_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBStatusEvent_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _GDBTargetOutputEvent_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
@@ -278,6 +280,7 @@
     _GDBMITracer_Init(pass,__pRT__,snd);
     _GDBMemoryDump_Init(pass,__pRT__,snd);
     _GDBMemoryDumpRow_Init(pass,__pRT__,snd);
+    _GDBRegister_Init(pass,__pRT__,snd);
     _GDBStreamOutputEvent_Init(pass,__pRT__,snd);
     _GDBThreadGroupTypeProcess_Init(pass,__pRT__,snd);
     _GDBThreadInfo_Init(pass,__pRT__,snd);
@@ -407,6 +410,7 @@
     _GDBMI_137var_137show_137format_Init(pass,__pRT__,snd);
     _GDBMI_137var_137update_Init(pass,__pRT__,snd);
     _GDBNotificationEvent_Init(pass,__pRT__,snd);
+    _GDBRegisterWithValue_Init(pass,__pRT__,snd);
     _GDBSelectedFrameChangedEvent_Init(pass,__pRT__,snd);
     _GDBStatusEvent_Init(pass,__pRT__,snd);
     _GDBTargetOutputEvent_Init(pass,__pRT__,snd);
--- a/tests/GDBDebuggerTestsR.st	Wed Sep 26 13:25:40 2018 +0100
+++ b/tests/GDBDebuggerTestsR.st	Wed Sep 26 11:16:56 2018 +0100
@@ -450,6 +450,59 @@
     "Created: / 07-02-2018 / 10:56:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+test_registers_01a
+    | stack rax rip rsp raxValue1 ripValue1 rspValue1 raxValue2 ripValue2 rspValue2 |
+
+    debugger := GDBDebugger new.
+    self assert: debugger isConnected.
+    debugger executable: GDBDebuggeesResource current binaryFactorial1.
+    debugger send: 'b factorial'.
+    debugger send: 'r' andWaitFor: GDBStoppedEvent.
+    debugger send: 'c' andWaitFor: GDBStoppedEvent.
+
+    stack := debugger selectedInferior threads first stack.
+    self assert: stack size == 3.
+
+    self skipIf: (stack first arch name ~= 'x86_64') description: 'not supported on this architecture'.
+
+    rax := stack first registers detect:[:reg | reg name = 'rax' ].
+    rip := stack first registers detect:[:reg | reg name = 'rip' ].
+    rsp := stack first registers detect:[:reg | reg name = 'rsp' ].
+
+    self assert: rax hasChanged not.
+    self assert: rip hasChanged not.
+    self assert: rsp hasChanged not.
+
+    raxValue1 := rax value.
+    ripValue1 := rip value.
+    rspValue1 := rsp value.
+
+    debugger send: 'stepi' andWaitFor: GDBStoppedEvent.    
+    debugger send: 'stepi' andWaitFor: GDBStoppedEvent.    
+    debugger send: 'stepi' andWaitFor: GDBStoppedEvent.    
+    debugger send: 'stepi' andWaitFor: GDBStoppedEvent.    
+
+    raxValue2 := rax value.
+    ripValue2 := rip value.
+    rspValue2 := rsp value.
+
+    self assert: raxValue1 ~= raxValue2.
+    self assert: ripValue1 ~= ripValue2.
+    self assert: rspValue1 = rspValue2.
+
+    self assert: rax hasChanged.
+    self assert: rip hasChanged.
+    self assert: rsp hasChanged not.
+
+
+    debugger send: 'd'.
+    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
+    debugger send: 'quit' andWait: false.
+
+    "Created: / 27-09-2018 / 10:45:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 27-09-2018 / 16:02:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 test_stack_01a
     "Tests that stack frames object are preserved amonh run/stop cycles
      if they 're still valid"