Resurected old `GDBProcess` implementation using pipes
...as `GDBPipedProcess`. This one whould wotk on both Linux
and Windows as it does not use PTYs.
"
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 }"
Object subclass:#GDBDebugger
instanceVariableNames:'connection commandSequenceNumber inferiorStateSequenceNumber
inferiors breakpoints selectedInferior selectedThread
selectedFrame prettyPrintingEnabled frameFiltersEnabled'
classVariableNames:''
poolDictionaries:'GDBCommandStatus'
category:'GDB-Core'
!
!GDBDebugger 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
"
! !
!GDBDebugger class methodsFor:'instance creation'!
new
^ self newWithProcess: GDBProcess new
"Modified: / 12-12-2017 / 21:15:24 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
newWithProcess: aGDBProcess
^ self basicNew initializeWithProcess: aGDBProcess
"Created: / 20-06-2014 / 21:44:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'accessing'!
announcer
^ connection eventAnnouncer.
"Created: / 02-06-2014 / 23:06:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
breakpoints
breakpoints isNil ifTrue:[
breakpoints := List new.
].
^ breakpoints
"Created: / 06-07-2017 / 16:06:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
consoleInput
^ connection consoleInput
"Created: / 31-05-2017 / 23:20:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 02-06-2017 / 23:13:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
consoleOutput
^ connection consoleOutput
"Created: / 31-05-2017 / 23:20:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 02-06-2017 / 23:13:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
inferiorForId: id
^ inferiors ? #() detect:[:e | e id = id ] ifNone:[
self error: ('No inferior (thread group) with id ''%1'' found!!' bindWith: id)
].
"Created: / 07-09-2014 / 21:22:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
inferiorStderr
^ connection inferiorPTY master
"Created: / 09-06-2014 / 10:01:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 09-06-2014 / 18:26:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
inferiorStdin
^ connection inferiorPTY master
"Created: / 09-06-2014 / 10:00:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 09-06-2014 / 18:27:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
inferiorStdout
^ connection inferiorPTY master
"Created: / 09-06-2014 / 10:01:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 09-06-2014 / 18:27:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
inferiors
^ inferiors ? #()
"Modified: / 06-07-2017 / 16:06:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
selectedInferior
selectedInferior isNil ifTrue:[
inferiors size == 1 ifTrue:[
^ inferiors anElement.
].
].
^ selectedInferior
"Created: / 07-09-2014 / 23:02:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'accessing-private'!
currentInferiorStateSequnceNumber
^ inferiorStateSequenceNumber
"Created: / 19-06-2014 / 22:22:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
nextCommandSequnceNumber
commandSequenceNumber := commandSequenceNumber + 1.
commandSequenceNumber == SmallInteger maxVal ifTrue:[
commandSequenceNumber := 0.
].
^ commandSequenceNumber
"Created: / 02-06-2014 / 23:48:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
nextInferiorStateSequnceNumber
inferiorStateSequenceNumber := inferiorStateSequenceNumber + 1.
inferiorStateSequenceNumber == SmallInteger maxVal ifTrue:[
inferiorStateSequenceNumber := 0.
].
^ inferiorStateSequenceNumber
"Created: / 02-06-2014 / 23:48:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'commands'!
send: command
"Execute given `command` and wait until it finishes and return its result.
`command` may be either a GDBCommand or string, in which case it will
be parsed into a GDBCommand.
"
^ self send:command andWait:true.
"Created: / 03-06-2014 / 00:10:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified (comment): / 08-03-2015 / 05:50:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
send:command andWait:wait
"Sends given `command` to GDB. If `wait` is true, wait for
command to finish and return the command result.
Otherwise, return nil immediately.
If `wait` is true and if command results in an error GDBError
is thrown.
`command` may be either a GDBCommand or string, in which case it will
be parsed into a GDBCommand.
"
| cmd token blocker handler1 handler2 result |
cmd := command.
cmd isString ifTrue:[
cmd := GDBCLICommand new value:cmd.
].
token := self nextCommandSequnceNumber.
cmd token:token.
^ wait ifTrue:[
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.
result := ev result.
connection eventAnnouncerInternal when:GDBEventSetProcessingFinished
do:handler2.
]
].
handler2 := [:ev |
connection eventAnnouncerInternal unsubscribe:handler2.
blocker signal.
].
blocker := Semaphore new.
connection eventAnnouncer when:GDBCommandResultEvent do:handler1.
connection pushEvent:(GDBCommandEvent new command:cmd).
blocker wait.
result isError ifTrue:[
GDBCommandFailedError raiseForResult: result.
].
result.
]
ifFalse:[
connection pushEvent:(GDBCommandEvent new command:cmd).
nil.
]
"Created: / 02-06-2014 / 23:45:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 13-09-2017 / 14:46:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
send:command andWaitFor:eventHandlers
"Sends given `command` to GDB and then wait for events mathing
`eventHandlers`.
Params:
`command` may be either a GDBCommand or string, in which case it will
be parsed into a GDBCommand.
`eventHandler` may be either nil or event class or one arg block or collection
of event classes or blocks.
- If nil then do not wait for anything (use nil for async send)
- If event class, then wait for an event of that class. Note, that
subclasses are handled too.
- If block, then wait for an event for which the block returns true.
- If collectio, then wait for a sequence of events, each matched as above.
Returns: a matching event or events (in case a collection of handlers has been passes)"
^ self send: command andWaitFor: eventHandlers withTimeoutMs: nil
"Created: / 08-03-2015 / 06:03:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
send:command andWaitFor:eventHandlers withTimeoutMs:timeout
"Sends given `command` to GDB and then wait for events mathing
`eventHandlers`. Raise a TimeoutError if expected events don't arrive
in specified time.
Params:
`command` may be either a GDBCommand or string, in which case it will
be parsed into a GDBCommand.
`eventHandler` may be either nil or event class or one arg block or collection
of event classes or blocks.
- If nil then do not wait for anything (use nil for async send)
- If event class, then wait for an event of that class. Note, that
subclasses are handled too.
- If block, then wait for an event for which the block returns true.
- If collectio, then wait for a sequence of events, each matched as above.
`timeout` wait at most that much milliseconds, throw TimeoutError otherwise. If `timeout` == mil
then wait for indefinitly
Returns: a matching event or events (in case a collection of handlers has been passes)"
| commandObject |
command isString ifTrue:[
commandObject := (GDBMIParser on:command) parseCommand.
commandObject token:self nextCommandSequnceNumber.
] ifFalse:[
commandObject := command.
commandObject token isNil ifTrue:[
commandObject token:self nextCommandSequnceNumber.
].
].
^ self
do:[ connection pushEvent:(GDBCommandEvent new command: commandObject) ]
andWaitFor: eventHandlers
withTimeoutMs: timeout
"Created: / 07-03-2015 / 11:38:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 08-03-2015 / 07:31:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'commands - API'!
attach: aStringOrInteger
"Attach to a running process.
API equivalent to CLI command:
(gdb) attach <aStringOrInteger>
"
self send:(GDBMI_target_attach arguments:(Array with: aStringOrInteger asString)) andWait: true.
"Created: / 05-06-2017 / 17:08:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 17-11-2017 / 20:23:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
enableFrameFilters
"Enables frame filters & frame decorators for MI interface. Once enabled,
cannot be turned off.
@see GDBMI_enable_frame_filters"
| result |
result := self send: GDBMI_enable_frame_filters new.
result isDone ifTrue:[
frameFiltersEnabled := true.
] ifFalse:[
GDBError raiseErrorString: 'failed to enable frame filters'
].
"Created: / 12-06-2017 / 09:29:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
enablePrettyPrinting
"Enables pretty printing for MI interface. Once enabled,
cannot be turned off.
@see GDBMI_enable_pretty_printing"
| result |
result := self send: GDBMI_enable_pretty_printing new.
result isDone ifTrue:[
prettyPrintingEnabled := true.
] ifFalse:[
GDBError raiseErrorString: 'failed to enable pretty printing'
].
"Created: / 12-06-2017 / 09:29:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
executable: aStringOrFilename
"Sets the executable to debug.
API equivalent to CLI command:
(gdb) exec-file <aStringOrFilename>
"
self executable: aStringOrFilename arguments: nil
"Created: / 28-02-2015 / 00:19:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 05-06-2017 / 17:06:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
executable: aStringOrFilename arguments: anArray"of String"
"Sets the executable to debug and argument to pass to it.
API equivalent to CLI command:
(gdb) exec-file <aStringOrFilename>
(gdb) set args <anArray>
"
self send:(GDBMI_file_exec_and_symbols arguments: (Array with: aStringOrFilename asString)) andWait: true.
anArray notEmptyOrNil ifTrue:[
self send: (GDBMI_exec_arguments arguments: anArray) andWait: true.
].
"Created: / 05-06-2017 / 17:05:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 17-11-2017 / 20:22:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'evaluating'!
do: block andWaitFor:eventHandlers
"Evaluates a given block and then wait for events.
`eventHandlers`.
Params:
`block` block to evaluate
`eventHandler` may be either nil or event class or one arg block or collection
of event classes or blocks.
- If nil then do not wait for anything (use nil for async send)
- If event class, then wait for an event of that class. Note, that
subclasses are handled too.
- If block, then wait for an event for which the block returns true.
- If collection, then wait for a sequence of events, each matched as above.
Returns: a matching event or events (in case a collection of handlers has been passed)"
^ self do: block andWaitFor: eventHandlers withTimeoutMs: nil
"Created: / 08-03-2015 / 07:30:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified (comment): / 12-06-2017 / 09:31:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
do: block andWaitFor:eventHandlers withTimeoutMs:timeout
"Evaluates a given block and then wait for events.
`eventHandlers`. Raise a TimeoutError if expected events don't arrive
in specified time.
Params:
`block` block to evaluate
`eventHandler` may be either nil or event class or one arg block or collection
of event classes or blocks.
- If nil then do not wait for anything (use nil for async send)
- If event class, then wait for an event of that class. Note, that
subclasses are handled too.
- If block, then wait for an event for which the block returns true.
- If collectio, then wait for a sequence of events, each matched as above.
`timeout` wait at most that much milliseconds, throw TimeoutError otherwise. If `timeout` == mil
then wait for indefinitly
Returns: a matching event or events (in case a collection of handlers has been passes)"
| handlersArray handlerFinal eventsArray blocker |
eventHandlers isNil ifTrue:[
"/ Asynchronous send...
self assert:timeout isNil.
block value.
^ nil
].
"/ Synchronous send...
self assert:Processor activeProcess ~~ connection eventDispatchProcess
message:'Cannot send commands from within event dispatching process. Would deadlock'.
eventHandlers isCollection
ifTrue:[ handlersArray := eventHandlers ]
ifFalse:[ handlersArray := Array with:eventHandlers ].
eventsArray := Array new:handlersArray size.
1 to:handlersArray size do:[:i |
| handler |
handler := handlersArray at:i.
handlersArray at:i
put:[:event |
| matches |
matches := handler isBlock ifTrue:[ handler value:event ] ifFalse:[ event isKindOf:handler ].
(matches and:[ i == 1 or:[ (eventsArray at:i - 1) notNil ] ]) ifTrue:[
eventsArray at:i put:event.
self announcer unsubscribe:(handlersArray at:i).
i == handlersArray size ifTrue:[
connection eventAnnouncerInternal when: GDBEventSetProcessingFinished do: handlerFinal.
].
].
].
self announcer when:GDBEvent do:(handlersArray at:i).
].
handlerFinal := [ :event | connection eventAnnouncerInternal unsubscribe: handlerFinal. blocker signal ].
blocker := Semaphore new.
block value.
[
(blocker waitWithTimeoutMs:timeout) isNil ifTrue:[
eventsArray := nil.
].
] ensure:[
handlersArray do:[:handler |
handler notNil ifTrue:[
self announcer unsubscribe:handler
]
].
].
eventsArray isNil ifTrue:[
(TimeoutError newException)
parameter:timeout;
raise.
].
^ eventHandlers isCollection ifTrue:[ eventsArray ] ifFalse:[ eventsArray first ]
"Created: / 08-03-2015 / 07:28:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'event handling'!
onBreakpointCreatedEvent: aGDBBreakpointCreatedEvent
breakpoints isNil ifTrue:[
breakpoints := List new.
].
aGDBBreakpointCreatedEvent breakpoints do:[:breakpoint |
breakpoint setDebugger: self.
breakpoints add: breakpoint.
].
"Created: / 06-07-2017 / 16:08:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 12-11-2017 / 20:17:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onBreakpointDeletedEvent: aGDBBreakpointDeletedEvent
| breakpoint |
breakpoint := breakpoints detect:[:e | e number == aGDBBreakpointDeletedEvent id ].
breakpoint setDebugger: nil.
breakpoints remove: breakpoint.
"Created: / 06-07-2017 / 16:26:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 07-07-2017 / 12:39:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onBreakpointModifiedEvent: aGDBBreakpointModifiedEvent
aGDBBreakpointModifiedEvent breakpoints do:[:new |
| old |
old := breakpoints detect:[:e | e number == new number ].
old updateFrom: new.
].
"Created: / 06-07-2017 / 16:28:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 12-11-2017 / 20:18:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onCommandEvent:aGDBCommandEvent
connection send:aGDBCommandEvent command.
"Created: / 02-06-2014 / 23:38:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 20-06-2014 / 22:09:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onExitEvent:aGDBExitEvent
self release.
"Created: / 03-06-2014 / 00:36:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 04-06-2014 / 09:28:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onRunningEvent: aGDBRunningEvent
| threads threadId |
self nextInferiorStateSequnceNumber.
threadId := aGDBRunningEvent threadId.
threadId = 'all' ifFalse:[
threadId := threadId asInteger.
].
threads := Set new.
inferiors do:[:inferior |
inferior threads do:[:thread |
(threadId isString or:[thread id = threadId]) ifTrue:[
threads add: thread.
].
].
].
aGDBRunningEvent setThreads: threads.
threads do:[:thread |
thread onRunningEvent: aGDBRunningEvent.
].
"Created: / 07-09-2014 / 23:34:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 12-07-2017 / 13:48:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onStoppedEvent: aGDBStoppedEvent
| threads threadIds |
self nextInferiorStateSequnceNumber.
threadIds := aGDBStoppedEvent stoppedThreadIds.
threadIds = 'all' ifFalse:[
threadIds := threadIds collect:[:e | e asInteger ].
].
threads := Set new.
inferiors do:[:inferior |
inferior threads do:[:thread |
(threadIds isString or:[threadIds includes: thread id]) ifTrue:[
threads add: thread.
].
].
].
aGDBStoppedEvent setThreads: threads.
threads do:[:thread |
thread onStoppedEvent: aGDBStoppedEvent.
].
"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>"
!
onThreadCreatedEvent:aGDBThreadCreatedEvent
| inferior |
inferior := self inferiorForId:aGDBThreadCreatedEvent threadGroupId.
inferior onThreadCreatedEvent:aGDBThreadCreatedEvent.
"Created: / 07-09-2014 / 21:20:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onThreadExitedEvent:aGDBThreadExitedEvent
| inferior |
self nextInferiorStateSequnceNumber.
inferior := self inferiorForId:aGDBThreadExitedEvent threadGroupId.
inferior onThreadExitedEvent:aGDBThreadExitedEvent.
"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>"
!
onThreadGroupAddedEvent:aGDBThreadGroupAddedEvent
| inferior |
inferiors isNil ifTrue:[
inferiors := List new.
].
inferior := GDBThreadGroup newWithDebugger:self
id:aGDBThreadGroupAddedEvent threadGroupId.
inferiors add:inferior.
aGDBThreadGroupAddedEvent setThreadGroup:inferior
"Modified: / 07-09-2014 / 21:18:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onThreadGroupExitedEvent:aGDBThreadGroupExitedEvent
| inferior |
self nextInferiorStateSequnceNumber.
inferior := self inferiorForId:aGDBThreadGroupExitedEvent threadGroupId.
inferior setExitCode:aGDBThreadGroupExitedEvent exitCode.
aGDBThreadGroupExitedEvent setThreadGroup:inferior
"Created: / 06-09-2014 / 02:37:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 18-03-2015 / 13:57:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
onThreadGroupStartedEvent:aGDBThreadGroupStartedEvent
| inferior |
inferior := self inferiorForId:aGDBThreadGroupStartedEvent threadGroupId.
inferior setPid:aGDBThreadGroupStartedEvent pid.
aGDBThreadGroupStartedEvent setThreadGroup:inferior
"Created: / 06-09-2014 / 02:37:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 07-09-2014 / 21:23:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'finalization'!
finalize
self release.
"Created: / 26-05-2014 / 21:23:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'initialize & release'!
initializeWithProcess: aGDBProcess
self registerForFinalization.
connection := GDBConnection newWithProcess: aGDBProcess.
commandSequenceNumber := 0.
inferiorStateSequenceNumber := 0.
self subscribe.
connection eventPumpStart.
connection eventDispatchStart.
Delay waitForMilliseconds:100.
"/ self send: (GDBMICommand inferiorTtySet: driver inferiorPTY name).
self send: (GDBMI_inferior_tty_set arguments: (Array with: connection inferiorPTY name)).
self send: (GDBMI_gdb_set arguments: #('target-async' 'on')).
prettyPrintingEnabled := false.
frameFiltersEnabled := false.
"Created: / 20-06-2014 / 21:45:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 17-11-2017 / 20:14:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
release
connection notNil ifTrue:[
self unsubscribe.
connection release.
connection := nil.
].
"Created: / 26-05-2014 / 21:24:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 20-06-2014 / 22:08:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
subscribe
connection eventAnnouncerInternal
when: GDBCommandEvent send: #onCommandEvent: to: self;
when: GDBExitEvent send: #onExitEvent: to: self;
when: GDBThreadGroupAddedEvent send: #onThreadGroupAddedEvent: to: self;
when: GDBThreadGroupStartedEvent send: #onThreadGroupStartedEvent: to: self;
when: GDBThreadGroupExitedEvent send: #onThreadGroupExitedEvent: to: self;
when: GDBThreadCreatedEvent send: #onThreadCreatedEvent: to: self;
when: GDBThreadExitedEvent send: #onThreadExitedEvent: to: self;
when: GDBRunningEvent send: #onRunningEvent: to: self;
when: GDBStoppedEvent send: #onStoppedEvent: to: self;
when: GDBBreakpointCreatedEvent send: #onBreakpointCreatedEvent: to: self;
when: GDBBreakpointModifiedEvent send: #onBreakpointModifiedEvent: to: self;
when: GDBBreakpointDeletedEvent send: #onBreakpointDeletedEvent: to: self.
"Created: / 20-06-2014 / 22:07:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 06-07-2017 / 16:08:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
unsubscribe
connection eventAnnouncerInternal unsubscribe: self
"Created: / 20-06-2014 / 22:07:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'testing'!
isConnected
^ connection notNil
"Created: / 20-06-2014 / 22:12:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
isFrameFiltersEnabled
^ frameFiltersEnabled
"Created: / 12-06-2017 / 09:41:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
isPrettyPrintingEnabled
^ prettyPrintingEnabled
"Created: / 12-06-2017 / 09:40:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger class methodsFor:'documentation'!
version_HG
^ '$Changeset: <not expanded> $'
! !