GDBDebugger.st
changeset 64 ed6b45e838b7
parent 56 20989de12cfb
child 67 c4ac76afe03d
equal deleted inserted replaced
63:29a7a3b4532b 64:ed6b45e838b7
       
     1 "{ Encoding: utf8 }"
       
     2 
     1 "{ Package: 'jv:libgdbs' }"
     3 "{ Package: 'jv:libgdbs' }"
     2 
     4 
     3 "{ NameSpace: Smalltalk }"
     5 "{ NameSpace: Smalltalk }"
     4 
     6 
     5 Object subclass:#GDBDebugger
     7 Object subclass:#GDBDebugger
    37     "Sets the executable to debug. 
    39     "Sets the executable to debug. 
    38      API equivalent to CLI command:
    40      API equivalent to CLI command:
    39 
    41 
    40          (gdb) exec-file <aStringOrFilename>
    42          (gdb) exec-file <aStringOrFilename>
    41     "
    43     "
    42     self send: (GDBMI_file_exec_and_symbols arguments: { aStringOrFilename asString }) wait: false.
    44     self 
       
    45           send:(GDBMI_file_exec_and_symbols arguments:{
       
    46                           aStringOrFilename asString
       
    47                       })
       
    48           andWait:false.
    43 
    49 
    44     "Created: / 28-02-2015 / 00:19:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    50     "Created: / 28-02-2015 / 00:19:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    45 !
    51 !
    46 
    52 
    47 inferiorForId: id
    53 inferiorForId: id
   117 ! !
   123 ! !
   118 
   124 
   119 !GDBDebugger methodsFor:'commands'!
   125 !GDBDebugger methodsFor:'commands'!
   120 
   126 
   121 send: command
   127 send: command
   122     "Execute given `command` and wait until it finishes. 
   128     "Execute given `command` and wait until it finishes and return its result.
   123      Command can be either an instance of GDBCommand or
   129      `command` may be either a GDBCommand or string, in which case it will
   124      a String. If String, it is assumed to be a CLI command
   130      be parsed into a GDBCommand. 
   125      string.
   131    "
   126      "
   132     ^ self send:command andWait:true.
   127     ^ self send: command wait: true.
       
   128 
   133 
   129     "Created: / 03-06-2014 / 00:10:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   134     "Created: / 03-06-2014 / 00:10:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   130     "Modified (comment): / 28-02-2015 / 00:40:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   135     "Modified (comment): / 08-03-2015 / 05:50:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   131 !
   136 !
   132 
   137 
   133 send: command wait: wait
   138 send:command andWait:wait 
   134     "Sends given `command` to GDB. If `aBoolean` is true, wait for
   139     "Sends given `command` to GDB. If `wait` is true, wait for
   135      command to finish. Otherwise, return immediately."
   140      command to finish and return the command result.  
   136 
   141      Otherwise, return nil immediately.
   137     | cmd token blocker handler1 handler2 result |
   142 
       
   143      `command` may be either a GDBCommand or string, in which case it will
       
   144      be parsed into a GDBCommand.           
       
   145     "
       
   146     
       
   147     | cmd  token  blocker  handler1  handler2  result |
   138 
   148 
   139     cmd := command.
   149     cmd := command.
   140     cmd isString ifTrue:[ 
   150     cmd isString ifTrue:[
   141         cmd := GDBCLICommand new value: cmd.
   151         cmd := GDBCLICommand new value:cmd.
   142     ].
   152     ].
   143     (wait and:[Processor activeProcess == connection eventDispatchProcess]) ifTrue:[ 
       
   144         self error: 'Cannot send commands from within event dispatching process. Would deadlock'.
       
   145     ].
       
   146 
       
   147     token := self nextCommandSequnceNumber.
   153     token := self nextCommandSequnceNumber.
   148     cmd token: token.
   154     cmd token:token.
   149     ^ wait ifTrue:[ 
   155     ^ wait ifTrue:[
   150         handler1 := [ :ev |
   156         self assert:Processor activeProcess ~~ connection eventDispatchProcess
   151                     ev token == token ifTrue:[ 
   157             message:'Cannot send commands from within event dispatching process. Would deadlock'.                
   152                         connection eventAnnouncer unsubscribe: handler1.
   158         handler1 := [:ev | 
   153                         result := ev result.
   159             ev token == token ifTrue:[
   154                         connection eventAnnouncerInternal when: GDBEventSetProcessingFinished do: handler2. 
   160                 connection eventAnnouncer unsubscribe:handler1.
   155                     ]].
   161                 result := ev result.
   156         handler2 := [ :ev |
   162                 connection eventAnnouncerInternal when:GDBEventSetProcessingFinished
   157                     connection eventAnnouncerInternal unsubscribe: handler2.         
   163                     do:handler2.
   158                     blocker signal.
   164             ]
   159                     ].
   165         ].
       
   166         handler2 := [:ev | 
       
   167             connection eventAnnouncerInternal unsubscribe:handler2.
       
   168             blocker signal.
       
   169         ].
   160         blocker := Semaphore new.
   170         blocker := Semaphore new.
   161         connection eventAnnouncer when: GDBCommandResultEvent do: handler1.
   171         connection eventAnnouncer when:GDBCommandResultEvent do:handler1.
   162         connection pushEvent: (GDBCommandEvent new command: cmd).
   172         connection pushEvent:(GDBCommandEvent new command:cmd).
   163         blocker wait.
   173         blocker wait.
   164         result.
   174         result.
   165     ] ifFalse:[
   175     ]
   166         connection pushEvent: (GDBCommandEvent new command: cmd).
   176     ifFalse:[
       
   177         connection pushEvent:(GDBCommandEvent new command:cmd).
   167         nil.
   178         nil.
   168     ]
   179     ]
   169 
   180 
   170     "Created: / 02-06-2014 / 23:45:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   181     "Created: / 02-06-2014 / 23:45:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   171     "Modified: / 28-02-2015 / 00:42:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   182     "Modified: / 08-03-2015 / 05:51:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   183 !
       
   184 
       
   185 send:command andWaitFor:eventHandlers
       
   186     "Sends given `command` to GDB and then wait for events mathing 
       
   187      `eventHandlers`. 
       
   188 
       
   189      Params:
       
   190      `command`      may be either a GDBCommand or string, in which case it will
       
   191                     be parsed into a GDBCommand.
       
   192      `eventHandler` may be either nil or event class or one arg block or collection
       
   193                     of event classes or blocks.
       
   194                     - If nil then do not wait for anything (use nil for async send)
       
   195                     - If event class, then wait for an event of that class. Note, that
       
   196                       subclasses are handled too.
       
   197                     - If block, then wait for an event for which the block returns true.
       
   198                     - If collectio, then wait for a sequence of events, each matched as above.
       
   199 
       
   200      Returns:       a matching event or events (in case a collection of handlers has been passes)"
       
   201 
       
   202     ^ self send: command andWaitFor: eventHandlers withTimeoutMs: nil
       
   203 
       
   204     "Created: / 08-03-2015 / 06:03:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   205 !
       
   206 
       
   207 send:command andWaitFor:eventHandlers withTimeoutMs:timeout 
       
   208     "Sends given `command` to GDB and then wait for events mathing 
       
   209      `eventHandlers`. Raise a TimeoutError if expected events don't arrive
       
   210      in specified time.
       
   211 
       
   212      Params:
       
   213      `command`      may be either a GDBCommand or string, in which case it will
       
   214                     be parsed into a GDBCommand.
       
   215      `eventHandler` may be either nil or event class or one arg block or collection
       
   216                     of event classes or blocks.
       
   217                     - If nil then do not wait for anything (use nil for async send)
       
   218                     - If event class, then wait for an event of that class. Note, that
       
   219                       subclasses are handled too.
       
   220                     - If block, then wait for an event for which the block returns true.
       
   221                     - If collectio, then wait for a sequence of events, each matched as above.
       
   222      `timeout`       wait at most that much milliseconds, throw TimeoutError otherwise. If `timeout` == mil
       
   223                     then wait for indefinitly
       
   224 
       
   225      Returns:       a matching event or events (in case a collection of handlers has been passes)"
       
   226     
       
   227     | commandObject |
       
   228 
       
   229     command isString ifTrue:[
       
   230         commandObject := (GDBMIParser on:command) parseCommand.
       
   231         commandObject token:self nextCommandSequnceNumber.
       
   232     ] ifFalse:[
       
   233         commandObject := command.
       
   234         commandObject token isNil ifTrue:[
       
   235             commandObject token:self nextCommandSequnceNumber.
       
   236         ].
       
   237     ].
       
   238     ^ self 
       
   239         do:[ connection pushEvent:(GDBCommandEvent new command: commandObject) ] 
       
   240         andWaitFor: eventHandlers 
       
   241         withTimeoutMs: timeout
       
   242 
       
   243     "Created: / 07-03-2015 / 11:38:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   244     "Modified: / 08-03-2015 / 07:31:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   245 ! !
       
   246 
       
   247 !GDBDebugger methodsFor:'commands-convenience'!
       
   248 
       
   249 do: block andWaitFor:eventHandlers
       
   250     "Evaluates a given block and then wait for events.
       
   251      `eventHandlers`. 
       
   252      Params:
       
   253      `block`        block to evaluate
       
   254      `eventHandler` may be either nil or event class or one arg block or collection
       
   255                     of event classes or blocks.
       
   256                     - If nil then do not wait for anything (use nil for async send)
       
   257                     - If event class, then wait for an event of that class. Note, that
       
   258                       subclasses are handled too.
       
   259                     - If block, then wait for an event for which the block returns true.
       
   260                     - If collectio, then wait for a sequence of events, each matched as above.
       
   261      Returns:       a matching event or events (in case a collection of handlers has been passed)"
       
   262 
       
   263     ^ self do: block andWaitFor: eventHandlers withTimeoutMs: nil
       
   264 
       
   265     "Created: / 08-03-2015 / 07:30:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   266 !
       
   267 
       
   268 do: block andWaitFor:eventHandlers withTimeoutMs:timeout 
       
   269     "Evaluates a given block and then wait for events.
       
   270      `eventHandlers`. Raise a TimeoutError if expected events don't arrive
       
   271      in specified time.
       
   272 
       
   273      Params:
       
   274      `block`        block to evaluate
       
   275      `eventHandler` may be either nil or event class or one arg block or collection
       
   276                     of event classes or blocks.
       
   277                     - If nil then do not wait for anything (use nil for async send)
       
   278                     - If event class, then wait for an event of that class. Note, that
       
   279                       subclasses are handled too.
       
   280                     - If block, then wait for an event for which the block returns true.
       
   281                     - If collectio, then wait for a sequence of events, each matched as above.
       
   282      `timeout`       wait at most that much milliseconds, throw TimeoutError otherwise. If `timeout` == mil
       
   283                     then wait for indefinitly
       
   284 
       
   285      Returns:       a matching event or events (in case a collection of handlers has been passes)"
       
   286     
       
   287     | handlersArray handlerFinal eventsArray blocker |
       
   288 
       
   289     eventHandlers isNil ifTrue:[
       
   290         "/ Asynchronous send...
       
   291         self assert:timeout isNil.
       
   292         block value.
       
   293         ^ nil
       
   294     ].
       
   295     "/ Synchronous send...
       
   296     self assert:Processor activeProcess ~~ connection eventDispatchProcess
       
   297         message:'Cannot send commands from within event dispatching process. Would deadlock'.
       
   298     eventHandlers isCollection 
       
   299         ifTrue:[ handlersArray := eventHandlers ]
       
   300         ifFalse:[ handlersArray := Array with:eventHandlers ].
       
   301     eventsArray := Array new:handlersArray size.
       
   302     1 to:handlersArray size do:[:i | 
       
   303         | handler |
       
   304 
       
   305         handler := handlersArray at:i.
       
   306         handlersArray at:i
       
   307             put:[:event | 
       
   308                 | matches |
       
   309 
       
   310                 matches := handler isBlock ifTrue:[ handler value:event ] ifFalse:[ event isKindOf:handler ].
       
   311                 (matches and:[ i == 1 or:[ (eventsArray at:i - 1) notNil ] ]) ifTrue:[
       
   312                     eventsArray at:i put:event.
       
   313                     self announcer unsubscribe:(handlersArray at:i).
       
   314                     i == handlersArray size ifTrue:[
       
   315                         connection eventAnnouncerInternal when: GDBEventSetProcessingFinished do: handlerFinal.
       
   316                     ].
       
   317                 ].
       
   318             ].
       
   319         self announcer when:GDBEvent do:(handlersArray at:i).
       
   320     ].
       
   321     handlerFinal := [ :event | connection eventAnnouncerInternal unsubscribe: handlerFinal. blocker signal ].  
       
   322     blocker := Semaphore new.
       
   323     block value.
       
   324     [
       
   325         (blocker waitWithTimeoutMs:timeout) isNil ifTrue:[
       
   326             eventsArray := nil.
       
   327         ].
       
   328     ] ensure:[
       
   329         handlersArray do:[:handler | 
       
   330             handler notNil ifTrue:[
       
   331                 self announcer unsubscribe:handler
       
   332             ]
       
   333         ].
       
   334     ].
       
   335     eventsArray isNil ifTrue:[
       
   336         (TimeoutError newException)
       
   337             parameter:timeout;
       
   338             raise.
       
   339     ].
       
   340     ^ eventHandlers isCollection ifTrue:[ eventsArray ] ifFalse:[ eventsArray first ]
       
   341 
       
   342     "Created: / 08-03-2015 / 07:28:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   172 ! !
   343 ! !
   173 
   344 
   174 !GDBDebugger methodsFor:'event handling'!
   345 !GDBDebugger methodsFor:'event handling'!
   175 
   346 
   176 onCommandEvent:aGDBCommandEvent 
   347 onCommandEvent:aGDBCommandEvent