Fix: initialize debugger features early during initialization
The frontend or `stx:libgdbs` may need to query features to
conditionally perform some logic, however, if the target does
not support async mode (such as Windows), it would block.
The GDB documentation says:
Whenever a target can change, due to commands such as
-target-select, -target-attach or -exec-run, the list of
target features may change, and the frontend should obtain
it again.
The problem is, however, that on a target that does not support,
once `-exec-run` is issued, the inferior runs so GDB does not
accept any commands until inferior stops.
To workaround this until a better solution is found, initialize
target features on first stopped event and until initialized, use
"default natives features", a hard-coded set. Ugly, but we should
move on.
--- a/GDBConnection.st Tue Mar 27 08:50:56 2018 +0100
+++ b/GDBConnection.st Tue Mar 27 08:55:29 2018 +0100
@@ -94,6 +94,12 @@
^ inferiorPTY
!
+nativeTargetFeatures
+ ^ process nativeTargetFeatures
+
+ "Created: / 09-04-2018 / 15:40:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
recorder
^ recorder
!
--- a/GDBDebugger.st Tue Mar 27 08:50:56 2018 +0100
+++ b/GDBDebugger.st Tue Mar 27 08:55:29 2018 +0100
@@ -120,23 +120,11 @@
* https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Support-Commands.html,
command `-list-features`
"
-
- debuggerFeatures isNil ifTrue:[
- | result |
-
- result := self send: GDBMI_list_features new.
- debuggerFeatures := result propertyAt: #features.
- ].
- targetFeatures isNil ifTrue:[
- | result |
-
- result := self send: GDBMI_list_target_features new.
- targetFeatures := result propertyAt: #features.
- ].
- ^ debuggerFeatures , targetFeatures
+ ^ debuggerFeatures , (targetFeatures ? connection nativeTargetFeatures)
"Created: / 07-02-2018 / 10:50:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
- "Modified: / 07-02-2018 / 12:46:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 26-03-2018 / 21:35:22 / jv"
+ "Modified: / 09-04-2018 / 15:39:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
inferiorForId: id
@@ -281,12 +269,14 @@
cmd isString ifTrue:[
cmd := GDBCLICommand new value:cmd.
].
+ cmd token: self nextCommandSequnceNumber.
connection pushEvent:(GDBCommandEvent new command:cmd).
nil.
]
"Created: / 02-06-2014 / 23:45:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 04-02-2018 / 00:21:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 26-03-2018 / 21:19:59 / jv"
!
send:command andWaitFor:eventHandlers
@@ -382,8 +372,6 @@
].
token := self nextCommandSequnceNumber.
cmd token:token.
- self assert:Processor activeProcess ~~ connection eventDispatchProcess
- message:'Cannot send commands from within event dispatching process. Would deadlock'.
handler1 := [:ev |
ev token == token ifTrue:[
connection eventAnnouncer unsubscribe:handler1.
@@ -402,6 +390,7 @@
"Created: / 26-01-2018 / 21:47:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified (format): / 04-02-2018 / 00:20:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 26-03-2018 / 21:48:02 / jv"
! !
!GDBDebugger methodsFor:'commands - API'!
@@ -751,8 +740,14 @@
thread onStoppedEvent: aGDBStoppedEvent.
].
+ "/ Initialize target features properly
+ targetFeatures isNil ifTrue:[
+ self send: GDBMI_list_target_features new
+ andWithResultDo:[ :result | targetFeatures := result propertyAt: #features ].
+ ].
+
"Created: / 07-09-2014 / 23:34:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
- "Modified: / 12-07-2017 / 13:47:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 09-04-2018 / 15:42:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onThreadCreatedEvent:aGDBThreadCreatedEvent
@@ -771,8 +766,11 @@
inferior := self inferiorForId:aGDBThreadExitedEvent threadGroupId.
inferior onThreadExitedEvent:aGDBThreadExitedEvent.
+ "/ reset target features
+ targetFeatures := nil.
+
"Created: / 07-09-2014 / 21:20:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
- "Modified: / 18-03-2015 / 13:57:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 09-04-2018 / 15:42:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onThreadGroupAddedEvent:aGDBThreadGroupAddedEvent
@@ -784,9 +782,10 @@
inferior := GDBThreadGroup newWithDebugger:self
id:aGDBThreadGroupAddedEvent threadGroupId.
inferiors add:inferior.
- aGDBThreadGroupAddedEvent setThreadGroup:inferior
+ aGDBThreadGroupAddedEvent setThreadGroup:inferior.
- "Modified: / 07-09-2014 / 21:18:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 26-03-2018 / 21:46:51 / jv"
+ "Modified: / 09-04-2018 / 15:36:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onThreadGroupExitedEvent:aGDBThreadGroupExitedEvent
@@ -807,13 +806,10 @@
inferior := self inferiorForId:aGDBThreadGroupStartedEvent threadGroupId.
inferior setPid:aGDBThreadGroupStartedEvent pid.
aGDBThreadGroupStartedEvent setThreadGroup:inferior.
- "/ Also, we have to reset targetFeatures since we get no notification
- "/ that the target has changed. Note, that `targetFeatures` are lazily
- "/ initialized in #features.
- targetFeatures := nil
"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"
! !
!GDBDebugger methodsFor:'finalization'!
@@ -827,6 +823,8 @@
!GDBDebugger methodsFor:'initialize & release'!
initializeWithProcess: aGDBProcess
+ | result |
+
self registerForFinalization.
finalizationRegistry := Registry new.
@@ -846,12 +844,16 @@
].
self send: (GDBMI_gdb_set arguments: #('target-async' 'on')).
+ result := self send: GDBMI_list_features new.
+ debuggerFeatures := result propertyAt: #features.
+ targetFeatures := nil.
+
prettyPrintingEnabled := false.
frameFiltersEnabled := false.
"Created: / 20-06-2014 / 21:45:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
- "Modified: / 12-01-2018 / 00:13:09 / jv"
- "Modified: / 28-01-2018 / 23:19:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 26-03-2018 / 21:36:31 / jv"
+ "Modified: / 09-04-2018 / 15:38:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
release
@@ -921,6 +923,19 @@
"Created: / 07-02-2018 / 11:32:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified (comment): / 07-02-2018 / 12:44:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+hasFeatureAsync
+ "Indicates that the target is capable of asynchronous command execution, which means
+ that GDB will accept further commands while the target is running."
+
+ targetFeatures notNil ifTrue:[
+ ^ targetFeatures includes: 'async'
+ ] ifFalse:[
+ ^ connection nativeTargetFeatures includes: 'async'.
+ ].
+
+ "Created: / 09-04-2018 / 15:45:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'testing'!
--- a/GDBProcess.st Tue Mar 27 08:50:56 2018 +0100
+++ b/GDBProcess.st Tue Mar 27 08:55:29 2018 +0100
@@ -125,6 +125,12 @@
"Modified: / 15-12-2017 / 23:58:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
+nativeTargetFeatures
+ ^ self subclassResponsibility
+
+ "Created: / 09-04-2018 / 15:40:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
pid
^ pid
! !
--- a/GDBUnixProcess.st Tue Mar 27 08:50:56 2018 +0100
+++ b/GDBUnixProcess.st Tue Mar 27 08:55:29 2018 +0100
@@ -62,6 +62,12 @@
^ consolePTY master
"Created: / 02-06-2017 / 23:36:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+nativeTargetFeatures
+ ^ #('async')
+
+ "Created: / 09-04-2018 / 15:40:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBUnixProcess methodsFor:'initialization & release'!
--- a/GDBWindowsProcess.st Tue Mar 27 08:50:56 2018 +0100
+++ b/GDBWindowsProcess.st Tue Mar 27 08:55:29 2018 +0100
@@ -50,6 +50,14 @@
"
! !
+!GDBWindowsProcess methodsFor:'accessing'!
+
+nativeTargetFeatures
+ ^ #()
+
+ "Created: / 09-04-2018 / 15:41:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
!GDBWindowsProcess methodsFor:'error pump'!
errorPumpLoop