API: add `GDBDebugger >> getParameter:` and `setParameter:to:`
authorJan Vrany <jan.vrany@fit.cvut.cz>
Sat, 19 Jan 2019 23:25:55 +0000
changeset 169 a3d1f59e3bfd
parent 168 822cd61a882e
child 170 6cf990ac2cad
API: add `GDBDebugger >> getParameter:` and `setParameter:to:` ...to get / set GDB internal parameters such as prompt. The only complication here is that when a parameter is set by MI `-gdb-set` command, the `=cmd-param-changed' notification is not sent. This may or may not be a GDB bug. To make this transparent to `libgdbs` clients, intercept all `-gdb-set` commands and when sucessful, emit the event manually. This way, client may rely on value change notification (`GDBCmdParamChangedEvent`) to detect changes.
GDBCmdParamChangedEvent.st
GDBCommandResult.st
GDBCommandResultEvent.st
GDBDebugger.st
tests/GDBDebuggerTestsR.st
--- a/GDBCmdParamChangedEvent.st	Wed Jan 16 23:42:24 2019 +0000
+++ b/GDBCmdParamChangedEvent.st	Sat Jan 19 23:25:55 2019 +0000
@@ -50,6 +50,21 @@
 "
 ! !
 
+!GDBCmdParamChangedEvent class methodsFor:'instance creation'!
+
+name: name value: value
+    ^ self new  
+        propertyAt: #param put: name;
+        propertyAt: #value put: value;
+        yourself.
+
+    "
+    GDBCmdParamChangedEvent name: 'prompt' value: '>  '
+    "
+
+    "Created: / 19-01-2019 / 22:33:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !GDBCmdParamChangedEvent methodsFor:'accessing'!
 
 name
--- a/GDBCommandResult.st	Wed Jan 16 23:42:24 2019 +0000
+++ b/GDBCommandResult.st	Sat Jan 19 23:25:55 2019 +0000
@@ -117,6 +117,22 @@
     "Modified: / 30-12-2018 / 20:01:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
+!GDBCommandResult methodsFor:'printing & storing'!
+
+printOn:aStream
+    "append a printed representation of the receiver to the argument, aStream"
+
+    super printOn:aStream.
+    aStream 
+        nextPut:$(;
+        nextPutAll: status;
+        nextPutAll:': ';
+        nextPutAll: command asString;
+        nextPut:$).
+
+    "Modified: / 19-01-2019 / 22:58:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !GDBCommandResult methodsFor:'testing'!
 
 isDone
--- a/GDBCommandResultEvent.st	Wed Jan 16 23:42:24 2019 +0000
+++ b/GDBCommandResultEvent.st	Sat Jan 19 23:25:55 2019 +0000
@@ -56,8 +56,8 @@
     ^ result
 !
 
-result:something
-    result := something.
+result:aGDBCommandResult
+    result := aGDBCommandResult.
 !
 
 status
@@ -74,6 +74,22 @@
     "Created: / 01-03-2015 / 08:56:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
+!GDBCommandResultEvent methodsFor:'printing & storing'!
+
+printOn:aStream
+    "append a printed representation of the receiver to the argument, aStream"
+
+    super printOn:aStream.
+    aStream 
+        nextPut:$(;
+        nextPutAll: result status;
+        nextPutAll:': ';
+        nextPutAll: result command asString;
+        nextPut:$).
+
+    "Created: / 19-01-2019 / 22:59:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !GDBCommandResultEvent methodsFor:'testing'!
 
 isCommandResultEvent
--- a/GDBDebugger.st	Wed Jan 16 23:42:24 2019 +0000
+++ b/GDBDebugger.st	Sat Jan 19 23:25:55 2019 +0000
@@ -354,7 +354,7 @@
 
     self assert: self isConnected.
     command isString ifTrue:[
-        commandObject := (GDBMIParser on:command) parseCommand.
+        commandObject := GDBCommand parse: command.
         commandObject token:self nextCommandSequnceNumber.
     ] ifFalse:[
         commandObject := command.
@@ -368,7 +368,7 @@
         withTimeoutMs: timeout
 
     "Created: / 07-03-2015 / 11:38:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified (format): / 04-02-2018 / 00:20:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 19-01-2019 / 23:05:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 send:command andWithResultDo: block
@@ -397,7 +397,7 @@
     self assert: self isConnected.
     cmd := command.
     cmd isString ifTrue:[
-        cmd := GDBCLICommand new value:cmd.
+        cmd := GDBCommand parse:cmd.
     ].
     token := self nextCommandSequnceNumber.
     cmd token:token.
@@ -419,7 +419,7 @@
 
     "Created: / 26-01-2018 / 21:47:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 26-03-2018 / 21:48:02 / jv"
-    "Modified (comment): / 01-01-2019 / 11:31:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 19-01-2019 / 23:06:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !GDBDebugger methodsFor:'commands - API'!
@@ -594,6 +594,22 @@
     "Modified: / 09-02-2018 / 09:44:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+getParameter:name 
+    "Teturn the current value of a GDB parameter. 
+     See `show` GDB command.
+
+     Subscribe to `GDBCmdParamChangedEvent` to get notified
+     when parameter value changes.
+    "
+    
+    | result |
+
+    result := self send:(GDBMI_gdb_show arguments:(Array with:name)).
+    ^ result propertyAt:#value.
+
+    "Created: / 19-01-2019 / 21:55:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 selectFrame: aGDBFrame
     "
     Set the context frame to given frame. This frame is then
@@ -616,6 +632,20 @@
     "Created: / 01-02-2018 / 22:25:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+setParameter:name to:value 
+    "Set an internal GDB parameter named `name` to `value`.
+     See `set` GDB command.
+
+     Subscribe to `GDBCmdParamChangedEvent` to get notified
+     when parameter value changes.
+    "
+    
+    self assert:value isString.
+    self send:(GDBMI_gdb_set arguments:(Array with:name with:value)).
+
+    "Created: / 19-01-2019 / 21:56:47 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 targetConnect: type parameters: parameters
     "Connect to the remote target. `type` is the type of target, 
      for instance ‘extended-remote=’. `parameters` are device names, 
@@ -795,6 +825,29 @@
     "Modified: / 20-06-2014 / 22:09:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+onCommandResultEvent:aGDBCommandResultEvent
+    | result |
+
+    result := aGDBCommandResultEvent result.
+
+    "/ For some reason, -gdb-set MI command does not cause
+    "/ =cmd-param-changed notification. To make this transparent
+    "/ for users, catch successful -gdb-set here and send
+    "/ GDBCmdParamChangedEvent manually. Sigh, what a hack!!
+    (result isDone
+        and:[ result command notNil
+        and:[ result command isMICommand 
+        and:[ result command operation = 'gdb-set' ]]]) ifTrue:[ 
+        | event |
+
+        event := GDBCmdParamChangedEvent name: result command arguments first value: result command arguments second.
+        connection pushEvent: event.  
+    ].
+
+    "Created: / 19-01-2019 / 22:35:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 21-01-2019 / 17:53:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 onExitEvent:aGDBExitEvent 
     self release.
 
@@ -988,6 +1041,7 @@
 subscribe
     connection eventAnnouncerInternal
         when: GDBCommandEvent               send: #onCommandEvent:           to: self;
+        when: GDBCommandResultEvent         send: #onCommandResultEvent:     to: self;
         when: GDBExitEvent                  send: #onExitEvent:              to: self;
 
         when: GDBThreadGroupAddedEvent      send: #onThreadGroupAddedEvent:  to: self;
@@ -1009,7 +1063,7 @@
         when: GDBCmdParamChangedEvent       send: #onCmdParamChangedEvent:    to: self.
 
     "Created: / 20-06-2014 / 22:07:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 29-07-2018 / 22:18:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 19-01-2019 / 22:20:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 unsubscribe
--- a/tests/GDBDebuggerTestsR.st	Wed Jan 16 23:42:24 2019 +0000
+++ b/tests/GDBDebuggerTestsR.st	Sat Jan 19 23:25:55 2019 +0000
@@ -475,6 +475,37 @@
     "Modified: / 18-10-2018 / 10:56:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+test_parameters_01
+    | event |
+
+    debugger announcer when: GDBCmdParamChangedEvent do:[:ev | event := ev ].
+
+    debugger send: 'set prompt > '.
+    self assert: (debugger getParameter: 'prompt') = '> '.
+    self assert: event notNil.
+    self assert: event name = 'prompt'.
+    self assert: event value = '> '.
+
+    event := nil.
+    debugger setParameter: 'prompt' to: '$'.
+    self assert: (debugger getParameter: 'prompt') = '$'.
+    self assert: event notNil.
+    self assert: event name = 'prompt'.
+    self assert: event value = '$'.
+
+    event := nil.
+    debugger send: '-gdb-set prompt X'.
+    self assert: (debugger getParameter: 'prompt') = 'X'.
+    self assert: event notNil.
+    self assert: event name = 'prompt'.
+    self assert: event value = 'X'.
+    
+
+    debugger send: 'quit' andWait: false.
+
+    "Created: / 19-01-2019 / 22:51:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 test_registers_01a
     | stack rax rip rsp raxValue1 ripValue1 rspValue1 raxValue2 ripValue2 rspValue2 |