- live browsing of Self object memory -

lobby traitsdebugger

CopyDowns: vector

CreatorPath: traits debugger

Module: debugger

parent* = traits clonable

attaching

attach: =
( | stack <- processStack |
    detach.
    cp: identifyProcess: processID IfFail: [
        'could not find process.' printLine.
        ^self].

    cp isAlive ifFalse: [
        'a dead process cannot be attached.' printLine.
        ^self].

    stack: cp stack.
    trimTop: stack.
    trimBottom: stack.

    ('Process ', cp objectID,
    ' has been attached to the debugger.') printLine.

    cp hasError ifTrue: [
         ('"', cp causeOfError errorString, '"') printLine ].

    show)
Attach a process. processID should either be a process or an object id number on a process
detach =
( 
    cp = process ifFalse: [ cp: process ].
    self)
identifyProcess:IfFail: =
( | mirror <- mirrors mirror |
    mirror: reflect: processID.
    mirror isReflecteeProcess ifTrue: [^processID].
    mirror isReflecteeInteger ifTrue: [
        mirror: reflect: processID asIfFail: failBlk.
        mirror isReflecteeProcess ifTrue: [^mirror reflectee]].
    failBlk value)
trimBottom = ( trimBottom: cp stack)
trimBottom: =
( 
    "compute the trimmed bottom of the stack"
    trimmedBottomActivation:
        cp causeOfError firstInterestingFrameOf: stack.
    activationNum: trimmedBottomActivation = 0
        ifTrue: 0 False: trimmedBottomActivation)
trimTop: =
( 
    "compute the trimmed top of the stack"
    trimmedTopActivation: stack topmostInterestingActivation.
    numberOfRedundantTopActivations:
         cp stackDepth - trimmedTopActivation succ)

inspecting

down =
( 
    inspectCommand: 'down' Do: [ 
        show: filteredActivationIndexDownFrom: activationNum pred])
Methods for interactive inspecting
down: = ( inspectCommand: 'down' Do: [ show: activationNum - n ])Methods for interactive inspecting
locals =
( 
    inspectCommand: 'locals' Do: [| stack |
     stack: cp stack.
     stack titleString printLine.
     (cp at: activationNum) doLexicalScopes: [| :act |
         act size > 0 ifTrue: [ |index|
             index: findActivationIndex: act
                                   From: activationNum
                               IfAbsent: 0.
             (stack activationString: index) printLine.
             act do: [| :slot |
                 slot value isReflecteeAssignment ifFalse: [
                     (slot printStringAssignable, '.') printLine ]]]]])
Methods for interactive inspecting
lookup: =
( 
    inspectCommand: 'lookup' Do: [| index <- 0 |
        lookupLexicalScope: (cp at: activationNum)
                      Name: name
                 IfPresent: [| :slot |
                      (slot printString, ' {slot in activation ', 
                       (findActivationIndex: slot holder
                                       From: activationNum
                                   IfAbsent: []) printString,
                       '}') printLine.
                       (' and contents is ', slot contents idName, ' = ',
                        (slot contents safeNameSize: 45)) printLine]
                  IfAbsent: [| :outerReceiver. slotList <- list |
                      'self' = name ifTrue: [
                          (name, ' in activation: ',
                       activationNum printString, ' and contains: ',
                       outerReceiver idName, ' = ',
                       (outerReceiver safeNameSize: 45), '.') printLine
                      ] False: [
                      slotList: outerReceiver lookupKey: name.
                      slotList isEmpty ifTrue: [
                          ('cannot lookup: ', name, '.') printLine ]
                        False: [
                      slotList size = 1 ifTrue: [| slot. |
                          slot: slotList first.
                          (name, ' is found in object: ',
                           slot holder idName, ' = ',
                           (slot holder safeNameSize: 30),
                           (slot contents isReflecteeMethod ifTrue: [
                               ' and is a method' ] False: [
                               ' and contents is: ',
                               slot contents idName, ' = ',
                               (slot contents safeNameSize: 45)]),
                           '.') printLine
                      ] False: [
                           ('ambiguous lookup for: ', name, '.')
                                printLine]]]]
    ])
Methods for interactive inspecting
show = ( show: activationNum)Methods for interactive inspecting
show: =
( 
    inspectCommand: 'show' Do: [
        tty inTermcapMode ifTrue: [ tty clear ].
        number < 0 ifTrue: [
            'already at the bottom activation.' printLine] False: [
        number >= stackDepth ifTrue: [
            'already at the top activation.' printLine] False: [
        activationNum: number.
        printActivation]]])
Methods for interactive inspecting
status =
( 
     processStatusString printLine.
     cp hasError ifTrue: [
         cp causeOfError errorString printLine ].
    'status')
Methods for interactive inspecting
trace =
( 
    lexicalTracing ifTrue: [ ^ traceLex ].
    inspectCommand: 'trace' Do: [
        enableFilter ifTrue: [cp filteredStackTrace] 
                      False: [cp         stackTrace]])
Methods for interactive inspecting
traceLex = ( traceLexShowBlocks: true)Methods for interactive inspecting
traceLexShowBlocks: =
( 
    inspectCommand: 'traceLex' Do: [
        | stack <- processStack. activation. index <- 0|
        stack: cp stack.
        trimBottom: stack.
        stack titleString printLine.

        index: trimmedBottomActivation.
        [ index <= trimmedTopActivation ] whileTrue: [
            activation: cp at: index.
            activation isReflecteeMethodActivation || showBlocks 
              ifTrue: [
                (stack activationString: index) printLine.
            ].
            index:  
              activation isReflecteeMethodActivation 
                ifTrue: [index succ]
                 False: [
                          findActivationIndex: activation lexicalParent
                                         From: index
                                     IfAbsent: [ index succ ]
            ].
        ].
     ].
     self)
Methods for interactive inspecting
traceTops = ( traceLexShowBlocks: false)Methods for interactive inspecting
up =
( 
    inspectCommand: 'up' Do: [ 
        show: filteredActivationIndexUpFrom: activationNum succ])
Methods for interactive inspecting
up: = ( inspectCommand: 'up' Do: [ show: activationNum + n ])Methods for interactive inspecting
upLex =
( 
     inspectCommand: 'upLex' Do: [| activation |
    activation: cp at: activationNum.
    activation isReflecteeMethodActivation  ifFalse: [
    show: findActivationIndex: activation lexicalParent
                         From: activationNum
                     IfAbsent: [
              'not able to find lexical scope.' printLine.
              ^ self]
    ] True: [ 'not a block activation.' printLine ] ])
Methods for interactive inspecting
filteredActivationIndexDownFrom: =
( | s |
    s: cp stack.
    filteredActivationIndexFrom: start To: 0 By: -1 In: s)
Methods for interactive inspecting
filteredActivationIndexFrom:To:By:In: =
( 
    start to: stop By: step Do: [|:i| 
        enableFilter not || [cp isFrameShown: s at: i] ifTrue: [^i]
    ].
    stop)
Methods for interactive inspecting
filteredActivationIndexUpFrom: =
( | s |
    s: cp stack.
    filteredActivationIndexFrom: start To: s size pred By: 1 In: s)
Methods for interactive inspecting
findActivationIndex:From:IfAbsent: =
( 
    cp stack findFirst: [|:a. :i| (i >= index) && [ a = activation]]
             IfPresent: [|:a. :i| i]
              IfAbsent: absentBlk)
Methods for interactive inspecting
inspectCommand:Do: = ( ifProcessValidDo: cmd)Methods for interactive inspecting
lookupLexicalScope:Name:IfPresent:IfAbsent: =
( 
    absentBlk value: activation doLexicalScopes: [| :act |
        (act names includes: name) ifTrue: [
            ^presentBlk value: act slotAt: name ]])
Methods for interactive inspecting

printing

activationString: =
( | activation. string <- '' |
    activation: cp at: activationNum.
    activation isReflecteeMethodActivation  ifFalse: [
        activation receiver isReflecteeBlock
            ifTrue: [ string: 'block ' ]].
    string, 'activation:')
expressionStackString: =
( | string <- 'Expression stack: ' |
    activation expressionStack do: [| :element |
        string: string, '\n\t',
                ((reflect: element) safeNameSize: 50) ].
    string)
fileInfoString: =
( | filename <- ''. selfRoot <- ''. suffix = '.self' |
    filename: activation file.

    "Remove the self working dirctory prefix"
    selfRoot: bootstrap selfObjectsWorkingDir, '/'.
    filename: filename copyWithoutPrefix: selfRoot.

    "Remove the .self extension"
    filename: filename copyWithoutSuffix: suffix.

    'File: ', filename, ':', activation line printString)
methodHolderString: =
( 
    activation isReflecteeMethodActivation ifFalse: '' True: [
        'Method holder: ',
        (activation methodHolder safeNameSize: 50), '.'])
printActivation =
( | activation. string <- '' |
    activation: cp at: activationNum.

    showMethod ifTrue: [
        (activationText copyForActivation: activation
                                    Width: tty width)
                        do: [|:c|  string: string, c ]
          AtSelectionStart: [ string print. string: ''.
                              tty startEmphasize]
            AtSelectionEnd: [ string print. string: ''.
                              tty endEmphasize].
        string print].

    showMethodHolder ifTrue: [| string <- '' |
        string: methodHolderString: activation.
        string isEmpty ifFalse: [ string printLine ] ].
    showExpressionStack ifTrue: [
        (expressionStackString: activation) printLine]. 
    showStatus ifTrue: [ processStatusString printLine].
    showFile   ifTrue: [ (fileInfoString: activation) printLine ])
processStatusString =
( | string |
    string: 'Process ', cp objectID, ', ', cp status asString.
    cp hasError ifTrue: [ string: string, ' with error'].
    cp isAlive ifTrue: [
       string: string, ', ', (activationString: activationNum), ' ',
               activationNum printString,
               ' in [0,', stackDepth pred printString, ']'].
    string, '.')
selfFileExtension = '.self'

private

ifProcessValidDo: =
( 
    cp = process ifTrue: ['no process is attached.' printLine. ^self].
    cp isAlive ifFalse: ['process is dead.' printLine. ^self].
    cmd value.
    self)
stackDepth = ( cp stackDepth - numberOfRedundantTopActivations)

stack manipulation

retry =
( 
    stackCommandDo: [ cp _KillActivationsUpTo: activationNum.
                      cp continue. cp waitForSuspension ]
              Show: [ show ])
revert = ( stackCommandDo: [cp _KillActivationsUpTo: activationNum ])
lastByteCodeError =
( 
    ('Sorry, cannot return from the last bytecode. \n',
     'The current implementation disallows a breakpoint ',
     'after the last byte code.') printLine)
stackCommandDo:Show: =
( 
    ifProcessValidDo: [
       action value.
       cp isAlive ifFalse: [ 'process has terminated.' printLine ]
           True: [
           stackDepth < 0 ifTrue: [
               "Terminate process since we passed the top
                most interesting activation."
               cp continue. cp waitForDeath.
               'process has terminated.' printLine ] False: [trimBottom]].
       cp isAlive ifTrue: blk])

stepping

cont =
( 
     stepCommandDo: [cp continue. cp waitForSuspension]
    Iterations: 1 SkipSimpleBytecodes: false)
Continue execution
finish =
( 
     stepCommandDo: [cp finish: cp at: activationNum]
    Iterations: 1 SkipSimpleBytecodes: false)
Finish current activation
next =
( 
     stepCommandDo: [ nextAction ]
    Iterations: 1  SkipSimpleBytecodes: true)
step to the next non-trivial bytecode in this activation
next: =
( 
     stepCommandDo: [ nextAction ] 
    Iterations: n  SkipSimpleBytecodes: true)
nextb =
( 
     stepCommandDo: [ nextActionIntoBlocks ]
    Iterations: 1  SkipSimpleBytecodes: true)
step to the next non-trivial bytecode in this activation; step into blocks if they are present warning: may occasionally result in very long waits
nextb: =
( 
     stepCommandDo: [ nextActionIntoBlocks ] 
    Iterations: n  SkipSimpleBytecodes: true)
nexti =
( 
     stepCommandDo: [ nextAction ]
    Iterations: 1  SkipSimpleBytecodes: false)
step to the next bytecode in this activation
nexti: =
( 
     stepCommandDo: [ nextAction ] 
    Iterations: n  SkipSimpleBytecodes: false)
step =
( 
     stepCommandDo: [ stepAction ]
    Iterations: 1  SkipSimpleBytecodes: true)
step to the next non-trivial bytecode
step: =
( 
     stepCommandDo: [ stepAction ]
    Iterations: n  SkipSimpleBytecodes: true)
stepi =
( 
     stepCommandDo: [ stepAction ]
    Iterations: 1  SkipSimpleBytecodes: false)
step to the next bytecode
stepi: =
( 
     stepCommandDo: [ stepAction ]
    Iterations: 1  SkipSimpleBytecodes: false)
isMatching:With: =
( 
    frameA = frameB ifTrue: [^true].
    frameB isReflecteeMethodActivation ifTrue: [^false].
    frameB doLexicalScopes: [|:f| f = frameA ifTrue: [^true] ].
    false)
nextAction =
( 
    activationNum = 0 ifTrue: [| beforeStepActivation <- 0 |
        "next at the bottom most activation consists of
         one step and afterwards a finish if the step 
         was a send byte code."
        beforeStepActivation: cp currentActivation.
        cp step.
        cp isAlive ifFalse: [
            'process has terminated.' printLine] True: [
                cp currentActivation hasSender
             && [ cp currentActivation sender = beforeStepActivation]
               ifTrue: [ cp finish ]]
    ] False: [
        "next in the middle of the stack consists of
        finish the previous activation."
       cp finish: cp at: activationNum pred ])
nextActionIntoBlocks =
( | before <- mirrors methodActivation |
    before: cp at: activationNum.
    before isReflecteeMethodActivation ifFalse: [
      before doLexicalScopes: [|:f| before: f ]
    ].
    cp step.
    [ before isLive &&
        [ (isMatching: before With: cp currentActivation) not]]
    whileTrue: [ cp step])
stepAction =
( 
    "make a normal step"
    activationNum = 0 ifTrue: [ cp step ] False: [
        "step in the middle of the stack consists of
        finish the previous activation."
        cp finish: cp at: activationNum pred])
stepCommandDo:Iterations:SkipSimpleBytecodes: =
( 
    ifProcessValidDo: [
        [|:exit|
            n do: [ action value.
                cp isAlive ifFalse: [
                    'process has terminated.' printLine.
                    exit value ].
                b ifTrue: [ cp stepOverSimpleBytecodes ].
                stackDepth < 0 ifTrue: [
                    "Terminate process since we passed the top
                     most interesting activation."
                    cp continue.
                    cp waitForDeath.
                    'process has terminated.' printLine.
                    exit value ].
                trimBottom ]
        ] exit.
        cp isAlive ifTrue: [ show ]])