VM Maker: GDB-bgs.1.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

VM Maker: GDB-bgs.1.mcz

commits-2
 
Boris Shingarov uploaded a new version of GDB to project VM Maker:
http://source.squeak.org/VMMaker/GDB-bgs.1.mcz

==================== Summary ====================

Name: GDB-bgs.1
Author: bgs
Time: 12 April 2020, 7:54:25.444451 pm
UUID: 0eba5e72-c35a-4d8c-a192-489728067891
Ancestors:

Initial import of GDB Remote Client interface

==================== Snapshot ====================

SystemOrganization addCategory: #'GDB-RSP'!
SystemOrganization addCategory: #'GDB-TAJ'!
SystemOrganization addCategory: #'GDB-UI'!
SystemOrganization addCategory: #'GDB-Primitives'!
SystemOrganization addCategory: #'GDB-Tests'!
SystemOrganization addCategory: #'GDB-Doodles'!
SystemOrganization addCategory: #'GDB-Cog'!

BorderedMorph subclass: #GdbMTEngineMorph
        instanceVariableNames: 'gdb regs'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-UI'!

!GdbMTEngineMorph commentStamp: 'BorisShingarov 4/25/2016 13:39' prior: 0!
I add a 'Modtalk' tab to the GT Inspector.!

----- Method: GdbMTEngineMorph class>>on: (in category 'instance creation') -----
on: aGDB
        ^self new
                gdb: aGDB;
                yourself!

----- Method: GdbMTEngineMorph>>defaultBounds (in category 'as yet unclassified') -----
defaultBounds
        "Answer the default bounds for the receiver."

        ^0 @ 0 corner: 500 @ 300!

----- Method: GdbMTEngineMorph>>drawCurrentBytecodeOn:fromHeight: (in category 'as yet unclassified') -----
drawCurrentBytecodeOn: clippedCanvas fromHeight: y
        | bc |
        bc := [ gdb currentBytecode printString ]
                on: Error do: [ '???' ].
        clippedCanvas
                drawString: bc
                at: (self bounds topLeft + (0 @ y))
                font: (LogicalFont familyName: 'Bitmap DejaVu Sans' pointSize: 12)
                color: Color black.
        ^y + 14!

----- Method: GdbMTEngineMorph>>drawCurrentFrameOn:fromHeight: (in category 'as yet unclassified') -----
drawCurrentFrameOn: clippedCanvas fromHeight: y
        | fp  |
        fp := gdb getVRegister: #FP.
        self drawFrame: fp withAllSendersOn: clippedCanvas fromHeight: y
!

----- Method: GdbMTEngineMorph>>drawCurrentInstructionOn:fromHeight: (in category 'as yet unclassified') -----
drawCurrentInstructionOn: clippedCanvas fromHeight: y
        | pc nativeInstr |
        pc := regs at: 'pc'.
        nativeInstr := gdb currentInstruction.
        clippedCanvas
                drawString: nativeInstr printString
                at: (self bounds topLeft + (0 @ y))
                font: (LogicalFont familyName: 'Bitmap DejaVu Sans' pointSize: 12)
                color: Color black.
        ^y + 14!

----- Method: GdbMTEngineMorph>>drawFrame:on:fromHeight: (in category 'as yet unclassified') -----
drawFrame: fp on: clippedCanvas fromHeight: y
        | frame cm |
        frame := MTRemoteStackFrame gdb: gdb pointer: fp.
        cm := frame method.
        clippedCanvas
                drawString: cm selector symbol asString
                at: (self bounds topLeft + (0 @ y))
                font: (LogicalFont familyName: 'Bitmap DejaVu Sans' pointSize: 12)
                color: Color black.
        ^y+20!

----- Method: GdbMTEngineMorph>>drawFrame:withAllSendersOn:fromHeight: (in category 'as yet unclassified') -----
drawFrame: fp withAllSendersOn: clippedCanvas fromHeight: y
        | frame yy |
        yy := self drawFrame: fp on: clippedCanvas fromHeight: y.
        frame := MTRemoteStackFrame gdb: gdb pointer: fp.
        frame .
        ^y+20
!

----- Method: GdbMTEngineMorph>>drawOn: (in category 'as yet unclassified') -----
drawOn: aCanvas
        regs := gdb getRegisters.
        aCanvas
                clipBy: self bounds
                during: [:clippedCanvas |
                        clippedCanvas
                                fillRectangle: self bounds
                                color: Color white.
                self drawCurrentFrameOn: clippedCanvas fromHeight:
                (self drawCurrentBytecodeOn: clippedCanvas fromHeight:
                (self drawCurrentInstructionOn: clippedCanvas fromHeight:
                (self drawVregsOn: clippedCanvas) + 15)) + 15
                                ].
 !

----- Method: GdbMTEngineMorph>>drawSPR:on:fromHeight: (in category 'as yet unclassified') -----
drawSPR: spr on: clippedCanvas fromHeight: y
        clippedCanvas
                drawString: spr, ' = ', (regs at: spr) printString
                at: (self bounds topLeft + (0 @ y))
                font: (LogicalFont familyName: 'Bitmap DejaVu Sans' pointSize: 12)
                color: Color black.
        ^y + 14 !

----- Method: GdbMTEngineMorph>>drawSPRsOn:fromHeight: (in category 'as yet unclassified') -----
drawSPRsOn: clippedCanvas fromHeight: y
        | yy |
        yy := y.
        #('pc' 'lr' 'cr' 'ctr' 'msr' 'xer') do: [ :spr |
                self drawSPR: spr on: clippedCanvas fromHeight: yy.
                yy := yy + 14.
                ].
        ^yy!

----- Method: GdbMTEngineMorph>>drawVRegHeaderOn: (in category 'as yet unclassified') -----
drawVRegHeaderOn: clippedCanvas
        clippedCanvas
                drawString: 'VRegs:'
                at: self bounds topLeft
                font: (LogicalFont familyName: 'Bitmap DejaVu Sans' pointSize: 14)
                color: Color black.
        ^18 "BOGUS CODE"
        !

----- Method: GdbMTEngineMorph>>drawVregsOn: (in category 'as yet unclassified') -----
drawVregsOn: clippedCanvas
        | y |
        y := self drawVRegHeaderOn: clippedCanvas.
        TAJWriter registerMap keysAndValuesDo: [ :vReg :physReg |
                | regName |
                regName := physReg isInteger ifTrue: ['r', physReg printString]
                        ifFalse: [ physReg ].

                clippedCanvas
                        drawString: vReg printString, ' = ', (regs at: regName) printString
                        at: (self bounds topLeft + (0 @ y))
                        font: (LogicalFont familyName: 'Bitmap DejaVu Sans' pointSize: 12)
                        color: Color black.
                y := y + 14.
                 ].
        ^y
        !

----- Method: GdbMTEngineMorph>>gdb (in category 'accessing') -----
gdb
        ^ gdb!

----- Method: GdbMTEngineMorph>>gdb: (in category 'accessing') -----
gdb: anObject
        gdb := anObject!

BorderedMorph subclass: #GdbRegistersMorph
        instanceVariableNames: 'gdb regs'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-UI'!

!GdbRegistersMorph commentStamp: 'BorisShingarov 4/25/2016 13:39' prior: 0!
I add a 'Registers' tab to the GT Inspector.!

----- Method: GdbRegistersMorph class>>concreteClassFor: (in category 'instance creation') -----
concreteClassFor: aGDB
        ^Smalltalk classNamed: 'GdbRegistersMorph', aGDB processorDescription architectureName !

----- Method: GdbRegistersMorph class>>on: (in category 'instance creation') -----
on: aGDB
        ^(self concreteClassFor: aGDB) new
                gdb: aGDB;
                yourself!

----- Method: GdbRegistersMorph>>defaultBounds (in category 'drawing') -----
defaultBounds
        "Answer the default bounds for the receiver."

        ^0 @ 0 corner: 500 @ 300!

----- Method: GdbRegistersMorph>>drawGPRHeaderOn: (in category 'drawing') -----
drawGPRHeaderOn: clippedCanvas
        clippedCanvas
                drawString: 'GPR:'
                at: self bounds topLeft
                font: (LogicalFont familyName: 'Bitmap DejaVu Sans' pointSize: 14)
                color: Color black.
        ^18 "BOGUS CODE"
        !

----- Method: GdbRegistersMorph>>drawGPRsOn: (in category 'drawing') -----
drawGPRsOn: clippedCanvas
        | y |
        y := self drawGPRHeaderOn: clippedCanvas.
        0 to: 31 do: [ :r |
                | regName |
                regName := 'r', r printString.
                clippedCanvas
                        drawString: regName, ' = ', (regs at: regName) printString
                        at: (self bounds topLeft + (0 @ y))
                        font: (LogicalFont familyName: 'Bitmap DejaVu Sans' pointSize: 12)
                        color: Color black.
                y := y + 15.
                 ].
        ^y
        !

----- Method: GdbRegistersMorph>>drawOn: (in category 'drawing') -----
drawOn: aCanvas
        regs := gdb getRegisters.
        aCanvas
                clipBy: self bounds
                during: [:clippedCanvas |
                        clippedCanvas
                                fillRectangle: self bounds
                                color: Color yellow.
                        self drawRegistersOn: clippedCanvas
                ]
 !

----- Method: GdbRegistersMorph>>gdb (in category 'accessing') -----
gdb
        ^ gdb!

----- Method: GdbRegistersMorph>>gdb: (in category 'accessing') -----
gdb: anObject
        gdb := anObject!

GdbRegistersMorph subclass: #GdbRegistersMorphIA32
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-UI'!

----- Method: GdbRegistersMorphIA32>>drawRegistersOn: (in category 'drawing') -----
drawRegistersOn: clippedCanvas
        | y |
        y := self drawGPRHeaderOn: clippedCanvas.
        gdb processorDescription gdb do: [ :r |
                | regName |
                regName := r regName.
                clippedCanvas
                        drawString: regName, ' = ', (regs at: regName) printString
                        at: (self bounds topLeft + (0 @ y))
                        font: (LogicalFont familyName: 'Bitmap DejaVu Sans' pointSize: 12)
                        color: Color black.
                y := y + 15.
                 ].
        ^y
        !

GdbRegistersMorph subclass: #GdbRegistersMorphpowerpc
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-UI'!

----- Method: GdbRegistersMorphpowerpc>>drawRegistersOn: (in category 'drawing') -----
drawRegistersOn: clippedCanvas
        self drawSPRsOn: clippedCanvas fromHeight:
                (self drawGPRsOn: clippedCanvas) + 15
 !

----- Method: GdbRegistersMorphpowerpc>>drawSPR:on:fromHeight: (in category 'drawing') -----
drawSPR: spr on: clippedCanvas fromHeight: y
        clippedCanvas
                drawString: spr, ' = ', (regs at: spr) printString
                at: (self bounds topLeft + (0 @ y))
                font: (LogicalFont familyName: 'Bitmap DejaVu Sans' pointSize: 12)
                color: Color black.
        ^y + 14 !

----- Method: GdbRegistersMorphpowerpc>>drawSPRsOn:fromHeight: (in category 'drawing') -----
drawSPRsOn: clippedCanvas fromHeight: y
        | yy |
        yy := y.
        self sprNames  do: [ :spr |
                self drawSPR: spr on: clippedCanvas fromHeight: yy.
                yy := yy + 15.
                ]!

----- Method: GdbRegistersMorphpowerpc>>sprNames (in category 'drawing') -----
sprNames
        gdb processorDescription architectureName = 'powerpc'
                ifTrue: [ ^#('pc' 'lr' 'cr' 'ctr' 'msr' 'xer') ].
        ^#('pc' 'sr' 'hi' 'lo' 'cause' 'badvaddr')!

Error subclass: #GdbChildExited
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

Error subclass: #InferiorExited
        instanceVariableNames: 'exitCode'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: InferiorExited class>>exitCode: (in category 'instance creation') -----
exitCode: anInteger
        ^self new exitCode: anInteger; yourself!

----- Method: InferiorExited class>>signalWithExitCode: (in category 'signaling') -----
signalWithExitCode: anInteger

        ^(self exitCode: anInteger) signal!

----- Method: InferiorExited>>exitCode (in category 'accessing') -----
exitCode
        ^ exitCode!

----- Method: InferiorExited>>exitCode: (in category 'accessing') -----
exitCode: anObject
        exitCode := anObject!

TestCase subclass: #DebugStoppedTestCase
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Tests'!

----- Method: DebugStoppedTestCase>>testCreateSEGV (in category 'tests-basic') -----
testCreateSEGV
        | sig |
        sig := DebugStopped onSignalNum: 11.
        self assert: sig signal equals: #SIGSEGV!

----- Method: DebugStoppedTestCase>>testCreateSYS (in category 'tests-basic') -----
testCreateSYS
        | sig |
        sig := DebugStopped onSignalNum: 31.
        self assert: sig signal equals: #SIGSYS!

----- Method: DebugStoppedTestCase>>testCreateTRAP (in category 'tests-basic') -----
testCreateTRAP
        | sig |
        sig := DebugStopped onSignalNum: 5.
        self assert: sig signal equals: #SIGTRAP!

TestCase subclass: #FeatureParserTestCase
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Tests'!

----- Method: FeatureParserTestCase>>testParse1 (in category 'tests') -----
testParse1
        | regs r1 lr ctr |
        regs := (GdbXmlParser endian: FakeProcessorDescriptionPPC endian)
                parseString: FakeProcessorDescriptionPPC features.
        r1 := regs at: 2.
        self assert: r1 regName        equals: 'r1'.
        self assert: r1 width          equals: 32.
        self assert: r1 isLittleEndian equals: false.
        self assert: r1 regNum         equals: 1.
       
        lr := regs at: 68.
        self assert: lr regName        equals: 'lr'.
        self assert: lr width          equals: 32.
        self assert: lr isLittleEndian equals: false.
        self assert: lr regNum         equals: 67.
       
        ctr := regs at: 69.
        self assert: ctr regName        equals: 'ctr'.
        self assert: ctr width          equals: 32.
        self assert: ctr isLittleEndian equals: false.
        self assert: ctr regNum         equals: 68.
!

TestCase subclass: #GDBSocketTimeoutTest
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Tests'!

----- Method: GDBSocketTimeoutTest>>connectGdb (in category 'as yet unclassified') -----
connectGdb
        ^self debuggerClass
                host: self hostIP
                port: 7000
                processorDescription: FakeProcessorDescriptionPPC new!

----- Method: GDBSocketTimeoutTest>>hostIP (in category 'as yet unclassified') -----
hostIP
        ^'192.168.75.2'!

----- Method: GDBSocketTimeoutTest>>testBad (in category 'as yet unclassified') -----
testBad
        | gdb |
        gdb := self connectGdb.
        gdb halt.
        self should: [ gdb c ] raise: ConnectionClosed
!

----- Method: GDBSocketTimeoutTest>>testGood (in category 'as yet unclassified') -----
testGood
        | gdb |
        gdb := self connectGdb.
        gdb inspect!

TestCase subclass: #RemoteGDBTestCase
        instanceVariableNames: 'gdb pdl'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

!RemoteGDBTestCase commentStamp: 'bgs 3/22/2020 00:16' prior: 0!
I am deprecated leftover from TA-MT.
!

----- Method: RemoteGDBTestCase>>connectGDB (in category 'as yet unclassified') -----
connectGDB
        pdl := AcProcessorDescriptions powerpc.
        gdb := RemoteGDBSession
                host: '192.168.75.2'
                port: 7000
                processorDescription: pdl.!

----- Method: RemoteGDBTestCase>>exitSyscall: (in category 'syscall sequences') -----
exitSyscall: rtnInt
        | loadSyscallNo loadReturnValue sc |
        loadSyscallNo := (pdl instructionAt: #addi) bind: (Dictionary new
                at: 'ra' put: 0;
                at: 'rt' put: 0;
                at: 'd' put: 1;
                yourself).
        loadReturnValue := (pdl instructionAt: #addi) bind: (Dictionary new
                at: 'ra' put: 0;
                at: 'rt' put: 3;
                at: 'd' put: rtnInt;
                yourself).
        sc := (pdl instructionAt: #sc) bind: (Dictionary new
                at: 'lev' put: 0;
                yourself).
        ^(Array with: loadSyscallNo with: loadReturnValue with: sc)
        collect: [ :instr | instr emit ]!

----- Method: RemoteGDBTestCase>>messageBytes (in category 'syscall sequences') -----
messageBytes
        ^'HELLO!!' asByteArray, #(10 0)!

----- Method: RemoteGDBTestCase>>testManualSyscallInNZone (in category 'as yet unclassified') -----
testManualSyscallInNZone
        | memLayout writeInstructions exitInstructions |
        self halt.
        self connectGDB.
        memLayout := ThinshellAddressLayout gdb: gdb.
        memLayout executeStartChain.
        writeInstructions := self writeSyscall: self messageBytes.
        exitInstructions := self exitSyscall: 1.
        gdb writeInt32s: writeInstructions, exitInstructions toAddr: memLayout nZone.
        gdb writeBytes: self messageBytes toAddr: memLayout heap.
       
        gdb
                stepUntil: [ gdb currentInstruction name = 'sc' ];
                s.   "the actual write syscall"
       
        gdb s; s; s. "exit"
        Transcript yourself
        !

----- Method: RemoteGDBTestCase>>testSetRegisters (in category 'as yet unclassified') -----
testSetRegisters

        | regs1 regs2 |
        self halt.
        regs1 := gdb getRegisters.
        gdb setRegisters: regs1.
        regs2 := gdb getRegisters.
        self assert: regs1 = regs2.!

----- Method: RemoteGDBTestCase>>writeSyscall: (in category 'syscall sequences') -----
writeSyscall: aByteArray
        | loadSyscallNo loadFD loadBuf loadLength sc |
        loadSyscallNo := (pdl instructionAt: #addi) bind: (Dictionary new
                at: 'ra' put: 0;
                at: 'rt' put: 0;
                at: 'd' put: 4;
                yourself).
        loadFD := (pdl instructionAt: #addi) bind: (Dictionary new
                at: 'ra' put: 0;
                at: 'rt' put: 3;
                at: 'd' put: 1;
                yourself).
        loadBuf := (pdl instructionAt: #addi) bind: (Dictionary new
                at: 'ra' put: 17;
                at: 'rt' put: 4;
                at: 'd' put: 0;
                yourself).
        loadLength := (pdl instructionAt: #addi) bind: (Dictionary new
                at: 'ra' put: 0;
                at: 'rt' put: 5;
                at: 'd' put: (aByteArray size);
                yourself).
        sc := (pdl instructionAt: #sc) bind: (Dictionary new
                at: 'lev' put: 0;
                yourself).
        ^(Array with: loadSyscallNo with: loadFD with: loadBuf with: loadLength with: sc)
        collect: [ :instr | instr emit ]!

Object subclass: #AddressSpaceLayout
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-TAJ'!

!AddressSpaceLayout commentStamp: 'BorisShingarov 3/7/2020 13:22' prior: 0!
In Target-Agnostic Modtalk, when we are AoT-ing the binary image, somewhere in the address space there is the arena where we construct the object heap, and the nZone.  Instances of my concrete subclasses know where these two addresses are.!

----- Method: AddressSpaceLayout>>heap (in category 'accessing') -----
heap
        self subclassResponsibility !

----- Method: AddressSpaceLayout>>nZone (in category 'accessing') -----
nZone
        self subclassResponsibility !

AddressSpaceLayout subclass: #ThinshellAddressLayout
        instanceVariableNames: 'gdb nZone heap stack'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-TAJ'!

!ThinshellAddressLayout commentStamp: 'BorisShingarov 3/7/2020 14:02' prior: 0!
The TAM Thinshell, as described in the Kilpela-Shingarov report, and available in the shingarov/thinshell GitHub repo, is an ELF binary which doesn't link to the C runtime.  Its simple, processor-specific assembly source declares areas for heap, nZone and stack, and a _start entry point leading into a "start chain".  The start chain has a few instructions to load the addresses of the heap, nZone and stack into register defined by convention, a magic-point for transfering control to the outer-Smalltalk ProgramBuilder, and a jump to the beginning of the nZone.!

----- Method: ThinshellAddressLayout class>>gdb: (in category 'instance creation') -----
gdb: aGDB
        ^self basicNew
                gdb: aGDB;
                initialize!

----- Method: ThinshellAddressLayout class>>registerAssignments (in category 'register conventions') -----
registerAssignments
        "This is TAM-specific and probably should not be here."
        ^
        (#R  -> 1),
        (#A  -> 2),
        (#A  -> 3),
        (#FP -> 4),

        (#Scratch1  -> 5),
        (#Scratch2  -> 6),
        (#Scratch3  -> 7),
        (#Scratch4  -> 8),
        (#Scratch5  -> 9),
        (#Scratch6  -> 10),
        (#Scratch7  -> 11),
        (#Scratch8  -> 12),
        (#Scratch9  -> 13),
        (#Scratch10 -> 14),
       
        (#NZone -> 16),
        (#HEAP  -> 2),
        (#SP    -> 18),
        (#VPC   -> 19),
       
        (#NativePC -> 'pc')
        !

----- Method: ThinshellAddressLayout>>executeStartChain (in category 'initialization') -----
executeStartChain
        | regs |
        regs := gdb s; "the first nop"
                s; s; "lis/ori 16"
                s; s;
                s; s;
                s; s; "2 nops"
                getRegisters.

        nZone := regs at: (self regNameFor: #NZone).
        heap := regs at: (self regNameFor: #HEAP).
        stack := regs at: (self regNameFor: #SP).!

----- Method: ThinshellAddressLayout>>gdb (in category 'accessing') -----
gdb
        ^ gdb!

----- Method: ThinshellAddressLayout>>gdb: (in category 'accessing') -----
gdb: anObject
        gdb := anObject!

----- Method: ThinshellAddressLayout>>heap (in category 'accessing') -----
heap
        ^ heap!

----- Method: ThinshellAddressLayout>>heap: (in category 'accessing') -----
heap: anObject
        heap := anObject!

----- Method: ThinshellAddressLayout>>initialize (in category 'initialization') -----
initialize
        super initialize.
        self executeStartChain!

----- Method: ThinshellAddressLayout>>nZone (in category 'accessing') -----
nZone
        ^ nZone!

----- Method: ThinshellAddressLayout>>nZone: (in category 'accessing') -----
nZone: anObject
        nZone := anObject!

----- Method: ThinshellAddressLayout>>regNameFor: (in category 'cooperation with gdb') -----
regNameFor: vRegName
        ^'r', (ThinshellAddressLayout registerAssignments at: vRegName) printString!

----- Method: ThinshellAddressLayout>>stack (in category 'accessing') -----
stack
        ^ stack!

----- Method: ThinshellAddressLayout>>stack: (in category 'accessing') -----
stack: anObject
        stack := anObject!

Object subclass: #BasePrimitiveProcessor
        instanceVariableNames: 'gdb regs'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Primitives'!

----- Method: BasePrimitiveProcessor class>>gdb: (in category 'as yet unclassified') -----
gdb: gdb
        ^self new
                gdb: gdb;
                yourself!

----- Method: BasePrimitiveProcessor>>advancePastTrap (in category 'engine') -----
advancePastTrap
        regs at: 'pc' put: (regs at: 'pc')+4!

----- Method: BasePrimitiveProcessor>>allocIndexed:md: (in category 'allocating') -----
allocIndexed: size md: md
        |  ptr obj liveObj mtNil |
        ptr := self allocSlots: size serviceSlots: 3.
        obj := MTRemoteObject gdb: gdb pointer: ptr.
        obj header: (TAJObjectWriter
                declareObjectHeaderType: 'IndexedObjectType'
                hashFormat: 'NoHash'
                numVars: size
                hash: 0
                meta: 0).
        obj md: md.
        liveObj := MTRemoteLiveIndexedObject gdb: gdb pointer: ptr.
        mtNil := gdb exe externalReferences at: #MT_nil.
        1 to: size do: [ :i |
                liveObj mtAt: i put: mtNil ].
        self return: ptr!

----- Method: BasePrimitiveProcessor>>allocOop:md: (in category 'allocating') -----
allocOop: numVars md: md
        |  ptr obj mtNil |
        ptr := self allocSlots: numVars serviceSlots: 3 "header, md, hash".
        obj := MTRemoteObject gdb: gdb pointer: ptr.
        obj header: (TAJObjectWriter
                declareObjectHeaderType: 'OopObjectType'
                hashFormat: 'NoHash'
                numVars: numVars hash: 0 meta: 0).
        obj md: md.
        "nil the slots:"
        mtNil := gdb exe externalReferences at: #MT_nil.
        1 to: numVars do: [ :idx | obj basicSlotAt: idx+2 put: mtNil ].
        ^ptr
!

----- Method: BasePrimitiveProcessor>>allocSlots:serviceSlots: (in category 'allocating') -----
allocSlots: numSlots serviceSlots: s
        | nBytes p |
        false ifTrue: [ ^self allocSlotsFromMTXMemory: numSlots ].
       
        nBytes := (numSlots + s) * 4.
        nBytes := nBytes+15 bitAnd: 16rFFFFFFF0.
        p := self getVRegister: #HEAP.
        self setVRegister: #HEAP to: p + nBytes.
        ^p!

----- Method: BasePrimitiveProcessor>>allocSlotsFromMTXMemory: (in category 'allocating') -----
allocSlotsFromMTXMemory: numSlots
        | nBytes |
        nBytes := numSlots * 4.
        ^self gdb exe objectMemory alloc: nBytes!

----- Method: BasePrimitiveProcessor>>allocString:md: (in category 'allocating') -----
allocString: size md: md
        | ptr obj |
        ptr := self allocSlots: (size + 2 + 3 // 4) serviceSlots: 3 "header, md, hash".
        obj := MTRemoteObject gdb: gdb pointer: ptr.
        obj header: (TAJObjectWriter
                declareObjectHeaderType: 'ZByteObjectType'
                hashFormat: 'StringHash'
                numVars: size
                hash: 0
                meta: 0).
        obj md: md.
        self return: ptr!

----- Method: BasePrimitiveProcessor>>currentFrame (in category 'engine') -----
currentFrame
"NB -- this is problematic, this parallel implementation with GDB"
        ^MTRemoteStackFrame gdb: gdb pointer: (self getVRegister: #FP)!

----- Method: BasePrimitiveProcessor>>gdb (in category 'accessing') -----
gdb
        ^ gdb!

----- Method: BasePrimitiveProcessor>>gdb: (in category 'accessing') -----
gdb: anObject
        gdb := anObject!

----- Method: BasePrimitiveProcessor>>getAllRegisters (in category 'engine') -----
getAllRegisters
        regs := gdb getRegisters!

----- Method: BasePrimitiveProcessor>>getRegister: (in category 'engine') -----
getRegister: r
        ^regs at: r!

----- Method: BasePrimitiveProcessor>>getVRegister: (in category 'engine') -----
getVRegister: regSym
        | nRegister |
        nRegister := TAJWriter vRegister: regSym.
        ^self getRegister: 'r', nRegister printString!

----- Method: BasePrimitiveProcessor>>processPrimitive: (in category 'engine') -----
processPrimitive: primitiveSelector
        self
                getAllRegisters;
                perform: primitiveSelector;
                advancePastTrap;
                setAllRegisters!

----- Method: BasePrimitiveProcessor>>setAllRegisters (in category 'engine') -----
setAllRegisters
        gdb setRegisters: regs!

----- Method: BasePrimitiveProcessor>>setRegister:to: (in category 'engine') -----
setRegister: r to: x
        regs at: r put: x!

----- Method: BasePrimitiveProcessor>>setVRegister:to: (in category 'engine') -----
setVRegister: r to: x
        | nRegister |
        nRegister := TAJWriter vRegister:  r.
        nRegister := 'r', nRegister printString.
        self setRegister: nRegister to: x!

BasePrimitiveProcessor subclass: #PrimitiveProcessor
        instanceVariableNames: 'exceptionEnvSlot'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Primitives'!

!PrimitiveProcessor commentStamp: 'BorisShingarov 5/5/2016 17:24' prior: 0!
When the native runtime does not have a native implementation for a primitive, a callback into the outer Smalltalk happens which I then process, surgically operating on the state of the inner VM.!

----- Method: PrimitiveProcessor>>falseObject (in category 'accessing') -----
falseObject
        ^gdb exe externalReferences at: #MT_false!

----- Method: PrimitiveProcessor>>getExceptionEnvSlot (in category 'accessing') -----
getExceptionEnvSlot
        exceptionEnvSlot isNil ifTrue: [ exceptionEnvSlot := self nilObject ].
        ^exceptionEnvSlot !

----- Method: PrimitiveProcessor>>isTerminationContextFor (in category 'control primitives') -----
isTerminationContextFor
        | currentCtx startCtx block blockMarkEnv methodMarkEnv matchesP | self halt.
        currentCtx := MTRemoteStackFrame
                gdb: gdb
                pointer: ((self getVRegister: #R) bitAnd: 2r11 bitInvert32).
        startCtx := MTRemoteStackFrame gdb: gdb pointer: ((self getVRegister: #A) bitAnd: 2r11 bitInvert32).
        block := startCtx blockClosure.
        blockMarkEnv := block env markEnv.
        methodMarkEnv := currentCtx env markEnv.
        matchesP := (currentCtx method pointer = block compiledBlock homeMethod pointer) and:
                [ blockMarkEnv pointer = methodMarkEnv pointer ].
        self return: (matchesP
                ifTrue: [ self trueObject ]
                ifFalse: [ self falseObject ])!

----- Method: PrimitiveProcessor>>isValueMarked (in category 'control primitives') -----
isValueMarked
        | frame matchesP |
        frame := MTRemoteStackFrame gdb: gdb pointer: (self receiverOop  bitAnd: 2r11 bitInvert32).
        matchesP := frame method pointer = (gdb exe externalReferences at: #MT_valueMarked).
        self return: (matchesP
                ifTrue: [ self trueObject ]
                ifFalse: [ self falseObject ])!

----- Method: PrimitiveProcessor>>markFail (in category 'engine') -----
markFail
        | cr |
self halt.
        cr := regs at: 'cr'.
        cr := cr bitOr: 2r0010 << (4 * 2). "EQ bit in CR5"
        regs at: 'cr' put: cr!

----- Method: PrimitiveProcessor>>markSuccess (in category 'engine') -----
markSuccess
        | cr |
        cr := regs at: 'cr'.
        cr := cr bitAnd: (2r0010 << (4 * 2)) bitInvert32. "EQ bit in CR5"
        regs at: 'cr' put: cr!

----- Method: PrimitiveProcessor>>nilObject (in category 'accessing') -----
nilObject
        ^gdb exe externalReferences at: #MT_nil!

----- Method: PrimitiveProcessor>>primAddSI (in category 'integer primitives') -----
primAddSI
        | r a sum |
        r := self getVRegister: #R.
        (r bitAnd: 2r11) = 2r0001 ifFalse:[ ^self markFail ].
        r := gdb exe architecture smallIntegerToInteger: r.
        a := self getVRegister: #A.
        (a bitAnd: 2r11) = 2r0001 ifFalse:[ ^self markFail ].
        a := gdb exe architecture smallIntegerToInteger: a.
        sum := r + a.
        sum := gdb exe architecture integerToSmallInteger: sum.
        self return: sum!

----- Method: PrimitiveProcessor>>primAlignedPointerOopAt (in category 'object access primitives') -----
primAlignedPointerOopAt
        | r idx oop |
        idx := (self getVRegister: #A) >> 4.
        r := (self getVRegister: #R) bitAnd: 2r0011 bitInvert32.
        oop := gdb read32At: r + (idx*4).
        self return: oop!

----- Method: PrimitiveProcessor>>primAlignedPointerOopAtPut (in category 'object access primitives') -----
primAlignedPointerOopAtPut
        | r idx arg2  |
        idx := (self getVRegister: #A) >> 4.
        r := (self getVRegister: #R) bitAnd: 2r00011 bitInvert32.
        arg2 := gdb currentFrame arg: 2.
        gdb writeInt32: arg2 toAddr: r + (idx*4).
        self markSuccess !

----- Method: PrimitiveProcessor>>primBasicAt (in category 'object access primitives') -----
primBasicAt
        | l |
        "NB - guards"
        l := MTRemoteLiveObject gdb: gdb liveObject: (self getVRegister: #R).
        self return: (l mtBasicAt: (self getVRegister: #A) >> 4)!

----- Method: PrimitiveProcessor>>primBasicAtPut (in category 'object access primitives') -----
primBasicAtPut
        | l idx arg2 |
        "NB - guards"
        l := MTRemoteLiveObject gdb: gdb liveObject: (self getVRegister: #R).
        idx := (self getVRegister: #A) >> 4.
        arg2 := self currentFrame arg: 2.
        l mtBasicAt: idx put: arg2.
        self markSuccess !

----- Method: PrimitiveProcessor>>primBasicSize (in category 'primitives') -----
primBasicSize
        | answer |
" NB: insert prim failure guards here, such as SmallInteger "
        answer := (MTRemoteLiveObject gdb: gdb liveObject: self receiverOop) numIndexed.
        answer := (answer bitShift: 4) bitOr: 2r0001. "SI"
        self return: answer!

----- Method: PrimitiveProcessor>>primCharacterBasicAt (in category 'object access primitives') -----
primCharacterBasicAt
        | index char |
        index := self getVRegister: #A.
        "Guard that the arg is an SI:"
        (index bitAnd: 2r00011) = 1 ifFalse: [ ^self markFail ].
        index := index >> 4.
       
        char := gdb readByteAt: (self getVRegister: #R) + 8 + index - 1.
       
        "CHAR_TAG=2"
        char := char << 4 bitOr: 2.
       
        self return: char!

----- Method: PrimitiveProcessor>>primCharacterBasicAtPut (in category 'object access primitives') -----
primCharacterBasicAtPut
        | index char charOop |

        index := self getVRegister: #A.
        "Guard that the index arg is an SI"
        (index bitAnd: 2r00011) = 1 ifFalse: [ ^self markFail ].
        index := index >> 4.
       
        charOop := self currentFrame arg: 2.
        "Guard that the char arg is a char"
        (charOop bitAnd: 2r00011) = 2 ifFalse: [ ^self markFail ].
        char := charOop >> 4.
       
        gdb byteAt: (self getVRegister: #R) + 8 + index - 1 put: char.
       
        self return: charOop!

----- Method: PrimitiveProcessor>>primCharacterFromCodePoint (in category 'object access primitives') -----
primCharacterFromCodePoint
        | arg |
        arg := self getVRegister: #A.
        "Remove the SI tag and attach a CHAR tag"
        arg := (arg bitAnd: 16rFFFFFFF0) bitOr: 2r00010.
        self return: arg!

----- Method: PrimitiveProcessor>>primCharacterValue (in category 'object access primitives') -----
primCharacterValue
        | arg |
        arg := self getVRegister: #A.
        "Remove the CHAR tag and attach a SI tag"
        arg := (arg bitAnd: 16rFFFFFFF0) bitOr: 2r00001.
        self return: arg!

----- Method: PrimitiveProcessor>>primClass (in category 'primitives') -----
primClass
        | rcv md |
        rcv := MTRemoteObject gdb: gdb pointer:  (self getVRegister: #R).
        md := MTRemoteMethodDictionary gdb: gdb pointer: rcv md.
        [ md pointer = self nilObject ] whileFalse: [
                | clazz |
                clazz := md definingClass.
                clazz isRemoteNil ifFalse: [ ^self return: clazz pointer ].
                md := md superMd ].
        ^self return: self nilObject !

----- Method: PrimitiveProcessor>>primClassName (in category 'primitives') -----
primClassName
        | rcv |
        "The argument is a class."
        rcv := MTRemoteClass gdb: gdb pointer:  (self getVRegister: #R).
        self return: rcv name!

----- Method: PrimitiveProcessor>>primCurrentContext (in category 'control primitives') -----
primCurrentContext
        | context  |
        context := self currentFrame senderFrame.
        self return: (context pointer bitOr: 3)!

----- Method: PrimitiveProcessor>>primExceptionEnvironment (in category 'control primitives') -----
primExceptionEnvironment
        ^self return: self getExceptionEnvSlot !

----- Method: PrimitiveProcessor>>primFail (in category 'feature primitives') -----
primFail
        self markFail!

----- Method: PrimitiveProcessor>>primHash (in category 'object access primitives') -----
primHash
        self return: 2r0001. "SI 0"
!

----- Method: PrimitiveProcessor>>primIntDivSI (in category 'integer primitives') -----
primIntDivSI
        | r a d |
        r := self getVRegister: #R.
        (r bitAnd: 2r111) = 2r0001 ifFalse:[ ^self markFail ].
        r := gdb exe architecture smallIntegerToInteger: r.
        a := self getVRegister: #A.
        (a bitAnd: 2r111) = 2r0001 ifFalse:[ ^self markFail ].
        a := gdb exe architecture smallIntegerToInteger: a.
        d := r // a.
        d := gdb exe architecture integerToSmallInteger: d.
        self return: d!

----- Method: PrimitiveProcessor>>primIntRemSI (in category 'integer primitives') -----
primIntRemSI
        | r a rem |
        r := self getVRegister: #R.
        (r bitAnd: 2r11) = 2r0001 ifFalse:[ ^self markFail ].
        r := gdb exe architecture smallIntegerToInteger: r.
        a := self getVRegister: #A.
        (a bitAnd: 2r11) = 2r0001 ifFalse:[ ^self markFail ].
        a := gdb exe architecture smallIntegerToInteger: a.
        rem  := r \\ a.
        rem := gdb exe architecture integerToSmallInteger: rem.
        self return: rem!

----- Method: PrimitiveProcessor>>primIsBottomOfStack (in category 'control primitives') -----
primIsBottomOfStack
        | bottomP frame |
        frame := MTRemoteStackFrame gdb: gdb pointer: ((self getVRegister: #R) bitAnd: 2r11 bitInvert32).
        bottomP := frame isBottomFrame.
        self return: (bottomP
                ifTrue: [ self trueObject ]
                ifFalse: [ self falseObject ])!

----- Method: PrimitiveProcessor>>primMultiplySI (in category 'integer primitives') -----
primMultiplySI
        | r a p |
        r := self getVRegister: #R.
        (r bitAnd: 2r111) = 2r0001 ifFalse:[ ^self markFail ].
        r := gdb exe architecture smallIntegerToInteger: r.
        a := self getVRegister: #A.
        (a bitAnd: 2r111) = 2r0001 ifFalse:[ ^self markFail ].
        a := gdb exe architecture smallIntegerToInteger: a.
        p := r * a.
        p := gdb exe architecture integerToSmallInteger: p.
        self return: p!

----- Method: PrimitiveProcessor>>primNewIndexedObject (in category 'primitives') -----
primNewIndexedObject
        | clazz size |
self halt.
        size := (self getVRegister: #A) >> 4.
size >= (65536*4) ifTrue:[self halt].
        clazz := MTRemoteClass gdb: gdb pointer: self receiverOop.
        clazz structure = 5
                ifTrue: [ self allocString: size md: clazz instanceMd ]
                ifFalse: [ self allocIndexed: size md: clazz instanceMd ]!

----- Method: PrimitiveProcessor>>primNewObject (in category 'primitives') -----
primNewObject
        | clazz  |
        clazz := MTRemoteClass gdb: gdb pointer: self receiverOop.
        self return: (self
                allocOop: clazz instVarCount
                md: clazz instanceMd)!

----- Method: PrimitiveProcessor>>primPerform (in category 'control primitives') -----
primPerform
        "Perform a 0-arg send.
        Receiver in R, selector in A."
        | a selector fp frame jmpTarget |

        a := self getVRegister: #A.
        fp := self getVRegister: #FP.
        frame := MTRemoteStackFrame gdb: gdb pointer: fp.
        self setVRegister: #SP to: fp-4.
        self setVRegister: #FP to: frame senderFrame pointer.
       
        selector := MTRemoteSymbol gdb: gdb pointer: a.
        jmpTarget := (HostAssistedLookup regBase: self ram: gdb) messageSendSelector: selector symbol.
        "jmpTarget := gdb messageSendSelector: selector symbol."  "correct address to jump to in CTR!!"
        "but the contract with the primitive invocation code is that
        the address is in scratch1."
        self setVRegister: #Scratch1 to: jmpTarget
       
        !

----- Method: PrimitiveProcessor>>primPreviousContext (in category 'control primitives') -----
primPreviousContext
        | context prevAddr |
        context := self receiverOop.
        context := context bitAnd: 3 bitInvert32.
        prevAddr := gdb read32At: context.
        self return: (prevAddr bitOr: 3)!

----- Method: PrimitiveProcessor>>primPrintString (in category 'feature primitives') -----
primPrintString
        | r tag |
self halt.
        r := self receiverOop.
        tag := r bitAnd: 2r00011.
        tag = 0 ifTrue: [
                "For pointer oops, assume it's a String"
                | rs |
                rs := MTRemoteString gdb: gdb pointer: r.
                Transcript show: rs string.
                ^self markSuccess
        ].
        tag = 1 ifTrue: [
                Transcript show: (r>>4) printString.
                ^self markSuccess
        ].
        self halt!

----- Method: PrimitiveProcessor>>primReturnValueFromContext (in category 'control primitives') -----
primReturnValueFromContext
        | ctx |
        self setVRegister: #R to: (self getVRegister: #A).
        ctx := gdb read32At: (self getVRegister: #FP) - 8.
        ctx := ctx bitAnd: 2r11 bitInvert32. "strip off context immediate tag"
        self setVRegister: #FP to: ctx.
        self setVRegister: #SP to: ctx + 4.
        self markSuccess !

----- Method: PrimitiveProcessor>>primSIGreaterThan (in category 'integer primitives') -----
primSIGreaterThan
        self return: ((self getVRegister: #R) > (self getVRegister: #A)
                ifTrue: [ self trueObject ]
                ifFalse: [ self falseObject ])!

----- Method: PrimitiveProcessor>>primSIGreaterThanEqual (in category 'integer primitives') -----
primSIGreaterThanEqual
        self return: ((gdb getVRegister: #R) >= (gdb getVRegister: #A)
                ifTrue: [ self trueObject ]
                ifFalse: [ self falseObject ])!

----- Method: PrimitiveProcessor>>primSILessThan (in category 'integer primitives') -----
primSILessThan
        self return: ((self getVRegister: #R) < (self getVRegister: #A)
                ifTrue: [ self trueObject ]
                ifFalse: [ self falseObject ])!

----- Method: PrimitiveProcessor>>primSILessThanEqual (in category 'integer primitives') -----
primSILessThanEqual
        self return: ((self getVRegister: #R) <= (self getVRegister: #A)
                ifTrue: [ self trueObject ]
                ifFalse: [ self falseObject ])!

----- Method: PrimitiveProcessor>>primSay (in category 'feature primitives') -----
primSay
        " Show the receiver SI on the host transcript. "
        | something tag |
self halt.
        something := self getVRegister: #R.
        tag := something bitAnd: 2r00011.
        tag = 0 ifTrue: [ something := 'oop:', something asString, ' md:', (MTRemoteObject gdb: gdb pointer: something) md printString ].
        tag = 1 ifTrue: [ something := gdb exe architecture smallIntegerToInteger: something ].
       
        Transcript show: ('Modtalk says: ', something asString); cr.
        self markSuccess.


        !

----- Method: PrimitiveProcessor>>primSay2 (in category 'feature primitives') -----
primSay2
        " On the class side of ProtoObject. "
self halt.
        self markSuccess.


        !

----- Method: PrimitiveProcessor>>primSaySomething (in category 'feature primitives') -----
primSaySomething
self halt.
        Transcript show: 'It WORKS!!!!!!'; cr!

----- Method: PrimitiveProcessor>>primSaySomethingElse (in category 'feature primitives') -----
primSaySomethingElse
        Transcript show: 'It DOES NOT WORK!!!!!!'; cr!

----- Method: PrimitiveProcessor>>primSetExceptionEnvironment (in category 'control primitives') -----
primSetExceptionEnvironment
        | ee |
        ee := self getVRegister: #A.
        self setExceptionEnvSlot: ee;
                markSuccess !

----- Method: PrimitiveProcessor>>primStringCompare (in category 'feature primitives') -----
primStringCompare
        | r b answer |
        r := self getVRegister: #R.
        r := MTRemoteString gdb: gdb pointer: r.
        r := r string.
       
        b := self getVRegister: #A.
        b := MTRemoteString gdb: gdb pointer: b.
        b := b string.
       
        answer := r = b ifTrue: [2] ifFalse: [ r < b ifTrue: [1] ifFalse: [3] ].
        answer := gdb exe architecture integerToSmallInteger: answer.
        self return: answer!

----- Method: PrimitiveProcessor>>primSubSI (in category 'integer primitives') -----
primSubSI
        | r a diff |
        r := self getVRegister: #R.
        (r bitAnd: 2r111) = 2r0001 ifFalse:[ ^self markFail ].
        r := gdb exe architecture smallIntegerToInteger: r.
        a := self getVRegister: #A.
        (a bitAnd: 2r111) = 2r0001 ifFalse:[ ^self markFail ].
        a := gdb exe architecture smallIntegerToInteger: a.
        diff := r - a.
        diff := gdb exe architecture integerToSmallInteger: diff.
        self return: diff!

----- Method: PrimitiveProcessor>>primValue (in category 'control primitives') -----
primValue
        | addr |
        addr := (MTRemoteBlockClosure gdb: gdb pointer: self receiverOop)
                compiledBlock codeRef address.
        self setVRegister: #Scratch1 to: addr.
        self setVRegister: #X to: self receiverOop.
        self markSuccess !

----- Method: PrimitiveProcessor>>primValueWith2Args (in category 'control primitives') -----
primValueWith2Args
        | arg2 |
        arg2 := self currentFrame arg: 2.
        gdb push: arg2.
        ^self primValue!

----- Method: PrimitiveProcessor>>primValueWithArgument (in category 'control primitives') -----
primValueWithArgument
        ^self primValue "No need to specifically pass the arg because it is already in #A"!

----- Method: PrimitiveProcessor>>primValueWithArguments (in category 'control primitives') -----
primValueWithArguments
self halt!

----- Method: PrimitiveProcessor>>receiverOop (in category 'engine') -----
receiverOop
        ^self getVRegister: #R!

----- Method: PrimitiveProcessor>>return: (in category 'engine') -----
return: oop
        self setVRegister: #R to: oop.
        self markSuccess!

----- Method: PrimitiveProcessor>>setExceptionEnvSlot: (in category 'accessing') -----
setExceptionEnvSlot: oop
        exceptionEnvSlot := oop!

----- Method: PrimitiveProcessor>>trueObject (in category 'accessing') -----
trueObject
        ^gdb exe externalReferences at: #MT_true!

BasePrimitiveProcessor subclass: #PrivatePrimitiveProcessor
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Primitives'!

----- Method: PrivatePrimitiveProcessor>>primAllocEnv (in category 'primitives') -----
primAllocEnv
        | stackFrame count ptr env |
        count := gdb currentBytecode count.
        stackFrame := self currentFrame.
        ptr := self allocSlots: count serviceSlots: 2 "header, hash".
        env := MTRemoteIndexedPart gdb: gdb pointer: ptr.
        env header: (TAJObjectWriter
                declareObjectHeaderType: 'IndexedPartType'
                hashFormat: 'NoHash'
                numVars: count
                hash: 0
                meta: 0).
        env basicSlotAt: 1 put: stackFrame env pointer.
        stackFrame env: env.
        self setVRegister: #X to: ptr.
!

----- Method: PrivatePrimitiveProcessor>>primMethodClosure (in category 'primitives') -----
primMethodClosure
        |  stackFrame method blocks ptr md count block blockClosure numArgs blockClosureMDKey |

        count := gdb currentBytecode count.
        stackFrame := self currentFrame.
        method := stackFrame method.
        blocks := method blocks.
        block := MTRemoteCompiledBlock gdb: gdb pointer: (blocks at: count).
        numArgs := block numArgs.
        blockClosureMDKey := (Array
                with: #MTZeroArgumentBlockClosure_md
                with: #MTOneArgumentBlockClosure_md
                with: #MTTwoArgumentBlockClosure_md
        ) at: numArgs + 1.
        md := gdb exe externalReferences at: blockClosureMDKey.
        ptr := self allocOop: 4 md: md.
        blockClosure := MTRemoteBlockClosure gdb: gdb pointer: ptr.
        blockClosure
                literals: method literals;
                compiledBlock: block;
                env:(stackFrame env);
                receiver: (MTRemoteObject gdb: gdb pointer: (self getVRegister: #R)).
        self setVRegister: #R to: ptr.!

Object subclass: #DebugStopped
        instanceVariableNames: 'signal'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: DebugStopped class>>onSignalNum: (in category 'instance creation') -----
onSignalNum: anInteger
        ^self basicNew
                signal: (self signalNames at: anInteger)
                yourself!

----- Method: DebugStopped class>>signalNames (in category 'signal numbers') -----
signalNames
        ^#(
        SIGHUP
        SIGINT
        SIGQUIT
        SIGILL
        SIGTRAP
        SIGABRT
        SIGBUS
        SIGFPE
        SIGKILL
        SIGUSR1
        SIGSEGV
        SIGUSR2
        SIGPIPE
        SIGALRM
        SIGTERM
        SIGSTKFLT
        SIGCHLD
        SIGCONT
        SIGSTOP
        SIGTSTP
        SIGTTIN
        SIGTTOU
        SIGURG
        SIGXCPU
        SIGXFSZ
        SIGVTALRM
        SIGPROF
        SIGWINCH
        SIGIO
        SIGPWR
        SIGSYS
        SIGRTMIN
        )!

----- Method: DebugStopped>>printOn: (in category 'printing') -----
printOn: aStream
        aStream nextPutAll: 'Got '; nextPutAll: self signal asString!

----- Method: DebugStopped>>signal (in category 'accessing') -----
signal
        ^signal!

----- Method: DebugStopped>>signal: (in category 'accessing') -----
signal: aSymbol
        signal := aSymbol!

Object subclass: #Doodle
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

----- Method: Doodle>>assert:equals: (in category 'as yet unclassified') -----
assert: expected equals: actual
        ^self
                assert: expected = actual
!

Doodle subclass: #GDBDoodle
        instanceVariableNames: 'gdb'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

GDBDoodle subclass: #AbsoluteZeroPPC
        instanceVariableNames: 'memory'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

!AbsoluteZeroPPC commentStamp: 'bgs 3/25/2020 06:56' prior: 0!
See thinshell/absolute/power/absolute.s.
This gets built into an exe loaded at absolute address 0.
Execution starts at 0.
gem5 is able to simulate an MMU that can map such address.
!

----- Method: AbsoluteZeroPPC>>connectGdb (in category 'target connection') -----
connectGdb
        super connectGdb.
        memory := RemoteRAM gdb: gdb!

----- Method: AbsoluteZeroPPC>>hostIP (in category 'target connection') -----
hostIP
        ^'192.168.75.2'!

----- Method: AbsoluteZeroPPC>>makeAFewSteps (in category 'stepping logic') -----
makeAFewSteps
        self assert: gdb pc equals: 0.
        self assert: memory currentInstructionEncoding equals: 16r7c631a78.
        gdb s.
        self assert: gdb pc equals: 4.
        self assert: memory currentInstructionEncoding equals: 16r3860002a.
        gdb s.
        self assert: gdb pc equals: 8.
!

----- Method: AbsoluteZeroPPC>>pdl (in category 'target connection') -----
pdl
        ^FakeProcessorDescriptionPPC new!

----- Method: AbsoluteZeroPPC>>testAbs (in category 'target connection') -----
testAbs
        "
        AbsoluteZeroPPC  new halt ;  testAbs
        "
        self connectGdb; makeAFewSteps.
        [ "then, run at full speed until the exit() syscall"
        gdb c
                "At this point we expect gem5 to have exited and said,
                Exit code is 42"
        ] on: GdbChildExited do: [ ^self ].
        self error!

----- Method: GDBDoodle>>connectGdb (in category 'target connection') -----
connectGdb
        gdb := self debuggerClass
                host: self hostIP
                port: self tcpPort
                processorDescription: self pdl.
        ^gdb!

----- Method: GDBDoodle>>debuggerClass (in category 'target connection') -----
debuggerClass
        ^RemoteGDBSession!

----- Method: GDBDoodle>>hostIP (in category 'target connection') -----
hostIP
        self shouldBeImplemented!

----- Method: GDBDoodle>>pdl (in category 'target connection') -----
pdl
        self shouldBeImplemented!

----- Method: GDBDoodle>>tcpPort (in category 'target connection') -----
tcpPort
        ^7000!

GDBDoodle subclass: #ThinshellDoodle
        instanceVariableNames: 'memory'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

ThinshellDoodle subclass: #PPCThinshellDoodle
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

PPCThinshellDoodle subclass: #P1025ThinshellDoodle
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

----- Method: P1025ThinshellDoodle>>hostIP (in category 'target connection') -----
hostIP
        ^'192.168.75.199'!

----- Method: P1025ThinshellDoodle>>pdl (in category 'target connection') -----
pdl
        ^FakeProcessorDescriptionP1025 new!

----- Method: P1025ThinshellDoodle>>testStepThoughPreamble (in category 'tests') -----
testStepThoughPreamble
        "
        P1025ThinshellDoodle new testStepThoughPreamble
        "
        self connectGdb; stepThroughThinshellPreamble.
        [ gdb kill ] on: GdbChildExited do: [ ^self ].
        "should be unreachable"
        self error!

----- Method: P1025ThinshellDoodle>>testSurgicalJump (in category 'tests') -----
testSurgicalJump
        "
        P1025ThinshellDoodle new testSurgicalJump
        "
        self connectGdb; stepThroughThinshellPreamble.

        gdb setRegister: 'r1' to: 240.
        gdb setRegister: 'pc' to: 16r100000cc.
        [ gdb c ] on: InferiorExited do: [ :ex |
                "We expect gdbserver to say, Child exited with status 15"
                self assert: ex exitCode equals: 15.
                "The RSP protocol spec doesn't say what is allowed here,
                because targets can vary.
                For example, attempting to terminate the gdbserver by sending KILL,
                will not work with the normal GNU gdbserver.
                However, simply closing the connection will suffice."
                ^gdb socket close
                ].
       
        "shouldn't reach here"
        self error!

PPCThinshellDoodle subclass: #PPCgem5ThinshellDoodle
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

PPCgem5ThinshellDoodle subclass: #HardwareBreakpointDoodle
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

----- Method: HardwareBreakpointDoodle>>hostIP (in category 'target connection') -----
hostIP
        ^'192.168.75.2'!

----- Method: HardwareBreakpointDoodle>>installBrk (in category 'tests') -----
installBrk
        gdb insertHWBreakpointAt: self initialPC + 8!

----- Method: HardwareBreakpointDoodle>>pdl (in category 'target connection') -----
pdl
        ^FakeProcessorDescriptionPPC new!

----- Method: HardwareBreakpointDoodle>>testHWBrk (in category 'tests') -----
testHWBrk
        "
        HardwareBreakpointDoodle new halt; testHWBrk.
        "
        self connectGdb;
                installBrk.
        gdb c.
        self assert: gdb pc equals: self initialPC + 8.
        self fillNZone.
       
        "No need to advance, because this is not a trap."
        [ gdb c ] on: GdbChildExited do: [ ^self ].
        self error!

PPCgem5ThinshellDoodle subclass: #PPCIllegalStoreDoodle
        instanceVariableNames: 'isHardware'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

----- Method: PPCIllegalStoreDoodle class>>onHardware (in category 'instance creation') -----
onHardware
        "Set up the test for the real devboard."
        ^self basicNew isHardware: true!

----- Method: PPCIllegalStoreDoodle class>>onSoftware (in category 'instance creation') -----
onSoftware
        "Set up the test for gem5."
        ^self basicNew isHardware: false!

----- Method: PPCIllegalStoreDoodle>>hostIP (in category 'target connection') -----
hostIP
        ^isHardware
                ifTrue: [ '192.168.75.199' ]
                ifFalse: [ '192.168.75.2' ]!

----- Method: PPCIllegalStoreDoodle>>isHardware: (in category 'as yet unclassified') -----
isHardware: whetherToUseP1025
        isHardware := whetherToUseP1025.
        ^self!

----- Method: PPCIllegalStoreDoodle>>pdl (in category 'target connection') -----
pdl
        ^isHardware
                ifTrue: [ FakeProcessorDescriptionP1025 new ]
                ifFalse: [ FakeProcessorDescriptionPPC new ]!

----- Method: PPCIllegalStoreDoodle>>stepThroughThinshellPreamble (in category 'as yet unclassified') -----
stepThroughThinshellPreamble

        self assert: memory currentInstructionEncoding equals: 16r3920ffff. "li r9,-1"
self halt.
        gdb c.
        self assert: memory currentInstructionEncoding equals: 16r90090000. "stw r0,0(r9)"
self halt.
        gdb s. "Simulation dies"
!

----- Method: PPCIllegalStoreDoodle>>testSTW (in category 'as yet unclassified') -----
testSTW
        "
        PPCIllegalStoreDoodle onSoftware testSTW.
       
        PPCIllegalStoreDoodle onHardware testSTW.
        "
        self connectGdb;
                stepThroughThinshellPreamble!

----- Method: PPCgem5ThinshellDoodle>>hostIP (in category 'target connection') -----
hostIP
        ^'192.168.75.2'!

----- Method: PPCgem5ThinshellDoodle>>pdl (in category 'target connection') -----
pdl
        ^FakeProcessorDescriptionPPC new!

----- Method: PPCgem5ThinshellDoodle>>testManualNZone (in category 'tests') -----
testManualNZone
        "
        PPCgem5ThinshellDoodle new halt;  testManualNZone
        "
        self connectGdb;
                stepThroughThinshellPreamble;
                fillNZone.
        [ "then, run at full speed until the exit() syscall"
        gdb c
                "At this point we expect gem5 to have exited and said,
                Exit code is 42"
        ] on: GdbChildExited do: [ ^self ].
        self error
!

----- Method: PPCgem5ThinshellDoodle>>testManualNZone2 (in category 'tests') -----
testManualNZone2
        "
        PPCgem5ThinshellDoodle new testManualNZone2
        "
        self connectGdb;
                stepThroughThinshellPreamble;
                fillNZone2.
        [ "then, run at full speed until the exit() syscall"
        gdb c
                "At this point we expect gem5 to have exited and said,
                Exit code is 42"
        ] on: GdbChildExited do: [ ^self ].
        self error
!

PPCgem5ThinshellDoodle subclass: #RemoteMemoryDoodle
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

----- Method: RemoteMemoryDoodle>>hostIP (in category 'target connection') -----
hostIP
        ^'192.168.75.2'!

----- Method: RemoteMemoryDoodle>>pdl (in category 'target connection') -----
pdl
        ^FakeProcessorDescriptionPPC new!

----- Method: RemoteMemoryDoodle>>testLowLevelWrite (in category 'tests-reading') -----
testLowLevelWrite
        "
        RemoteMemoryDoodle new testLowLevelWrite
        "
        | goodAddress |
        self connectGdb.
        goodAddress := self initialPC.
        memory writeBytes: #[1 2 3 4] toAddr: goodAddress.
       
        self assert: (memory unsignedLongAtAddr: goodAddress bigEndian: true) equals: 16r01020304.
        self assert: (memory unsignedLongAt: goodAddress + 1 bigEndian: true) equals: 16r01020304.
        self assert: (memory read: 4 bytesAtAddr: goodAddress) equals: #[1 2 3 4].
        self assert: (memory unsignedByteAtAddr: 16r10000080) equals: 1.
        self assert: (memory unsignedByteAtAddr: 16r10000081) equals: 2.
       
        [ gdb kill ] on: GdbChildExited do: [ ^self ]
        !

----- Method: RemoteMemoryDoodle>>testReadFirstInstruction (in category 'tests-reading') -----
testReadFirstInstruction
        "
        RemoteMemoryDoodle new testReadFirstInstruction
        "
        | entry |
        self connectGdb.
        entry := self initialPC.
       
        self assert: (memory unsignedLongAtAddr: entry bigEndian: true) equals: 16r7c000378.
        self assert: (memory unsignedLongAtAddr: entry bigEndian: false) equals: 16r7803007c.
        self assert: (memory read: 4 bytesAtAddr: entry) equals: #[124 0 3 120].
        self assert: (memory unsignedByteAtAddr: 16r10000080) equals: 124.
       
        [ gdb kill ] on: GdbChildExited do: [ ^self ]
!

RemoteMemoryDoodle subclass: #ShmemDoodle
        instanceVariableNames: 'plainRAM'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

----- Method: ShmemDoodle>>connectGdb (in category 'target connection') -----
connectGdb
        super connectGdb.
        memory shmemSize: 536870912. "size of TAM's thinshell process image"
        plainRAM := RemoteRAM gdb: gdb.
        ^gdb!

----- Method: ShmemDoodle>>doodles (in category 'tests-agreement') -----
doodles

ShmemDoodle new testLowLevelWrite.

ShmemDoodle new testReadFirstInstruction.

ShmemDoodle new testManualNZone.

ShmemDoodle new testManualNZone2.

!

----- Method: ShmemDoodle>>remoteMemoryClass (in category 'target connection') -----
remoteMemoryClass
        ^Gem5SharedRAM!

----- Method: ShmemDoodle>>testSharedToNonShared (in category 'tests-agreement') -----
testSharedToNonShared!

----- Method: ThinshellDoodle>>connectGdb (in category 'target connection') -----
connectGdb
        super connectGdb.
        self createRAM!

----- Method: ThinshellDoodle>>createRAM (in category 'target connection') -----
createRAM
        memory := self remoteMemoryClass gdb: gdb!

----- Method: ThinshellDoodle>>fillNZone (in category 'stepping logic') -----
fillNZone
        "Fill the nZone with (programmer-assembled) machine code
        that will return the SmallInteger 42.
        The Thinshell will convert the TAM SmallInteger in #R
        (which is where the Program Initializer is expected to put it)
        into a machine integer suitable for passing to the exit() syscall."

        memory writeInt32: 16r382002a0 toAddr: self nZone+0. "li r1,672"
        memory writeInt32: 16r4e800020 toAddr: self nZone+4. "blr"
!

----- Method: ThinshellDoodle>>fillNZone2 (in category 'stepping logic') -----
fillNZone2
        "Same as fillNZone, but in one shot."

        memory writeInt32s: #(16r382002a0 16r4e800020) toAddr: self nZone+0!

----- Method: ThinshellDoodle>>initialPC (in category 'facts about thinshell') -----
initialPC
        ^16r10000080
!

----- Method: ThinshellDoodle>>nZone (in category 'facts about thinshell') -----
nZone
        ^16r100100E0!

----- Method: ThinshellDoodle>>remoteMemoryClass (in category 'target connection') -----
remoteMemoryClass
        ^RemoteRAM!

----- Method: ThinshellDoodle>>stepThroughThinshellPreamble (in category 'stepping logic') -----
stepThroughThinshellPreamble
        | initialPC nZone |
        initialPC := gdb pc.
        self assert: initialPC equals: 16r10000080.
        self assert: memory currentInstructionEncoding equals: 16r7C000378. "mr r0,r0"
        gdb s.
        self assert: gdb pc equals: initialPC + 4.
        self assert: memory currentInstructionEncoding equals: 16r3E001001. "lis r16,4097"
        gdb s.
        self assert: gdb pc equals: initialPC + 8.
        gdb s; s; s; s; s. "last non-nop"
        nZone := gdb getRegisters at: 'r16'.
        self assert: nZone equals: self nZone.
        gdb s; s; s; s; s; s. "bunch of nops (there are more!!)"
        self assert: gdb pc equals: 16r100000B4!

GDBDoodle subclass: #X86JumpDoodle
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

----- Method: X86JumpDoodle>>hostIP (in category 'target connection') -----
hostIP
        ^'192.168.75.2'!

----- Method: X86JumpDoodle>>pdl (in category 'target connection') -----
pdl
        ^FakeProcessorDescriptionX86 new!

----- Method: X86JumpDoodle>>tcpPort (in category 'target connection') -----
tcpPort
        ^7000!

----- Method: X86JumpDoodle>>testAtomicSimpleCPU (in category 'tests') -----
testAtomicSimpleCPU
        "
        X86JumpDoodle new testAtomicSimpleCPU
        "
        self halt; connectGdb.
        gdb pc: 17.
        gdb s.
        gdb pc.
        gdb getRegisters at: 'eax'.
        gdb getRegisters at: 'ebp'.!

Object subclass: #FakeProcessorDescription
        instanceVariableNames: 'regsInGPacket'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

----- Method: FakeProcessorDescription>>endian (in category 'accessing') -----
endian
        ^self class endian!

----- Method: FakeProcessorDescription>>initRegsInGPacket (in category 'accessing') -----
initRegsInGPacket
        "Do not try to use the real GdbXmlParser.
        On some Smalltalks under development, there is no XML."
        | regNum |
        regNum := 0.
        regsInGPacket := self class fakeFeatures collect: [ :reg |
                | rt |
                rt := RSPOneRegisterTransfer new
                        regName: (reg first);
                        width: (reg second);
                        isLittleEndian: (self endian = #little);
                        regNum: regNum;
                        yourself.
                regNum := regNum + 1.
               
                rt ]!

----- Method: FakeProcessorDescription>>regsInGPacket (in category 'accessing') -----
regsInGPacket
        regsInGPacket isNil ifTrue: [ self initRegsInGPacket ].
        ^regsInGPacket !

FakeProcessorDescription subclass: #FakeProcessorDescriptionPPC
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

FakeProcessorDescriptionPPC subclass: #FakeProcessorDescriptionP1025
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

!FakeProcessorDescriptionP1025 commentStamp: 'BorisShingarov 3/13/2020 01:27' prior: 0!
This will go away when we implement xi:include!

----- Method: FakeProcessorDescriptionP1025 class>>fakeFeatures (in category 'as yet unclassified') -----
fakeFeatures
        ^#(
#('r0' 32)  #('r1' 32)  #('r2' 32)  #('r3' 32)  #('r4' 32)  #('r5' 32)  #('r6' 32)  #('r7' 32)
#('r8' 32)  #('r9' 32)  #('r10' 32) #('r11' 32) #('r12' 32) #('r13' 32) #('r14' 32) #('r15' 32)
#('r16' 32) #('r17' 32) #('r18' 32) #('r19' 32) #('r20' 32) #('r21' 32) #('r22' 32) #('r23' 32)
#('r24' 32) #('r25' 32) #('r26' 32) #('r27' 32) #('r28' 32) #('r29' 32) #('r30' 32) #('r31' 32)

#('ev0h' 32)  #('ev1h' 32)  #('ev2h' 32)  #('ev3h' 32)  #('ev4h' 32)  #('ev5h' 32)  #('ev6h' 32)  #('ev7h' 32)
#('ev8h' 32)  #('ev9h' 32)  #('ev10h' 32) #('ev11h' 32) #('ev12h' 32) #('ev13h' 32) #('ev14h' 32) #('ev15h' 32)
#('ev16h' 32) #('ev17h' 32) #('ev18h' 32) #('ev19h' 32) #('ev20h' 32) #('ev21h' 32) #('ev22h' 32) #('ev23h' 32)
#('ev24h' 32) #('ev25h' 32) #('ev26h' 32) #('ev27h' 32) #('ev28h' 32) #('ev29h' 32) #('ev30h' 32) #('ev31h' 32)

#('pc' 32)
#('msr' 32)
#('cr' 32)
#('lr' 32)
#('ctr' 32)
#('xer' 32)

#('orig_r3' 32)
#('trap' 32)
#('acc' 64)
#('spefscr' 32)
)
!

----- Method: FakeProcessorDescriptionPPC class>>endian (in category 'as yet unclassified') -----
endian
        ^#big!

----- Method: FakeProcessorDescriptionPPC class>>fakeFeatures (in category 'as yet unclassified') -----
fakeFeatures
        ^#(
#('r0' 32)  #('r1' 32)  #('r2' 32)  #('r3' 32)  #('r4' 32)  #('r5' 32)  #('r6' 32)  #('r7' 32)
#('r8' 32)  #('r9' 32)  #('r10' 32) #('r11' 32) #('r12' 32) #('r13' 32) #('r14' 32) #('r15' 32)
#('r16' 32) #('r17' 32) #('r18' 32) #('r19' 32) #('r20' 32) #('r21' 32) #('r22' 32) #('r23' 32)
#('r24' 32) #('r25' 32) #('r26' 32) #('r27' 32) #('r28' 32) #('r29' 32) #('r30' 32) #('r31' 32)

#('f0' 64)  #('f1' 64)  #('f2' 64)  #('f3' 64)  #('f4' 64)  #('f5' 64)  #('f6' 64)  #('f7' 64)
#('f8' 64)  #('f9' 64)  #('f10' 64) #('f11' 64) #('f12' 64) #('f13' 64) #('f14' 64) #('f15' 64)
#('f16' 64) #('f17' 64) #('f18' 64) #('f19' 64) #('f20' 64) #('f21' 64) #('f22' 64) #('f23' 64)
#('f24' 64) #('f25' 64) #('f26' 64) #('f27' 64) #('f28' 64) #('f29' 64) #('f30' 64) #('f31' 64)

#('pc' 32)
#('msr' 32)
#('cr' 32)
#('lr' 32)
#('ctr' 32)
#('xer' 32)
)
!

----- Method: FakeProcessorDescriptionPPC>>architectureName (in category 'as yet unclassified') -----
architectureName
        ^'powerpc'!

FakeProcessorDescription subclass: #FakeProcessorDescriptionX86
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-Doodles'!

----- Method: FakeProcessorDescriptionX86 class>>endian (in category 'as yet unclassified') -----
endian
        ^#little!

----- Method: FakeProcessorDescriptionX86 class>>fakeFeatures (in category 'as yet unclassified') -----
fakeFeatures
        ^#(
#('eax' 32)  #('ecx' 32)  #('edx' 32)  #('ebx' 32)  #('esp' 32)  #('ebp' 32)  #('esi' 32)  #('edi' 32)
#('eip' 32)  #('eflags' 32)  #('cs' 32) #('ss' 32) #('ds' 32) #('es' 32) #('fs' 32) #('gs' 32)
)
"
#('st0' 80) #('st1' 80) #('st2' 80) #('st3' 80) #('st4' 80) #('st5' 80) #('st6' 80) #('st7' 80)

#('fctrl' 32)
#('fstat' 32)
#('ftag' 32)
#('fiseg' 32)
#('fioff' 32)
#('foseg' 32)
#('fooff' 32)
#('fop' 32)
)
"!

----- Method: FakeProcessorDescriptionX86>>architectureName (in category 'as yet unclassified') -----
architectureName
        ^'x86'!

----- Method: FakeProcessorDescriptionX86>>pcRegisterName (in category 'as yet unclassified') -----
pcRegisterName
        ^'eip'!

Object subclass: #GdbXmlParser
        instanceVariableNames: 'isLittleEndian'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: GdbXmlParser class>>endian: (in category 'API') -----
endian: aSymbol
        | le |
        aSymbol == #big ifTrue: [ le := false ]
                ifFalse: [ aSymbol == #little ifTrue: [ le := true ] ifFalse: [ self error: 'Endian must be big or little' ]].
        ^self basicNew
                isLittleEndian: le!

----- Method: GdbXmlParser class>>new (in category 'API') -----
new
        self error: 'Please use #endian:'!

----- Method: GdbXmlParser class>>parseFile:in:assumeEndian: (in category 'API') -----
parseFile: fileName in: path assumeEndian: aSymbol
        | f s |
        f := FileStream fileNamed:
                path, '/', fileName.
        s := f contentsOfEntireFile.
        f close.
        ^ (self endian: aSymbol) parseString: s!

----- Method: GdbXmlParser>>isLittleEndian: (in category 'private') -----
isLittleEndian: aBoolean
        isLittleEndian := aBoolean.
        ^self!

----- Method: GdbXmlParser>>parseString: (in category 'API') -----
parseString: s
        | parser |
        parser := XMLDOMParser on: s.
        ^self processXML: parser parseDocument root.!

----- Method: GdbXmlParser>>processXML: (in category 'private') -----
processXML: root
        | oneRegTransfers regNum feature regs |
        feature := root nodesDetect: [ :aChild | aChild isElementNamed: 'feature' ].
        regs := feature nodesSelect:  [ :aChild | aChild isElementNamed: 'reg' ].
        regNum := 0.
        oneRegTransfers := regs collect: [ :regNode |
                | rt |
                rt := RSPOneRegisterTransfer new
                        regName: (regNode attributeAt: 'name');
                        width: ((regNode attributeAt: 'bitsize') asInteger);
                        isLittleEndian: isLittleEndian;
                        regNum: regNum;
                        yourself.
                regNum := regNum + 1.
                rt ].
       
        oneRegTransfers := oneRegTransfers asOrderedCollection sorted: [ :rA :rB | rA regNum <= rB regNum ].
       
        "Verify that we got all registers from 0 to the total number, without holes."
        regNum := 0.
        oneRegTransfers do: [ :rt |
                rt regNum == regNum ifFalse: [ self error ].
                regNum := regNum + 1 ].
        ^oneRegTransfers!

Object subclass: #HostAssistedLookup
        instanceVariableNames: 'regBase ram'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: HostAssistedLookup class>>regBase:ram: (in category 'instance creation') -----
regBase: regBase ram: ram
        ^self new
                regBase: regBase;
                ram: ram;
                yourself!

----- Method: HostAssistedLookup>>activateCM: (in category 'API') -----
activateCM: cm
        | jmpTarget |
        jmpTarget := cm codeRef address.
        regBase
                setRegister: 'ctr' to: jmpTarget; "we should do something about it"
                setVRegister: #X to: cm pointer.
        ^jmpTarget!

----- Method: HostAssistedLookup>>messageSendSelector: (in category 'API') -----
messageSendSelector: selectorSymbol
        | receiver  mdRef md  cm |
        receiver := regBase getVRegister: #R.
        mdRef := ram mdFor: receiver.
        md := MTRemoteMethodDictionary gdb: ram pointer: mdRef.
        cm := md lookupSelector: selectorSymbol.
        ^self activateCM: cm!

----- Method: HostAssistedLookup>>ram (in category 'accessing') -----
ram
        ^ ram!

----- Method: HostAssistedLookup>>ram: (in category 'accessing') -----
ram: anObject
        ram := anObject!

----- Method: HostAssistedLookup>>regBase (in category 'accessing') -----
regBase
        ^ regBase!

----- Method: HostAssistedLookup>>regBase: (in category 'accessing') -----
regBase: anObject
        regBase := anObject!

Object subclass: #MTXMemory
        instanceVariableNames: 'ram layout currentHeapAllocPtr setup'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-TAJ'!

----- Method: MTXMemory class>>jumpTableSize (in category 'as yet unclassified') -----
jumpTableSize
        " In entries as opposed to bytes "
        ^1024
!

----- Method: MTXMemory>>alloc: (in category 'as yet unclassified') -----
alloc: nBytes
        ^self baseAlloc: nBytes + 4 "for the hash on 32-bit machines"!

----- Method: MTXMemory>>architecture (in category 'as yet unclassified') -----
architecture
        ^self targetSetup architecture!

----- Method: MTXMemory>>baseAlloc: (in category 'as yet unclassified') -----
baseAlloc: nBytes
        | evenBytes answer |
        answer := currentHeapAllocPtr.
        nBytes \\ 16 = 0
                ifTrue: [ evenBytes := nBytes ]
                ifFalse: [ evenBytes := (nBytes bitOr: 16r0F) + 1 ].
        currentHeapAllocPtr := currentHeapAllocPtr + evenBytes.
        ^answer!

----- Method: MTXMemory>>currentGrade (in category 'as yet unclassified') -----
currentGrade!

----- Method: MTXMemory>>initialize (in category 'as yet unclassified') -----
initialize
        self initializeGDB.
        ^self!

----- Method: MTXMemory>>initializeGDB (in category 'as yet unclassified') -----
initializeGDB
        setup := TAJTargetSetup current.
        ram := setup gdbClass  
                host: setup host
                port: setup port
                processorDescription: setup architecture isa.
        layout := ThinshellAddressLayout gdb: ram.
        currentHeapAllocPtr := layout heap + (self class jumpTableSize * 4).
        ^self!

----- Method: MTXMemory>>jumpTable (in category 'as yet unclassified') -----
jumpTable
        ^layout heap
!

----- Method: MTXMemory>>layout (in category 'as yet unclassified') -----
layout
        ^layout!

----- Method: MTXMemory>>newChunk (in category 'as yet unclassified') -----
newChunk!

----- Method: MTXMemory>>ram (in category 'as yet unclassified') -----
ram
        ^ram!

----- Method: MTXMemory>>startAllocatingOnTarget (in category 'as yet unclassified') -----
startAllocatingOnTarget
        ram setVRegister: #HEAP to: currentHeapAllocPtr!

----- Method: MTXMemory>>targetSetup (in category 'as yet unclassified') -----
targetSetup
        ^setup!

Object subclass: #MagicSurgeon
        instanceVariableNames: 'gdb'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

!MagicSurgeon commentStamp: 'BorisShingarov 3/7/2020 20:00' prior: 0!
Execution of the inner (target) Smalltalk VM stopped at a surgery point.!

MagicSurgeon subclass: #MTHostCallback
        instanceVariableNames: 'primitiveProcessor privatePrimitiveProcessor'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-TAJ'!

----- Method: MTHostCallback class>>gdb: (in category 'instance creation') -----
gdb: gdb
        ^self new
                gdb: gdb;
                yourself!

----- Method: MTHostCallback>>call (in category 'surgery') -----
call
        | methodDef cmRef regs |
        methodDef := gdb currentBytecode method value.
        regs := gdb getRegisters.
        regs at: 'ctr' put: (gdb exe externalReferences at: methodDef codeRuntimeName).
        cmRef := gdb exe externalReferences at: methodDef globalName.
        regs at: (TAJWriter registerMap at: #X) put: cmRef.
        gdb setRegisters: regs.
        gdb s!

----- Method: MTHostCallback>>getRegisters (in category 'surgery') -----
getRegisters
self halt!

----- Method: MTHostCallback>>handleDNU (in category 'surgery') -----
handleDNU
        | regs receiver selector className |
        regs := gdb getRegisters.
        receiver := regs at: 'r1'.
        receiver := MTRemoteObject gdb: gdb pointer: receiver.
        className := receiver mdObject definingClass name symbol.
        selector := regs at: 'r7'.
        selector := MTRemoteSymbol gdb: gdb pointer: selector.
        selector := selector symbol.
        self halt!

----- Method: MTHostCallback>>inspectionPoint (in category 'surgery') -----
inspectionPoint
self halt.
" selectorOop := self getRegisters at: 'r7'.
        primSaySelector := exe externalReferences at: #Symbol_primSay.
        selectorOop = primSaySelector ifTrue: [
                siOOP := self getVRegister: #R.
                self pharoObjectForOop: siOOP.
                self halt.
                siMD := self mdFor: siOOP.
                superMD := (MTRemoteMethodDictionary gdb: self pointer: siMD) superMd.
                superSuperMD := superMD superMd.
                 ]."
        "anotherWay := self currentBytecode selector value."
        "gdb s"!

----- Method: MTHostCallback>>messageSend (in category 'surgery') -----
messageSend
        ^self messageSendSelector: gdb currentBytecode selector value!

----- Method: MTHostCallback>>primitive (in category 'surgery') -----
primitive
        self primitiveProcessor
                processPrimitive: gdb currentBytecode selector value
                !

----- Method: MTHostCallback>>primitiveProcessor (in category 'accessing') -----
primitiveProcessor
        primitiveProcessor isNil ifTrue: [ primitiveProcessor := PrimitiveProcessor gdb: gdb ].
        ^primitiveProcessor !

----- Method: MTHostCallback>>privatePrimitive (in category 'accessing') -----
privatePrimitive
        self privatePrimitiveProcessor
                processPrimitive: gdb currentBytecode selector value
                !

----- Method: MTHostCallback>>privatePrimitiveProcessor (in category 'accessing') -----
privatePrimitiveProcessor
        privatePrimitiveProcessor isNil ifTrue: [ privatePrimitiveProcessor := PrivatePrimitiveProcessor gdb: gdb ].
        ^privatePrimitiveProcessor !

----- Method: MTHostCallback>>process (in category 'API') -----
process
        | callNo |
        callNo := gdb getRegisters at: 'r22'. "cf. TAJWriter>>nextPutMagic:"
        callNo = 1 ifTrue: [ ^self messageSend ].
        callNo = 2 ifTrue: [ ^self primitive ].
        callNo = 3 ifTrue: [ ^self return ].
        callNo = 4 ifTrue: [ ^self privatePrimitive ].
        callNo = 5 ifTrue: [ ^self call ].
        callNo = 6 ifTrue: [ ^self handleDNU ].
        callNo = 7 ifTrue: [ ^self inspectionPoint ].
        self error: 'Unknown callback'!

----- Method: MTHostCallback>>return (in category 'surgery') -----
return
        | cm numToDrop |
        self halt.
        cm := MTRemoteCompiledMethod gdb: self pointer: (self getVRegister: #X).
        numToDrop := cm numArgs - 1 max: 0.
        numToDrop = 0 ifFalse: [ self setVRegister: #SP to: (self getVRegister: #SP) - (numToDrop * 4) ]
!

----- Method: MagicSurgeon>>gdb (in category 'accessing') -----
gdb
        ^ gdb!

----- Method: MagicSurgeon>>gdb: (in category 'accessing') -----
gdb: anObject
        gdb := anObject!

----- Method: MagicSurgeon>>process (in category 'API') -----
process
        self subclassResponsibility !

Object subclass: #RSPOneRegisterTransfer
        instanceVariableNames: 'regName width isLittleEndian regNum'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: RSPOneRegisterTransfer>>isLittleEndian (in category 'accessing') -----
isLittleEndian
        ^ isLittleEndian!

----- Method: RSPOneRegisterTransfer>>isLittleEndian: (in category 'accessing') -----
isLittleEndian: anObject
        isLittleEndian := anObject!

----- Method: RSPOneRegisterTransfer>>readFrom: (in category 'reading') -----
readFrom: aStream
        | text int |
        text := aStream next: width//4.
        int := Integer readFrom: text base: 16.
        isLittleEndian ifTrue: [ int := int byteSwap32 ].
        "TODO - Different types (e.g. IEEE-754)"
        ^int!

----- Method: RSPOneRegisterTransfer>>regName (in category 'accessing') -----
regName
        ^ regName!

----- Method: RSPOneRegisterTransfer>>regName: (in category 'accessing') -----
regName: anObject
        regName := anObject!

----- Method: RSPOneRegisterTransfer>>regNum (in category 'accessing') -----
regNum
        ^ regNum!

----- Method: RSPOneRegisterTransfer>>regNum: (in category 'accessing') -----
regNum: anObject
        regNum := anObject!

----- Method: RSPOneRegisterTransfer>>width (in category 'accessing') -----
width
        ^ width!

----- Method: RSPOneRegisterTransfer>>width: (in category 'accessing') -----
width: anObject
        width := anObject!

----- Method: RSPOneRegisterTransfer>>write:to: (in category 'writing') -----
write: aDictionary to: aStream
        | value bytes |
        value := aDictionary at: self regName.
        isLittleEndian ifTrue: [ value := value byteSwap32 ].
        bytes := value printStringBase: 16 length: self width // 4 padded: true.
        aStream nextPutAll: bytes!

Object subclass: #RemoteGDBTransport
        instanceVariableNames: 'socket'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

RemoteGDBTransport subclass: #RemoteGDB
        instanceVariableNames: 'packetSize processorDescription tStatus why supported vCont'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: RemoteGDB class>>host:port:processorDescription: (in category 'instance creation') -----
host: h port: p processorDescription: pd
        "Create an instance, connect to the remote server, and fully prepare the debugging session."
        ^(self host: h port: p)
                processorDescription: pd;
                prepareSession;
                yourself!

----- Method: RemoteGDB>>analyzeContinueAnswer: (in category 'stop codes') -----
analyzeContinueAnswer: answer
        answer isEmpty ifTrue: [ self error: 'Empty Stop-Reply packet' ].
        answer first = $S ifTrue: [ ^self analyzeContinueAnswerS: answer allButFirst ].
        answer first = $T ifTrue: [ ^self analyzeContinueAnswerT: answer allButFirst ].
        answer first = $W ifTrue: [ ^self inferiorExited: answer ].
        "Something unknown / as-yet-unimplemented"
        self error: answer!

----- Method: RemoteGDB>>analyzeContinueAnswerS: (in category 'stop codes') -----
analyzeContinueAnswerS: answer
        "The program received signal number AA (a two-digit hexadecimal number).
        This is equivalent to a T response with no n:r pairs."
        ^DebugStopped onSignalNum: (self signalNumberFrom: answer)
!

----- Method: RemoteGDB>>analyzeContinueAnswerT: (in category 'stop codes') -----
analyzeContinueAnswerT: answer
        | signal textPairs importantRegs thread core stopReason stopArgument |
        signal := self signalNumberFrom: answer.
        textPairs := answer copyFrom: 3 to: answer size.
        textPairs := textPairs findTokens: ';'.
        importantRegs := Dictionary new.
        core := nil.
        thread := nil.
        stopReason := nil.
        stopArgument := nil.
        textPairs do: [ :textPair |
                | pair k v |
                pair := textPair findTokens: ':'.
                k := pair first.
                v := pair second.
                (self recognizedStopCodes includes: k)
                        ifTrue: [ stopReason := k. stopArgument := v ] ifFalse: [
                k = 'thread' ifTrue: [ thread := v ] ifFalse: [
                k = 'core' ifTrue: [ core := v ] ifFalse: [
                importantRegs at: k put: (Integer readFrom: k base: 16)
                "TODO: Missing the reserved case;
                this will be handled by catching exception in #readFrom: and discarding it"
        ]]]].
        self shouldBeImplemented "In TAM, this simply returns; processing is done in the sender after this call."
!

----- Method: RemoteGDB>>c (in category 'RSP commands') -----
c
        " Continue. "
        | answer |
        answer := self q: 'c'.  "NB: on some platforms, we have wanted 'vCont;c'.  I forgot why."
        ^self analyzeContinueAnswer: answer!

----- Method: RemoteGDB>>decodeGPacket: (in category 'private') -----
decodeGPacket: aStream
        | registerTransfers regs |
        registerTransfers := processorDescription regsInGPacket.
        regs := Dictionary new.
        registerTransfers do: [ :rt |
                | nextValue |
                aStream atEnd ifTrue: [ ^regs ].
                nextValue := rt readFrom: aStream.
                regs at: rt regName put: nextValue ].
        ^regs

!

----- Method: RemoteGDB>>getRegisters (in category 'RSP commands') -----
getRegisters
        | answer stream |
        answer := self q: 'g'.
        stream := ReadStream on: answer
                from: 1
                to: answer size.
        ^self decodeGPacket: stream!

----- Method: RemoteGDB>>gtInspectorPreviewIn: (in category 'private') -----
gtInspectorPreviewIn: composite
        <gtInspectorPresentationOrder: 20>
        composite morph
                title: 'Registers';
                morph: [ GdbRegistersMorph on: self ]!

----- Method: RemoteGDB>>inferiorExited: (in category 'stop codes') -----
inferiorExited: fullAnswer
        | exitCode |
        exitCode := Integer readFrom: fullAnswer copyWithoutFirst base: 16.
        InferiorExited signalWithExitCode: exitCode !

----- Method: RemoteGDB>>insertHWBreakpointAt: (in category 'general query commands') -----
insertHWBreakpointAt: addr
        | answer |
        answer := self q: 'Z1,',
                addr printStringHex,
                ',4'.
        answer = 'OK' ifFalse: [ self error ]!

----- Method: RemoteGDB>>insertSWBreakpointAt: (in category 'general query commands') -----
insertSWBreakpointAt: addr
        | answer |
        answer := self q: 'Z1,',
                addr printStringHex,
                ',4'.
        answer = 'OK' ifFalse: [ self error ]!

----- Method: RemoteGDB>>kill (in category 'RSP commands') -----
kill
        [ | answer |
        answer := self q: 'k'.
        answer = 'OK' ifFalse: [ self error: answer ].
        ^self ] on: ConnectionClosed do: [ ^self ]
!

----- Method: RemoteGDB>>nameForInspector (in category 'private') -----
nameForInspector
        ^'GDB'!

----- Method: RemoteGDB>>packetSize (in category 'general query commands') -----
packetSize
        packetSize isNil ifTrue: [
                | ps |
                ps := supported detect: [ :q | q beginsWith: 'PacketSize=' ].
                ps := ps copyFrom: 12 to: ps size.
                packetSize := SmallInteger readFrom: ps base: 16 ].
        ^packetSize !

----- Method: RemoteGDB>>processorDescription (in category 'private') -----
processorDescription
        ^processorDescription!

----- Method: RemoteGDB>>processorDescription: (in category 'private') -----
processorDescription: descr
        processorDescription := descr!

----- Method: RemoteGDB>>q: (in category 'private') -----
q: q
        ^self
                send: q;
                receive!

----- Method: RemoteGDB>>qOffsets (in category 'general query commands') -----
qOffsets
        ^self q: 'qOffsets'!

----- Method: RemoteGDB>>qStatus (in category 'general query commands') -----
qStatus
        ^self q: 'qStatus'!

----- Method: RemoteGDB>>qSupported (in category 'general query commands') -----
qSupported
        supported := self q: 'qSupported:swbreak+'.
        supported isEmpty ifTrue: [ ^self error: 'qSupported returned empty string' ].
        supported := supported findTokens: ';'!

----- Method: RemoteGDB>>qTStatus (in category 'general query commands') -----
qTStatus
        tStatus := self q: 'qTStatus'!

----- Method: RemoteGDB>>recognizedStopCodes (in category 'stop codes') -----
recognizedStopCodes
        ^#(
        'watch' 'rwatch' 'awatch'
        'syscall_entry' 'syscall_return'
        'library' 'replaying'
        'swbreak' 'hwbreak'
        'fork' 'vfork' 'vforkdone'
        'exec' 'create'
        )!

----- Method: RemoteGDB>>s (in category 'RSP commands') -----
s
        "Single step.
        Return control with signal 5 (TRAP),
        or if the execution of the current instruction failed, with whatever signal happened."
        | answer |
        answer := self q: 's'.
        ^self analyzeContinueAnswer: answer
!

----- Method: RemoteGDB>>setRegisters: (in category 'RSP commands') -----
setRegisters: aDict
        | answer stream registerTransfers |
        stream := WriteStream on: String new.
        registerTransfers := processorDescription regsInGPacket.
        registerTransfers do: [ :rt |
                rt write: aDict to: stream ].
       
        answer := self q: 'G', stream contents.
        answer = 'OK' ifFalse: [self error: answer]!

----- Method: RemoteGDB>>setThread:t: (in category 'RSP commands') -----
setThread: c t: t
        " Hxyyyy family of commands (e.g. Hc-1 or Hg0). "
        | answer |
        answer := self q: 'H', c, t printStringHex.
        answer = 'OK' "ifFalse: [ self error: answer ]" "I've seen this happen in normal operation of the GNU GDB and silently ignored"
!

----- Method: RemoteGDB>>signalNumberFrom: (in category 'stop codes') -----
signalNumberFrom: answer
        ^Integer readFrom: (answer copyFrom: 1 to: 2) base: 16
!

----- Method: RemoteGDB>>vCont (in category 'RSP commands') -----
vCont
        "Stepping mechanisms supported by the server"
        vCont := self q: 'vCont?'!

----- Method: RemoteGDB>>why (in category 'RSP commands') -----
why
        why := self q: '?'!

----- Method: RemoteGDB>>writeBytes:toAddr: (in category 'RSP commands') -----
writeBytes: aByteArray toAddr: addr
        | textualAddr currAddr answer |
        currAddr := addr.
        aByteArray do: [ :byte |
                | data |
                data := byte printStringBase: 16 length: 2 padded: true.
                textualAddr := currAddr printStringBase: 16 length: 8 padded: true.
                answer := self
                        q: 'M', textualAddr,  ',1:', data.
                answer = 'OK' ifFalse: [ self error: answer ].
                currAddr := currAddr + 1
        ]!

RemoteGDB subclass: #RemoteGDBSession
        instanceVariableNames: 'qXfer vFile'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

RemoteGDBSession subclass: #ExecutableAwareGDB
        instanceVariableNames: 'exe'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-TAJ'!

----- Method: ExecutableAwareGDB>>currentBytecode (in category 'representation') -----
currentBytecode
        | def vPC |
        def := self exe whereAmI.
        vPC := self getVRegister: #VPC.
        ^def ir instructions at: vPC+1!

----- Method: ExecutableAwareGDB>>currentFrame (in category 'representation') -----
currentFrame
        ^MTRemoteStackFrame gdb: self pointer: (self getVRegister: #FP)!

----- Method: ExecutableAwareGDB>>exe (in category 'accessing') -----
exe
        ^ exe!

----- Method: ExecutableAwareGDB>>exe: (in category 'accessing') -----
exe: anObject
        exe := anObject!

----- Method: ExecutableAwareGDB>>findPreviousCallers:from: (in category 'debug support') -----
findPreviousCallers: maxCallersToFind from: spOrNil
        | sp |
        maxCallersToFind < 1 ifTrue: [ ^OrderedCollection new ].
        sp := spOrNil isNil ifTrue: [ self getVRegister: #SP ] ifFalse: [ spOrNil ].
        [ self isInStack: sp ] whileTrue: [
                | slot |
                slot := self read32At: sp.
                sp := sp - 4.
                (self isInNZone: slot) ifTrue: [ ^(self findPreviousCallers: maxCallersToFind - 1 from: sp) addFirst: (exe whereIsPC: slot); yourself ]
        ].
        ^OrderedCollection new!

----- Method: ExecutableAwareGDB>>getVRegister: (in category 'representation') -----
getVRegister: r
        | nRegister |
        nRegister := TAJWriter vRegister: r.
        ^self getRegisters at: 'r', nRegister printString!

----- Method: ExecutableAwareGDB>>isInNZone: (in category 'debug support') -----
isInNZone: anAddress
        ^(anAddress < 272699392) and: [ anAddress > 268505088 ]!

----- Method: ExecutableAwareGDB>>isInStack: (in category 'debug support') -----
isInStack: anAddress
        ^(anAddress >= 272699392) and: [ anAddress < 273747968 ]!

----- Method: ExecutableAwareGDB>>isMTNil: (in category 'representation') -----
isMTNil: anOop
        ^anOop = (self exe externalReferences at: #MT_nil)!

----- Method: ExecutableAwareGDB>>mdFor: (in category 'representation') -----
mdFor: oop
        | tagBits   |
        tagBits := oop bitAnd: 3.
        tagBits == 1 ifTrue: [
                "SmallInteger"
                ^exe externalReferences at: #MTSmallInteger_md ].
        tagBits == 3 ifTrue: [
                "Context"
                ^exe externalReferences at: #MTContext_md ].
        ^self read32At: oop + 4!

----- Method: ExecutableAwareGDB>>pharoObjectForOop: (in category 'representation') -----
pharoObjectForOop: oop
        | tag |
        tag := oop bitAnd: 2r111.
        tag == 0 ifTrue: [ ^MTRemoteObject gdb: self pointer: oop ].
        tag == 1 ifTrue: [ ^exe architecture oop >> 4 ]. "SmallInteger; this code better delegate to the Target"
        tag == 3 ifTrue: [ ^MTRemoteObject gdb: self pointer: (oop bitAnd: 16rFFFFFFF0) ].
        self halt "I don't know what tag this is"!

----- Method: ExecutableAwareGDB>>pharoObjectForVReg: (in category 'representation') -----
pharoObjectForVReg: vReg
        ^self pharoObjectForOop: (self getVRegister: vReg)!

----- Method: ExecutableAwareGDB>>processCallback (in category 'surgery') -----
processCallback
        (MTHostCallback gdb: self) process
                !

----- Method: ExecutableAwareGDB>>push: (in category 'representation') -----
push: oop
        | sp |
        sp := self getVRegister: #SP.
        self writeInt32: oop toAddr: sp+4.
        self setVRegister: #SP to: sp+4!

----- Method: ExecutableAwareGDB>>setVRegister:to: (in category 'representation') -----
setVRegister: r to: x
        | nRegister |
        nRegister := TAJWriter vRegister: r.
        self setRegister: nRegister to: x!

----- Method: ExecutableAwareGDB>>tryRunning (in category 'surgery') -----
tryRunning
        self runWithMagickCallback: [ self processCallback ]!

----- Method: ExecutableAwareGDB>>tryRunningSteps (in category 'surgery') -----
tryRunningSteps
        self runStepsWithMagickCallback: [ self processCallback ]!

----- Method: RemoteGDBSession>>advancePastTrap (in category 'magick') -----
advancePastTrap
        | regs |
        regs := self getRegisters.
        regs at: 'pc' put: (regs at: 'pc') + 4.
        self setRegisters: regs.!

----- Method: RemoteGDBSession>>askFeatures (in category 'RSP commands') -----
askFeatures
        " Ask the stub for the target feature descriptor, and return it.
          If the stub doesn't provide it, return nil. "
        self supportsFeatures
                ifTrue: [ ^self qXfer features: 'target.xml' ]
                ifFalse: [ ^nil ]
                !

----- Method: RemoteGDBSession>>currentInstruction (in category 'RSP commands') -----
currentInstruction
        ^processorDescription disassemble: self currentInstructionEncoding
!

----- Method: RemoteGDBSession>>getRegister: (in category 'accessing') -----
getRegister: r
        | regs |
        regs := self getRegisters.
        ^regs at: r!

----- Method: RemoteGDBSession>>pc (in category 'RSP commands') -----
pc
        ^self getRegisters at: self processorDescription pcRegisterName !

----- Method: RemoteGDBSession>>pc: (in category 'RSP commands') -----
pc: newPC
        ^self setRegister: self processorDescription pcRegisterName to: newPC!

----- Method: RemoteGDBSession>>prepareSession (in category 'RSP commands') -----
prepareSession
        self qSupported.
        self packetSize.
        self setThread: 'g' t: 0.
        self qStatus = '' ifFalse: [ self error: 'Bad status' ].
        self vCont.

        self askFeatures ifNotNil: [ :xml | processorDescription regsInGPacket: (GdbXmlParser new processXML: xml) ]
!

----- Method: RemoteGDBSession>>printRegistersOn: (in category 'printing') -----
printRegistersOn: aStream
        | allRegisters |
        allRegisters := self getRegisters.
        allRegisters keysAndValuesDo: [ :regName :regValue |
                (#('ds' 'ss' 'cs' 'es' 'fs' 'gs') includes: regName) ifFalse: [
                        aStream nextPutAll: regName; nextPutAll: ': '.
                        regValue printOn: aStream base: 16 length: 8 padded: true.
                        aStream cr
        ]]!

----- Method: RemoteGDBSession>>qXfer (in category 'RSP Helpers') -----
qXfer
        qXfer isNil ifTrue: [ qXfer := RemoteGdbXFER gdb: self ].
        ^ qXfer!

----- Method: RemoteGDBSession>>runStepsWithMagickCallback: (in category 'magick') -----
runStepsWithMagickCallback: magicCallbackBlock
        [ true ] whileTrue: [ self stepUntilMagick. magicCallbackBlock value ] !

----- Method: RemoteGDBSession>>runUntil: (in category 'RSP commands') -----
runUntil: aBlock
        [ self c ] doWhileFalse: aBlock!

----- Method: RemoteGDBSession>>runUntilMagick (in category 'magick') -----
runUntilMagick
        self runUntil: [ self currentInstructionEncoding = (Integer readFrom: self exe objectMemory targetSetup magicInstruction radix: 2) ]!

----- Method: RemoteGDBSession>>runWithMagickCallback: (in category 'magick') -----
runWithMagickCallback: magicCallbackBlock
        [ true ] whileTrue: [ self runUntilMagick. magicCallbackBlock value ] !

----- Method: RemoteGDBSession>>setRegister:to: (in category 'accessing') -----
setRegister: r to: x
        | regs |
        regs := self getRegisters.
        regs at: r put: x.
        self setRegisters: regs!

----- Method: RemoteGDBSession>>stepUntil: (in category 'RSP commands') -----
stepUntil: aBlock
        [ self s.
        Transcript show: ((self getRegisters at: 'r19') printString); cr.
        ] doWhileFalse: aBlock!

----- Method: RemoteGDBSession>>stepUntilMagick (in category 'magick') -----
stepUntilMagick
        self stepUntil: [ self currentInstructionEncoding = self exe objectMemory targetSetup magicInstruction ]!

----- Method: RemoteGDBSession>>supportsFeatures (in category 'RSP commands') -----
supportsFeatures
        " Answer whether the stub supports target feature descriptors. "
        | features |
        features := supported detect: [ :s | s beginsWith: 'qXfer:features:' ] ifNone: [ ^false ].
        features = 'qXfer:features:read+' ifFalse: [ self error: 'Havent encountered such a CPU yet; investigate' ].
        "In reality the following line must be, ^true."
        ^false "disabled for now, before we have xi:include in the XML parser"
!

----- Method: RemoteGDBSession>>vFile (in category 'RSP Helpers') -----
vFile
        vFile isNil ifTrue: [ vFile := RemoteGdbVFILE gdb: self ].
        ^ vFile!

----- Method: RemoteGDBTransport class>>host: (in category 'as yet unclassified') -----
host: h
        ^self host: h port: self wellKnownPort !

----- Method: RemoteGDBTransport class>>host:port: (in category 'as yet unclassified') -----
host: h port: p
        | socket |
        socket := Socket newTCP
                connectTo: (NetNameResolver addressForName: h) port: p.
        ^self onSocket: socket!

----- Method: RemoteGDBTransport class>>onSocket: (in category 'as yet unclassified') -----
onSocket: aSocket
        ^self new socket: aSocket !

----- Method: RemoteGDBTransport class>>wellKnownPort (in category 'as yet unclassified') -----
wellKnownPort
        ^2159!

----- Method: RemoteGDBTransport>>assemblePacket: (in category 'private') -----
assemblePacket: packetDataString
        | s cksum |
        s := '$', (self escape: packetDataString), '#'.
        cksum := packetDataString  inject: 0 into: [ :soFar :c | soFar + c asciiValue \\ 256 ].
        ^s, (cksum printStringBase: 16 nDigits: 2) asLowercase
!

----- Method: RemoteGDBTransport>>disconnect (in category 'target connection') -----
disconnect
        self socket close!

----- Method: RemoteGDBTransport>>escape: (in category 'private') -----
escape: aString
        ^aString inject: '' into: [ :soFar :c | soFar, (self escapeChar: c) ].
        !

----- Method: RemoteGDBTransport>>escapeChar: (in category 'private') -----
escapeChar: c
        "Where the characters '#' or '$' appear in the packet data,
        they must be escaped.
        The escape character is ASCII 0x7d ('}'),
        and is followed by the original character XORed with 0x20.
        The character '}' itself must also be escaped."
       
        ((c == $# or: [c == $$]) or: [c == $}]) ifTrue: [
                ^String with: $} with: (Character value: (c asciiValue bitXor: 16r20))
        ] ifFalse: [ ^String with: c ]!

----- Method: RemoteGDBTransport>>readAndVerifyCksum: (in category 'private') -----
readAndVerifyCksum: anInteger
        "Read next two characters from the TCP stream and verify that they represent the same hext number as anInteger."
        | cksumFromServer |

        cksumFromServer := Integer
                readFrom: (String with: self receiveByte with: self receiveByte)
                radix: 16.
        "cksumFromServer = anInteger ifFalse: [ self error: 'Wrong checksum' ]"!

----- Method: RemoteGDBTransport>>receive (in category 'API') -----
receive
        | c stream cksum cc |
        "Receive and decode the server's response.
        It may come in chunks on the TCP stream; in that sense, the word Packet may be confusing."
       
        self receiveByte = $$ ifFalse: [ self error: 'Packet does not start with $' ].

        stream := WriteStream with: ''.
        cksum := 0.
        [ c := self receiveChar. c = $# ] whileFalse: [
                cksum := cksum + c asInteger \\ 256.
                c = $* ifTrue: [
                        | nChar |
                        nChar := self receiveChar asciiValue.
                        cksum := cksum + nChar \\ 256.
                        nChar - 29 timesRepeat: [ stream nextPut: cc.  ]
                "RLE"
                 ] ifFalse: [ stream nextPut: c. cc := c. ]].
"TODO: escaping"
        self readAndVerifyCksum: cksum.
        socket sendData: '+'.

        ^stream contents
!

----- Method: RemoteGDBTransport>>receiveByte (in category 'API') -----
receiveByte
        | buf1 |
        "Receive exactly one byte, waiting for it if neccesary.
        This is at a level lower than escaping; see #receiveChar for the escaped version."
        buf1 := ByteString new: 1.
        (socket receiveDataInto: buf1) == 1 ifFalse: [GdbChildExited new signal].
        ^buf1 first!

----- Method: RemoteGDBTransport>>receiveChar (in category 'API') -----
receiveChar
        "Receive the next char from the TCP stream."

        | byte |
        byte := self receiveByte.
        "Do NOT escape at this level; check for RLE, and then escaping is above."
        ^byte!

----- Method: RemoteGDBTransport>>send: (in category 'API') -----
send: aString
        | packet ack n |
        packet := self assemblePacket: aString.
        socket sendData: packet.
        ack := '*'.
        n := socket receiveDataInto: ack.
        ack = '+' ifFalse: [ self error: 'gdb server answered ', ack ]
!

----- Method: RemoteGDBTransport>>socket (in category 'accessing') -----
socket
        ^ socket!

----- Method: RemoteGDBTransport>>socket: (in category 'accessing') -----
socket: aSocket
        socket := aSocket!

Object subclass: #RemoteGdbAbstractHelper
        instanceVariableNames: 'gdb'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: RemoteGdbAbstractHelper class>>gdb: (in category 'instance creation') -----
gdb: aRemoteGDB
        ^self new
                gdb: aRemoteGDB ;
                yourself !

----- Method: RemoteGdbAbstractHelper>>gdb (in category 'accessing') -----
gdb
        ^ gdb!

----- Method: RemoteGdbAbstractHelper>>gdb: (in category 'accessing') -----
gdb: anObject
        gdb := anObject!

RemoteGdbAbstractHelper subclass: #RemoteGdbVFILE
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

RemoteGdbAbstractHelper subclass: #RemoteGdbXFER
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: RemoteGdbXFER>>features: (in category 'as yet unclassified') -----
features: filename
        | answer |
        answer := self readFeatureDocument: filename.
        answer isEmpty ifTrue: [ ^nil ]. " stub has indicated he does not understand this request "
        answer first == $l ifFalse: [ ^self error ].
        answer := answer allButFirst.
        ^self parseFeatures: answer!

----- Method: RemoteGdbXFER>>parseFeatures: (in category 'as yet unclassified') -----
parseFeatures: aStringOfXML
        self shouldBeImplemented
       
        "The below code used to work,
        back when we had PPXmlParser.
       
       
        | xml gdbXmlParser |
       
        gdbXmlParser := GdbXmlParser endian: gdb processorDescription endian.
        gdbXmlParser parseString: aStringOfXML.
        self halt.
        xml baseURI: (RemoteGdbFeatureURIProvider gdb: gdb).
        ^xml rootElement copy"!

----- Method: RemoteGdbXFER>>readFeatureDocument: (in category 'as yet unclassified') -----
readFeatureDocument: filename
        ^gdb q: 'qXfer:features:read:', filename, ':0,fff'!

Object subclass: #RemoteGdbFeatureURIProvider
        instanceVariableNames: 'gdb'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: RemoteGdbFeatureURIProvider class>>gdb: (in category 'as yet unclassified') -----
gdb: aGDB
        ^self new
                gdb: aGDB;
                yourself !

----- Method: RemoteGdbFeatureURIProvider>>gdb (in category 'accessing') -----
gdb
        ^ gdb!

----- Method: RemoteGdbFeatureURIProvider>>gdb: (in category 'accessing') -----
gdb: anObject
        gdb := anObject!

----- Method: RemoteGdbFeatureURIProvider>>get: (in category 'API') -----
get: filename
        ^gdb qXfer features: filename!

Object subclass: #ShmemUFFI
        instanceVariableNames: 'ptr'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

!ShmemUFFI commentStamp: 'BorisShingarov 5/23/2019 04:12' prior: 0!
FFI interface to Shared Memory.!

----- Method: ShmemUFFI class>>allocate: (in category 'NB interface to SHM') -----
allocate: nBytes
        | ptr |
        ptr := self shmaddr: nBytes.
        ^ShmemUFFI new
                ptr: ptr;
                yourself !

----- Method: ShmemUFFI class>>shmaddr: (in category 'NB interface to SHM') -----
shmaddr: size
"   ShmemUFFI shmaddr: 1024000   "
       
        ^ self
                ffiCall: #( void* shmaddr (int size) )
                module: self soName!

----- Method: ShmemUFFI class>>soName (in category 'NB interface to SHM') -----
soName
        ^'/home/boris/work/thinshell/HelloNB.so'!

----- Method: ShmemUFFI>>ptr (in category 'accessing') -----
ptr
        ^ ptr!

----- Method: ShmemUFFI>>ptr: (in category 'accessing') -----
ptr: anObject
        ptr := anObject!

Object subclass: #SimulationAddressSpace
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

SimulationAddressSpace subclass: #RemoteRAM
        instanceVariableNames: 'gdb'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

RemoteRAM subclass: #BufferingRemoteRAM
        instanceVariableNames: 'buffer minAddr leftFinger queuedBreakpoints'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: BufferingRemoteRAM>>buffer (in category 'accessing') -----
buffer
        buffer isNil ifTrue: [ buffer := ByteArray new: (4*1024*1024) + (1024*1024) + (80*1024*1024) ].
        ^buffer!

----- Method: BufferingRemoteRAM>>chunkSize (in category 'flushing') -----
chunkSize
        "In bytes"
        ^2048 "maybe? this was always 4096, I have no idea why this started breaking in Maribor"!

----- Method: BufferingRemoteRAM>>flushRAM (in category 'flushing') -----
flushRAM
        | firstUnallocatedAddress |
        firstUnallocatedAddress := self getVRegister: #HEAP.
        leftFinger := 1.
        'Injecting program'
                displayProgressFrom: minAddr to: firstUnallocatedAddress during:
                        [ :bar | self transmitBelow: firstUnallocatedAddress updating: bar ]
!

----- Method: BufferingRemoteRAM>>insertSWBreakpointAt: (in category 'API') -----
insertSWBreakpointAt: addr
        self queuedBreakpoints add: addr
 
 
!

----- Method: BufferingRemoteRAM>>minAddr (in category 'accessing') -----
minAddr
        minAddr isNil ifTrue: [ minAddr := self getVRegister: #NZone ].
        ^minAddr!

----- Method: BufferingRemoteRAM>>queuedBreakpoints (in category 'accessing') -----
queuedBreakpoints
        queuedBreakpoints isNil ifTrue: [ queuedBreakpoints := OrderedCollection new ].
        ^queuedBreakpoints!

----- Method: BufferingRemoteRAM>>read32At: (in category 'API') -----
read32At: addr
        leftFinger isNil ifTrue: [
                ^(((self buffer at: addr - self minAddr + 1) << 24
                bitOr: (self buffer at: addr - self minAddr + 2) << 16)
                bitOr: (self buffer at: addr - self minAddr + 3) << 8)
                bitOr: (self buffer at: addr - self minAddr + 4)
                 ].
        ^super read32At: addr!

----- Method: BufferingRemoteRAM>>transmitBelow:updating: (in category 'flushing') -----
transmitBelow: firstUnallocatedAddress updating: aProgressBar
| bytes thisChunk |
        bytes := firstUnallocatedAddress - self minAddr.
        bytes = 0 ifTrue: [ buffer := nil. ^self ].
        bytes > self chunkSize ifTrue: [ bytes := self chunkSize ].

thisChunk := buffer copyFrom: leftFinger to: leftFinger + bytes - 1.
aProgressBar value: minAddr.
self writeBytes: thisChunk toAddr: minAddr.
minAddr := minAddr + bytes.
leftFinger := leftFinger + bytes.
self transmitBelow: firstUnallocatedAddress updating: aProgressBar !

----- Method: BufferingRemoteRAM>>writeBytes:toAddr: (in category 'API') -----
writeBytes: aByteArray toAddr: addr
        | start stop |
        leftFinger isNil ifTrue: [
                start := addr - self minAddr + 1.
                stop := start + aByteArray size - 1.
                ^self buffer replaceFrom: start to: stop with: aByteArray startingAt: 1 ].
        ^super writeBytes: aByteArray toAddr: addr!

----- Method: BufferingRemoteRAM>>writeInt32:toAddr: (in category 'API') -----
writeInt32: int toAddr: addr
        leftFinger isNil ifTrue: [
                ^self buffer
                        at: addr - self minAddr + 1 put: ((int bitAnd: 16rFF000000) >> 24);
                        at: addr - self minAddr + 2 put: ((int bitAnd: 16r00FF0000) >> 16);
                        at: addr - self minAddr + 3 put: ((int bitAnd: 16r0000FF00) >> 8);
                        at: addr - self minAddr + 4 put: (int bitAnd: 16r000000FF) ].
        super writeInt32: int toAddr: addr
!

RemoteRAM subclass: #Gem5SharedRAM
        instanceVariableNames: 'tlb hostPtr shmemSize'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: Gem5SharedRAM class>>gem5: (in category 'FFI') -----
gem5: nBytes
        "Answer the void* pointer to the backing store of the gem5 guest memory."
        | fd addr |
        fd := self shmOpen: '/gem5'
                with: 64"O_CREAT" | 2"O_RDWR"
                with: 8r666. "mode"
        addr := self mmap: 0
                with: nBytes
                with: 1"PROT_READ" | 2"PROT_WRITE"
                with: 1 "MAP_SHARED"
                with: fd
                with: 0.
        ^addr

"
Gem5SharedRAM halt; gem5: 5000
"
!

----- Method: Gem5SharedRAM class>>mmap:with:with:with:with:with: (in category 'FFI') -----
mmap: addr with: length with: prot with: flags with: fd with: offset
        <cdecl: void* 'mmap' (longlong longlong long long long longlong) module: '/lib/x86_64-linux-gnu/libc.so.6'>
        ^self externalCallFailed
!

----- Method: Gem5SharedRAM class>>mmuPageSize (in category 'granularity') -----
mmuPageSize
        ^4096!

----- Method: Gem5SharedRAM class>>offsetMask (in category 'granularity') -----
offsetMask
        ^self mmuPageSize - 1!

----- Method: Gem5SharedRAM class>>pageMask (in category 'granularity') -----
pageMask
        ^16rFFFFFFFF bitXor: self offsetMask
!

----- Method: Gem5SharedRAM class>>shmOpen:with:with: (in category 'FFI') -----
shmOpen: name with: oflag with: mode
        <cdecl: ulong 'shm_open' (char* ulong ulong) module: '/lib/x86_64-linux-gnu/librt.so.1'>
        ^self externalCallFailed
!

----- Method: Gem5SharedRAM>>byteAtAddr:put: (in category 'writing') -----
byteAtAddr: byteAddress put: byte
        | ptr |
byteAddress = 16r109014 ifTrue: [self halt].
        ptr := self translate: byteAddress.
        ptr unsignedByteAt: 1 put: byte!

----- Method: Gem5SharedRAM>>fillFromStream:startingAt:count: (in category 'writing') -----
fillFromStream: aFileStream startingAt: startAddress count: count
        | contents |
        contents := aFileStream next: count.
        self writeBytes: contents toAddr: startAddress.
        ^contents size!

----- Method: Gem5SharedRAM>>forceRead32At: (in category 'address translation') -----
forceRead32At: addr
        | x |
        self halt. "I don't remember why this was needed."
        x := super read32At: addr.
        tlb := self getTLB.
        ^x
!

----- Method: Gem5SharedRAM>>forceReadAt:nBytes: (in category 'address translation') -----
forceReadAt: addr nBytes: n
        super readAt: addr nBytes: n.
        tlb := self getTLB!

----- Method: Gem5SharedRAM>>forceWriteBytes:toAddr: (in category 'address translation') -----
forceWriteBytes: aByteArray  toAddr: addr
        | x |
        x := super writeBytes: aByteArray  toAddr: addr.
        tlb := self getTLB.
        ^x
!

----- Method: Gem5SharedRAM>>forceWriteInt32:toAddr: (in category 'address translation') -----
forceWriteInt32: int toAddr: addr
        | x |
        x := super writeInt32: int toAddr: addr.
        tlb := self getTLB.
        ^x
!

----- Method: Gem5SharedRAM>>getTLB (in category 'RSP') -----
getTLB
        | answer |
        answer := self gdb q: '.'.
        answer isEmpty ifTrue: [ self error: 'GDB failed to return TLB' ].
        ^Dictionary newFromAssociations:
                (((answer findTokens: ';')
                collect: [ :s | s findTokens: ':' ])
                collect: [ :pair | (Integer readFrom: pair first base: 16) -> (Integer readFrom: pair last base: 16) ])!

----- Method: Gem5SharedRAM>>hostPtr (in category 'shmem') -----
hostPtr
        hostPtr isNil ifTrue: [ hostPtr := Gem5SharedRAM gem5: shmemSize ].
        ^hostPtr!

----- Method: Gem5SharedRAM>>longAtAddr:put:bigEndian: (in category 'writing') -----
longAtAddr: addr put: aValue bigEndian: bigEndian
        | ptr int |
        int := bigEndian
                ifTrue: [ aValue byteSwap32 ]
                ifFalse: [ aValue ].
        ptr := self translate: addr.
        ptr unsignedLongAt: 1 put: int
       
       
       
!

----- Method: Gem5SharedRAM>>read:bytesAtAddr: (in category 'reading') -----
read: n bytesAtAddr: addr
        | backingAddr |
        backingAddr := self translate: addr.
        ^((1 to: n) collect: [ :idx| backingAddr byteAt: idx ]) asByteArray
!

----- Method: Gem5SharedRAM>>shmemSize (in category 'shmem') -----
shmemSize
        ^shmemSize!

----- Method: Gem5SharedRAM>>shmemSize: (in category 'shmem') -----
shmemSize: howBig
        shmemSize := howBig!

----- Method: Gem5SharedRAM>>tlb (in category 'address translation') -----
tlb
        tlb isNil ifTrue: [ tlb := self getTLB ].
        ^tlb!

----- Method: Gem5SharedRAM>>translate: (in category 'address translation') -----
translate: addr
        | pageAddr |
        pageAddr := self virt2phys: addr.
        pageAddr isNil ifTrue: [ ^ self error forceRead32At: addr ].
        ^self hostPtr getHandle + pageAddr.
!

----- Method: Gem5SharedRAM>>unsignedLongAtAddr:bigEndian: (in category 'reading') -----
unsignedLongAtAddr: addr bigEndian: bigEndian
        | backingAddr int |
        backingAddr := self translate: addr.
        int := backingAddr unsignedLongAt: 1.
        bigEndian ifTrue: [ int := int byteSwap32].
        ^int!

----- Method: Gem5SharedRAM>>virt2phys: (in category 'address translation') -----
virt2phys: anAddress
        " Answer the physical address for the given virtual address,
         if it is mapped, nil otherwise. "
        | pageVirt pagePhys |
        pageVirt := anAddress bitAnd: self class pageMask.
        pagePhys := self tlb at: pageVirt ifAbsent: [ ^nil ].
        ^pagePhys bitOr: (anAddress bitAnd: self class offsetMask)!

----- Method: Gem5SharedRAM>>writeBytes:toAddr: (in category 'writing') -----
writeBytes: aByteArray toAddr: addr
        | ptr |
addr = 16r109014 ifTrue: [self halt].
        ptr := self translate: addr.
        aByteArray doWithIndex: [ :x :idx | ptr unsignedByteAt: idx put: x ] "is there a faster way?"
!

Gem5SharedRAM subclass: #Gem5SharedRAM8K
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-RSP'!

----- Method: Gem5SharedRAM8K class>>mmuPageSize (in category 'granularity') -----
mmuPageSize
        "GEM5 MIPS.  Sweetman claims this should not happen."
        ^8192!

----- Method: RemoteRAM class>>gdb: (in category 'instance creation') -----
gdb: aRemoteGDB
        ^self basicNew
                gdb: aRemoteGDB;
                yourself !

----- Method: RemoteRAM>>byteAt: (in category 'reading') -----
byteAt: index
        "Compatibe with the ByteArray.
        Index is measured in bytes, and is 1-based.
        The return value is always unsigned."
        ^self byteAtAddr: index - 1!

----- Method: RemoteRAM>>byteAt:put: (in category 'writing') -----
byteAt: index put: byte
        self byteAtAddr: index - 1 put: byte!

----- Method: RemoteRAM>>byteAtAddr: (in category 'reading') -----
byteAtAddr: addr
        ^self unsignedByteAtAddr: addr!

----- Method: RemoteRAM>>byteAtAddr:put: (in category 'writing') -----
byteAtAddr: byteAddress put: byte
        | textualAddr data |
        data := byte printStringBase: 16 length: 2 padded: true.
        textualAddr := byteAddress printStringBase: 16 length: 8 padded: true.
        ^ self writeBytesHex: data toAddrHex: textualAddr hexSize: '1'!

----- Method: RemoteRAM>>flush (in category 'target synchronization') -----
flush
        "Do nothing because I write directly to the target's memory"!

----- Method: RemoteRAM>>gdb (in category 'debugger access') -----
gdb
        ^ gdb!

----- Method: RemoteRAM>>gdb: (in category 'debugger access') -----
gdb: anObject
        gdb := anObject!

----- Method: RemoteRAM>>long64At:put: (in category 'reading') -----
long64At: byteIndex put: aValue
        | lowBits mask wordIndex |
        (lowBits := byteIndex - 1 \\ 4) = 0 ifTrue:
                [self "N.B. Do the access that can fail first, before altering the receiver"
                        longAt: byteIndex + 4 put: (aValue bitShift: -32);
                        unsignedLongAt: byteIndex put: (aValue bitAnd: 16rffffffff).
                ^aValue].
        "There will always be three accesses; two partial words and a full word in the middle"
        wordIndex := byteIndex - 1 // 4 + 1.
        aValue < 0
                ifTrue:
                        [(aValue bitShift: -32) < -2147483648 ifTrue:
                                [^self errorImproperStore]]
                ifFalse:
                        [16r7FFFFFFF < (aValue bitShift: -32) ifTrue:
                                [^self errorImproperStore]].
        mask := 16rFFFFFFFF bitShift: 4 - lowBits * -8.
        self at: wordIndex put: (((self at: wordIndex) bitAnd: mask) bitXor: ((aValue bitShift: lowBits * 8) bitAnd: mask bitInvert32)).
        self at: wordIndex + 1 put: ((aValue bitShift: 4 - lowBits * -8) bitAnd: 16rFFFFFFFF).
        self at: wordIndex + 2 put: (((self at: wordIndex + 2) bitAnd: mask bitInvert32) bitXor: ((aValue bitShift: 4 - lowBits + 4 * -8) bitAnd: mask)).
        ^aValue!

----- Method: RemoteRAM>>longAt:put: (in category 'writing') -----
longAt: byteIndex put: int
        ^self unsignedLongAt: byteIndex put: int
!

----- Method: RemoteRAM>>longAt:put:bigEndian: (in category 'writing') -----
longAt: byteIndex put: aValue bigEndian: bigEndian
        "Compatibility with the ByteArray method of the same name."
        self longAtAddr: byteIndex  - 1 put: aValue bigEndian: bigEndian!

----- Method: RemoteRAM>>longAtAddr:put:bigEndian: (in category 'writing') -----
longAtAddr: addr put: aValue bigEndian: bigEndian
        "Compatibility with the ByteArray method of the same name."
        | textualAddr data textualData |
        textualAddr := addr printStringBase: 16 length: 8 padded: true.
        data := bigEndian
                ifTrue: [ aValue ]
                ifFalse: [ aValue byteSwap32 ].
        textualData := data printStringBase: 16 length: 8 padded: true.
        self writeBytesHex: textualData
                toAddrHex: textualAddr
                hexSize: '4'!

----- Method: RemoteRAM>>read:bytesAsHexAt: (in category 'RSP protocol') -----
read: n bytesAsHexAt: addr
        "Answer the hex string the gdbserver will return to represent the n bytes read from address addr.
        All read operations are implemented on top of this primitive."
        ^self gdb q: 'm',
                addr printStringHex,
                ',',
                n printStringHex
!

----- Method: RemoteRAM>>read:bytesAt: (in category 'reading') -----
read: n bytesAt: index
        ^self read: n bytesAtAddr: index - 1!

----- Method: RemoteRAM>>read:bytesAtAddr: (in category 'reading') -----
read: n bytesAtAddr: addr
        | answer stream |
        answer := self read: n bytesAsHexAt: addr.
        stream := ReadStream on: answer
                from: 1
                to: answer size.
        answer := ByteArray new: n.
        1 to: n do: [ :idx |
                | b |
                b := stream next: 2.
                answer at: idx put: (Integer readFrom: b base: 16) ].
        ^answer!

----- Method: RemoteRAM>>readInt32fromAddr: (in category 'remote endian') -----
readInt32fromAddr: addr
        "Read, using the REMOTE TARGET endianness."
        ^self unsignedLongAtAddr: addr bigEndian: self isBigEndian!

----- Method: RemoteRAM>>signedLong64At: (in category 'reading') -----
signedLong64At: byteIndex
        ^(self unsignedLong64At: byteIndex) signedIntFromLong64
!

----- Method: RemoteRAM>>unsignedByteAt: (in category 'reading') -----
unsignedByteAt: index
        ^self unsignedByteAtAddr: index - 1!

----- Method: RemoteRAM>>unsignedByteAtAddr: (in category 'reading') -----
unsignedByteAtAddr: addr
        ^(self read: 1 bytesAtAddr: addr) first!

----- Method: RemoteRAM>>unsignedLong64At: (in category 'reading') -----
unsignedLong64At: byteIndex
        ^self unsignedLong64AtAddr: byteIndex - 1!

----- Method: RemoteRAM>>unsignedLong64AtAddr: (in category 'reading') -----
unsignedLong64AtAddr: addr
        | hiWord loWord |
        addr \\ 8 ~= 0 ifTrue: [self unalignedAccessError].
        loWord := self unsignedLongAtAddr: addr bigEndian: false.
        hiWord := self unsignedLongAtAddr: addr + 4 bigEndian: false.
        ^hiWord = 0
                ifTrue: [loWord]
                ifFalse: [(hiWord bitShift: 32) + loWord]!

----- Method: RemoteRAM>>unsignedLongAt:bigEndian: (in category 'reading') -----
unsignedLongAt: byteIndex bigEndian: bigEndian
        ^self unsignedLongAtAddr: byteIndex - 1 bigEndian: bigEndian!

----- Method: RemoteRAM>>unsignedLongAt:put: (in category 'writing') -----
unsignedLongAt: byteIndex put: int
        self longAtAddr: byteIndex - 1 put: int bigEndian: self isBigEndian!

----- Method: RemoteRAM>>unsignedLongAtAddr:bigEndian: (in category 'reading') -----
unsignedLongAtAddr: addr bigEndian: bigEndian
        | string int |
        string := self read: 4 bytesAsHexAt: addr.
        int := Integer readFrom: string radix: 16.
        bigEndian ifFalse: [ int := int byteSwap32 ].
        ^int!

----- Method: RemoteRAM>>unsignedShortAtAddr:bigEndian: (in category 'reading') -----
unsignedShortAtAddr: addr bigEndian: bigEndian
        | string int |
        string := self read: 2 bytesAsHexAt: addr.
        int := Integer readFrom: string radix: 16.
        bigEndian ifFalse: [ int := int byteSwap16 ].
        ^int!

----- Method: RemoteRAM>>writeBytes:toAddr: (in category 'writing') -----
writeBytes: aByteArray toAddr: addr
        | buffer textualAddr textualSize |
        buffer := WriteStream on: (String new: aByteArray size * 2).
        aByteArray do: [ :aByte |
                | data |
                data := aByte printStringBase: 16 length: 2 padded: true.
                buffer nextPutAll: data
        ].
        textualAddr := addr printStringBase: 16 length: 8 padded: true.
        textualSize := aByteArray size  printStringBase: 16.
        self writeBytesHex: buffer contents
                toAddrHex: textualAddr
                hexSize: textualSize!

----- Method: RemoteRAM>>writeBytesHex:toAddrHex:hexSize: (in category 'RSP protocol') -----
writeBytesHex: aString toAddrHex: addr hexSize: s
        | answer |
        answer := gdb
                q: 'M', addr,  ',', s, ':', aString.
        answer = 'OK' ifFalse: [ self error: 'RSP protocol failure' ].

!

----- Method: RemoteRAM>>writeInt32:toAddr: (in category 'writing') -----
writeInt32: int toAddr: addr
        "Use the REMOTE TARGET's endianness."
        self longAtAddr: addr put: int bigEndian: self isBigEndian!

----- Method: RemoteRAM>>writeInt32s:toAddr: (in category 'writing') -----
writeInt32s: arrayOfInt32s toAddr: addr
        "Using the remote endianness."
        self writeInt32s: arrayOfInt32s toAddr: addr bigEndian: self isBigEndian
!

----- Method: RemoteRAM>>writeInt32s:toAddr:bigEndian: (in category 'writing') -----
writeInt32s: arrayOfInt32s toAddr: addr bigEndian: bigEndian
        "Using the remote endianness."
        | buffer textualAddr textualSize |
        buffer := WriteStream on: ''.
        arrayOfInt32s do: [ :anInt32 |
                | data textualData |
                data := bigEndian
                        ifTrue: [ anInt32 ]
                        ifFalse: [ anInt32 byteSwap32 ].
                textualData := data printStringBase: 16 length: 8 padded: true.
                buffer nextPutAll: textualData
        ].
        textualAddr := addr printStringBase: 16 length: 8 padded: true.
        textualSize := arrayOfInt32s size * 4 printStringBase: 16.
        self writeBytesHex: buffer contents
                toAddrHex: textualAddr
                hexSize: textualSize!

----- Method: SimulationAddressSpace class>>bytesPerElement (in category 'as yet unclassified') -----
bytesPerElement
        ^1!

----- Method: SimulationAddressSpace class>>new: (in category 'as yet unclassified') -----
new: bytes
        "I really hate this design.
        The only reason #new: is here is because there is no concept of conneciton
        between the processor and memory."
        | instance |
        instance := self gdb: TargetAwareX86 current gdb.
        instance shmemSize: 120*1024*1024.
        ^instance!

----- Method: SimulationAddressSpace>>currentInstructionEncoding (in category 'as yet unclassified') -----
currentInstructionEncoding
        ^self readInt32fromAddr: self gdb pc!

----- Method: SimulationAddressSpace>>endianness (in category 'as yet unclassified') -----
endianness
        "Answer the endianness OF THE REMOTE TARGET."
        ^self gdb processorDescription endian!

----- Method: SimulationAddressSpace>>isBigEndian (in category 'as yet unclassified') -----
isBigEndian
        ^self endianness == #big!

Object subclass: #TAJTargetSetup
        instanceVariableNames: 'gdbClass host port architecture processor magicInstruction instructionStreamClass breakpointKind'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'GDB-TAJ'!

----- Method: TAJTargetSetup class>>current (in category 'settings') -----
current
        ^self gem5PPC   !

----- Method: TAJTargetSetup class>>gem5MIPS (in category 'settings') -----
gem5MIPS
        | arch |
        arch := self tajMIPSArchitecture.
        ^self new
                gdbClass: Gem5SharedRAM8K;
                host: '192.168.75.2';
                port: 7000;
                architecture: arch;
                instructionStreamClass: TargetAgnosticInstructionStream;
                breakpointKind: #hard;
                magicInstruction: (((arch isa instructionAt: #sll) bind: (Dictionary new
                        at: 'rs' put: 0;
                        at: 'rt' put: 0;
                        at: 'rd' put: 0;
                        at: 'shamt' put: 0;
                        yourself)) emit);
                yourself!

----- Method: TAJTargetSetup class>>gem5PPC (in category 'settings') -----
gem5PPC
        | arch |
        arch := self tajPOWERArchitecture.
        ^self new
                gdbClass: Gem5SharedRAM;
                host: '127.0.0.1';
                port: 7000;
                architecture: arch;
                instructionStreamClass: TargetAgnosticInstructionStream;
                breakpointKind: #hard;
                magicInstruction: (((arch isa instructionAt: #ore) bind: (Dictionary new
                        at: 'ra' put: 1;
                        at: 'rb' put: 1;
                        at: 'rs' put: 1;
                        at: 'rc' put: 0;
                        yourself)) emit);
                yourself!

----- Method: TAJTargetSetup class>>gem86 (in category 'settings') -----
gem86
        | arch |
        arch := self tajIA32Architecture.
        ^self new
                gdbClass: BufferingRemoteRAM;
                host: '192.168.75.2';
                port: 7000;
                architecture: arch;
                instructionStreamClass: TargetAgnosticInstructionStream;
               
                "bogus, I still don't what it should be on x86"
                magicInstruction: 16r0;
                breakpointKind: #trap;
                yourself!

----- Method: TAJTargetSetup class>>mpc5125 (in category 'settings') -----
mpc5125
        | arch |
        arch := self tajPOWERArchitecture.
        ^self new
                gdbClass: BufferingRemoteRAM;
                host: '192.168.75.39';
                port: 7000;
                architecture: arch;
                instructionStreamClass: TargetAgnosticInstructionStream;
               
                "twge r2,r2; see gdb/gdbserver/linux-ppc-low.c.
                ptrace will happily send SIGTRAP for any tw,
                but gdb's breakpoint_at() will be confused unless
                the memory contents are exactly what it thinks
                the SW break instruction is."
                magicInstruction: 16r7D821008;
                breakpointKind: #trap;
                yourself!

----- Method: TAJTargetSetup class>>p1025 (in category 'settings') -----
p1025
        "Freescale TWR-P1025 PowerPC e500v2"
        | arch |
        arch := self tajPOWERArchitecture.
        ^self new
                gdbClass: BufferingRemoteRAM;
                host: '192.168.75.199';
                port: 7000;
                architecture: arch;
                instructionStreamClass: TargetAgnosticInstructionStream;
               
                "twge r2,r2; see gdb/gdbserver/linux-ppc-low.c.
                ptrace will happily send SIGTRAP for any tw,
                but gdb's breakpoint_at() will be confused unless
                the memory contents are exactly what it thinks
                the SW break instruction is."
                magicInstruction: 16r7D821008;
                breakpointKind: #trap;
                yourself!

----- Method: TAJTargetSetup class>>tajIA32Architecture (in category 'TAJArchitectures') -----
tajIA32Architecture
        ^"TAJIA32Architecture"0 resetDefault!

----- Method: TAJTargetSetup class>>tajMIPSArchitecture (in category 'TAJArchitectures') -----
tajMIPSArchitecture
        ^"TAJMIPSArchitecture"0 resetDefault!

----- Method: TAJTargetSetup class>>tajPOWERArchitecture (in category 'TAJArchitectures') -----
tajPOWERArchitecture
        ^"TAJPowerArchitecture"0 resetDefault!

----- Method: TAJTargetSetup>>architecture (in category 'accessing') -----
architecture
        ^ architecture!

----- Method: TAJTargetSetup>>architecture: (in category 'accessing') -----
architecture: anObject
        architecture := anObject!

----- Method: TAJTargetSetup>>breakpointKind (in category 'accessing') -----
breakpointKind
        ^ breakpointKind!

----- Method: TAJTargetSetup>>breakpointKind: (in category 'accessing') -----
breakpointKind: anObject
        breakpointKind := anObject!

----- Method: TAJTargetSetup>>gdbClass (in category 'accessing') -----
gdbClass
        ^ gdbClass!

----- Method: TAJTargetSetup>>gdbClass: (in category 'accessing') -----
gdbClass: anObject
        gdbClass := anObject!

----- Method: TAJTargetSetup>>host (in category 'accessing') -----
host
        ^ host!

----- Method: TAJTargetSetup>>host: (in category 'accessing') -----
host: anObject
        host := anObject!

----- Method: TAJTargetSetup>>instructionStreamClass (in category 'accessing') -----
instructionStreamClass
        ^ instructionStreamClass!

----- Method: TAJTargetSetup>>instructionStreamClass: (in category 'accessing') -----
instructionStreamClass: anObject
        instructionStreamClass := anObject!

----- Method: TAJTargetSetup>>magicInstruction (in category 'accessing') -----
magicInstruction
        ^ magicInstruction!

----- Method: TAJTargetSetup>>magicInstruction: (in category 'accessing') -----
magicInstruction: anObject
        magicInstruction := anObject!

----- Method: TAJTargetSetup>>port (in category 'accessing') -----
port
        ^ port!

----- Method: TAJTargetSetup>>port: (in category 'accessing') -----
port: anObject
        port := anObject!

Object subclass: #TargetAwareX86
        instanceVariableNames: 'gdb'
        classVariableNames: 'Current ExtendedOpcodeExceptionMap OpcodeExceptionMap PostBuildStackDelta'
        poolDictionaries: ''
        category: 'GDB-Cog'!

----- Method: TargetAwareX86 class>>current (in category 'instance creation') -----
current
        ^Current!

----- Method: TargetAwareX86 class>>initialize (in category 'class initialization') -----
initialize
        "TargetAwareX86 initialize"
        | it |
        it := self basicNew.
        PostBuildStackDelta := 0.
        OpcodeExceptionMap := Array new: 256 withAll: #handleExecutionPrimitiveFailureAt:in:.
        OpcodeExceptionMap
                at: 1 + it callOpcode put: #handleCallFailureAt:in:;
                at: 1 + it jmpOpcode put: #handleJmpFailureAt:in:;
                at: 1 + it retOpcode put: #handleRetFailureAt:in:;
                at: 1 + it movALObOpcode put: #handleMovALObFailureAt:in:;
                at: 1 + it movAXOvOpcode put: #handleMovAXOvFailureAt:in:;
                at: 1 + it movObALOpcode put: #handleMovObALFailureAt:in:;
                at: 1 + it movOvAXOpcode put: #handleMovOvAXFailureAt:in:;
                at: 1 + it movGvEvOpcode put: #handleMovGvEvFailureAt:in:;
                at: 1 + it movEvGvOpcode put: #handleMovEvGvFailureAt:in:;
                at: 1 + it movGbEbOpcode put: #handleMovGbEbFailureAt:in:;
                at: 1 + it movEbGbOpcode put: #handleMovEbGbFailureAt:in:.
        ExtendedOpcodeExceptionMap := Array new: 256 withAll: #handleExecutionPrimitiveFailureAt:in:.
        ExtendedOpcodeExceptionMap
                at: 1 + it movGvEbOpcode put: #handleMovGvEbFailureAt:in:!

----- Method: TargetAwareX86 class>>new (in category 'instance creation') -----
new
        "
        TargetAwareX86 new
        "
        Current := super new connectGdb.
        ^Current!

----- Method: TargetAwareX86>>cResultRegister (in category 'accessing-abstract') -----
cResultRegister
        ^self eax!

----- Method: TargetAwareX86>>callOpcode (in category 'opcodes') -----
callOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2, pA8"
        ^16rE8!

----- Method: TargetAwareX86>>connectGdb (in category 'target connection') -----
connectGdb
        gdb := self debuggerClass
                host: self hostIP
                port: self tcpPort
                processorDescription: self pdl.
        ^self "not gdb; #new needs the instance"!

----- Method: TargetAwareX86>>debuggerClass (in category 'target connection') -----
debuggerClass
        ^RemoteGDBSession!

----- Method: TargetAwareX86>>eax (in category 'intel registers') -----
eax
        ^gdb getRegister: 'eax'!

----- Method: TargetAwareX86>>eax: (in category 'intel registers') -----
eax: anUnsignedInteger
        gdb setRegister: 'eax' to: anUnsignedInteger.
        ^anUnsignedInteger!

----- Method: TargetAwareX86>>ebp (in category 'intel registers') -----
ebp
        ^gdb getRegister: 'ebp'!

----- Method: TargetAwareX86>>ebp: (in category 'intel registers') -----
ebp: anUnsignedInteger
        gdb setRegister: 'ebp' to: anUnsignedInteger.
        ^anUnsignedInteger!

----- Method: TargetAwareX86>>ebx (in category 'intel registers') -----
ebx
        ^gdb getRegister: 'ebx'!

----- Method: TargetAwareX86>>ebx: (in category 'intel registers') -----
ebx: anUnsignedInteger
        gdb setRegister: 'ebx' to: anUnsignedInteger.
        ^anUnsignedInteger!

----- Method: TargetAwareX86>>ecx (in category 'intel registers') -----
ecx
        ^gdb getRegister: 'ecx'!

----- Method: TargetAwareX86>>ecx: (in category 'intel registers') -----
ecx: anUnsignedInteger
        gdb setRegister: 'ecx' to: anUnsignedInteger.
        ^anUnsignedInteger!

----- Method: TargetAwareX86>>edi (in category 'intel registers') -----
edi
        ^gdb getRegister: 'edi'!

----- Method: TargetAwareX86>>edi: (in category 'intel registers') -----
edi: anUnsignedInteger
        gdb setRegister: 'edi' to: anUnsignedInteger.
        ^anUnsignedInteger!

----- Method: TargetAwareX86>>edx (in category 'intel registers') -----
edx
        ^gdb getRegister: 'edx'!

----- Method: TargetAwareX86>>edx: (in category 'intel registers') -----
edx: anUnsignedInteger
        gdb setRegister: 'edx' to: anUnsignedInteger.
        ^anUnsignedInteger!

----- Method: TargetAwareX86>>eip (in category 'intel registers') -----
eip
        ^gdb getRegister: 'eip'!

----- Method: TargetAwareX86>>eip: (in category 'intel registers') -----
eip: anUnsignedInteger
        gdb setRegister: 'eip' to: anUnsignedInteger.
        ^anUnsignedInteger!

----- Method: TargetAwareX86>>esi (in category 'intel registers') -----
esi
        ^gdb getRegister: 'esi'!

----- Method: TargetAwareX86>>esi: (in category 'intel registers') -----
esi: anUnsignedInteger
        gdb setRegister: 'esi' to: anUnsignedInteger.
        ^anUnsignedInteger!

----- Method: TargetAwareX86>>esp (in category 'intel registers') -----
esp
        ^gdb getRegister: 'esp'!

----- Method: TargetAwareX86>>esp: (in category 'intel registers') -----
esp: anUnsignedInteger
        gdb setRegister: 'esp' to: anUnsignedInteger.
        ^anUnsignedInteger!

----- Method: TargetAwareX86>>fp (in category 'accessing-abstract') -----
fp
        ^self ebp!

----- Method: TargetAwareX86>>gdb (in category 'target connection') -----
gdb
        ^gdb!

----- Method: TargetAwareX86>>handleCallFailureAt:in: (in category 'error handling') -----
handleCallFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a call into a ProcessorSimulationTrap signal."
        |  relativeJump |
        relativeJump := memoryArray longAt: pc + 2 bigEndian: false.
        "NB: CRAP!! CRAP!! CRAP!!  The real CPU already pushed the return address!!"
        self esp: self esp + 4.
       
        ^(ProcessorSimulationTrap
                        pc: pc
                        nextpc: pc + 5
                        address: (pc + 5 + relativeJump) signedIntToLong
                        type: #call)
                signal!

----- Method: TargetAwareX86>>handleExecutionPrimitiveFailureAt:in: (in category 'error handling') -----
handleExecutionPrimitiveFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Handle an execution primitive failure for an unhandled opcode."
        ^self reportPrimitiveFailure!

----- Method: TargetAwareX86>>handleExecutionPrimitiveFailureIn:minimumAddress: (in category 'execution') -----
handleExecutionPrimitiveFailureIn: memoryArray minimumAddress: minimumAddress
"NB: THIS SHOULD GO INTO A COMMON SemihostABI CLASS -- bgs"
        "Handle an execution primitive failure.  Convert out-of-range call and absolute
         memory read into register instructions into ProcessorSimulationTrap signals."
        "self printIntegerRegistersOn: Transcript"
        "self printRegistersOn: Transcript"
        | pc opcode |
        pc := self eip.
        " (() between: minimumAddress and: memoryArray byteSize - 1) ifTrue: self  reportPrimitiveFailure -- TODO"
        opcode := memoryArray byteAt: pc + 1.
        opcode ~= 16r0f ifTrue:
                        [^self
                                perform: (OpcodeExceptionMap at: opcode + 1)
                                with: pc
                                with: memoryArray].
        opcode := memoryArray byteAt: pc + 2.
        ^self
                                perform: (ExtendedOpcodeExceptionMap at: opcode + 1)
                                with: pc
                                with: memoryArray!

----- Method: TargetAwareX86>>handleJmpFailureAt:in: (in category 'error handling') -----
handleJmpFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a jmp into a ProcessorSimulationTrap signal."
        |  relativeJump |
        relativeJump := memoryArray longAt: pc + 2 bigEndian: false.
        ^(ProcessorSimulationTrap
                        pc: pc
                        nextpc: pc + 5
                        address: (pc + 5 + relativeJump) signedIntToLong
                        type: #jump)
                signal!

----- Method: TargetAwareX86>>handleMovALObFailureAt:in: (in category 'error handling') -----
handleMovALObFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a read into al into a ProcessorSimulationTrap signal."
        ^(ProcessorSimulationTrap
                        pc: pc
                        nextpc: pc + 5
                        address: (memoryArray unsignedLongAt: pc + 2 bigEndian: false)
                        type: #read
                        accessor: #al:)
                signal!

----- Method: TargetAwareX86>>handleMovAXOvFailureAt:in: (in category 'error handling') -----
handleMovAXOvFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a read into eax into a ProcessorSimulationTrap signal."
        ^(ProcessorSimulationTrap
                        pc: pc
                        nextpc: pc + 5
                        address: (memoryArray unsignedLongAt: pc + 2 bigEndian: false)
                        type: #read
                        accessor: #eax:)
                signal!

----- Method: TargetAwareX86>>handleMovEbGbFailureAt:in: (in category 'error handling') -----
handleMovEbGbFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a byte register write into a ProcessorSimulationTrap signal."
        | modrmByte address |
        modrmByte := memoryArray byteAt: pc + 2.
        (modrmByte bitAnd: 7) ~= 4 ifTrue: "MoveRMbr with r = ESP requires an SIB byte"
                [address := (modrmByte bitAnd: 16rC0)
                                        caseOf: {
                                                [0 "ModRegInd"]
                                                -> [memoryArray unsignedLongAt: pc + 3 bigEndian: false].
                                                [16r80 "ModRegRegDisp32"]
                                                -> [(self perform: (#(eax ecx edx ebx esp ebp esi edi) at: (modrmByte bitAnd: 7) + 1))
                                                                + (memoryArray unsignedLongAt: pc + 3 bigEndian: false)
                                                                bitAnd: 16rFFFFFFFF] }
                                        otherwise: [^self reportPrimitiveFailure].
                ^(ProcessorSimulationTrap
                                pc: pc
                                nextpc: pc + 6
                                address: address
                                type: #write
                                accessor: (#(al cl dl bl ah ch dh bh) at: ((modrmByte >> 3 bitAnd: 7) + 1)))
                        signal].
        ^self reportPrimitiveFailure!

----- Method: TargetAwareX86>>handleMovEvGvFailureAt:in: (in category 'error handling') -----
handleMovEvGvFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a register write into a ProcessorSimulationTrap signal."
        | modrmByte |
        ^((modrmByte := memoryArray byteAt: pc + 2) bitAnd: 16rC7) = 16r5 "ModRegInd & disp32"
                ifTrue:
                        [(ProcessorSimulationTrap
                                        pc: pc
                                        nextpc: pc + 6
                                        address: (memoryArray unsignedLongAt: pc + 3 bigEndian: false)
                                        type: #write
                                        accessor: (#(eax ecx edx ebx esp ebp esi edi) at: ((modrmByte >> 3 bitAnd: 7) + 1)))
                                signal]
                ifFalse:
                        [self reportPrimitiveFailure]!

----- Method: TargetAwareX86>>handleMovGbEbFailureAt:in: (in category 'error handling') -----
handleMovGbEbFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a byte register load into a ProcessorSimulationTrap signal."
        | modrmByte address |
        modrmByte := memoryArray byteAt: pc + 2.
        address := (modrmByte bitAnd: 16rC0)
                                        caseOf: {
                                                [0 "ModRegInd"]
                                                -> [memoryArray unsignedLongAt: pc + 3 bigEndian: false].
                                                [16r80 "ModRegRegDisp32"]
                                                -> [(self perform: (#(eax ecx edx ebx esp ebp esi edi) at: (modrmByte bitAnd: 7) + 1))
                                                                + (memoryArray unsignedLongAt: pc + 3 bigEndian: false)
                                                                bitAnd: 16rFFFFFFFF] }
                                        otherwise: [^self reportPrimitiveFailure].
        ^(ProcessorSimulationTrap
                        pc: pc
                        nextpc: pc + 6
                        address: address
                        type: #read
                        accessor: (#(al: cl: dl: bl: ah: ch: dh: bh:) at: ((modrmByte >> 3 bitAnd: 7) + 1)))
                signal!

----- Method: TargetAwareX86>>handleMovGvEbFailureAt:in: (in category 'error handling') -----
handleMovGvEbFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a register load into a ProcessorSimulationTrap signal."
        | modrmByte mode srcIsSP srcVal dst offset |
        modrmByte := memoryArray byteAt: pc + 3.
        mode := modrmByte >> 6 bitAnd: 3.
        dst := #(eax: ecx: edx: ebx: esp: ebp: esi: edi:) at: ((modrmByte >> 3 bitAnd: 7) + 1).
        mode = 0 ifTrue: "ModRegInd"
                [offset := memoryArray unsignedLongAt: pc + 4. "1-relative"
                 ^(ProcessorSimulationTrap
                                        pc: pc
                                        nextpc: pc + 7
                                        address: offset
                                        type: #read
                                        accessor: dst)
                                signal].
        srcIsSP := (modrmByte bitAnd: 7) = 4.
        srcVal := self perform: (#(eax ecx edx ebx esp ebp esi edi) at: (modrmByte bitAnd: 7) + 1).
        mode = 1 ifTrue: "ModRegRegDisp8"
                [offset := memoryArray byteAt: pc + (srcIsSP ifTrue: [5] ifFalse: [4]). "1-relative"
                 offset > 127 ifTrue: [offset := offset - 256].
                 ^(ProcessorSimulationTrap
                                        pc: pc
                                        nextpc: pc + (srcIsSP ifTrue: [5] ifFalse: [4])
                                        address: (srcVal + offset bitAnd: 16rFFFFFFFF)
                                        type: #read
                                        accessor: dst)
                                signal].
        mode = 2 ifTrue: "ModRegRegDisp32"
                [offset := memoryArray unsignedLongAt: pc + (srcIsSP ifTrue: [5] ifFalse: [4]). "1-relative"
                 ^(ProcessorSimulationTrap
                                        pc: pc
                                        nextpc: pc + (srcIsSP ifTrue: [8] ifFalse: [7])
                                        address: (srcVal + offset bitAnd: 16rFFFFFFFF)
                                        type: #read
                                        accessor: dst)
                                signal].
        ^self reportPrimitiveFailure!

----- Method: TargetAwareX86>>handleMovGvEvFailureAt:in: (in category 'error handling') -----
handleMovGvEvFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a register load into a ProcessorSimulationTrap signal."
        | modrmByte |
        ^(((modrmByte := memoryArray byteAt: pc + 2) bitAnd: 16rC7) = 16r5) "ModRegInd & disp32"
                ifTrue:
                        [(ProcessorSimulationTrap
                                        pc: pc
                                        nextpc: pc + 6
                                        address: (memoryArray unsignedLongAt: pc + 3 bigEndian: false)
                                        type: #read
                                        accessor: (#(eax: ecx: edx: ebx: esp: ebp: esi: edi:) at: ((modrmByte >> 3 bitAnd: 7) + 1)))
                                signal]
                ifFalse:
                        [self reportPrimitiveFailure]!

----- Method: TargetAwareX86>>handleMovObALFailureAt:in: (in category 'error handling') -----
handleMovObALFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a byte write of al into a ProcessorSimulationTrap signal."
        ^(ProcessorSimulationTrap
                        pc: pc
                        nextpc: pc + 5
                        address: (memoryArray unsignedLongAt: pc + 2 bigEndian: false)
                        type: #write
                        accessor: #al)
                signal!

----- Method: TargetAwareX86>>handleMovOvAXFailureAt:in: (in category 'error handling') -----
handleMovOvAXFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a write of eax into a ProcessorSimulationTrap signal."
        ^(ProcessorSimulationTrap
                        pc: pc
                        nextpc: pc + 5
                        address: (memoryArray unsignedLongAt: pc + 2 bigEndian: false)
                        type: #write
                        accessor: #eax)
                signal!

----- Method: TargetAwareX86>>handleRetFailureAt:in: (in category 'error handling') -----
handleRetFailureAt: pc "<Integer>" in: memoryArray "<Bitmap|ByteArray>"
        "Convert an execution primitive failure for a ret into a ProcessorSimulationTrap signal."
        ^(ProcessorSimulationTrap
                        pc: pc
                        nextpc: pc + 1
                        address: (memoryArray unsignedLongAt: self esp + 1)
                        type: #return
                        accessor: #eip:)
                signal!

----- Method: TargetAwareX86>>hostIP (in category 'target connection') -----
hostIP
        ^'192.168.75.2'!

----- Method: TargetAwareX86>>integerRegisterState (in category 'accessing-abstract') -----
integerRegisterState
        | registerState |
        registerState := gdb getRegisters.
        ^{ 'eax'.  'ebx'.  'ecx'.  'edx'.  'esp'.  'ebp'.  'esi'.  'edi'. 'eip'.  'eflags'} collect: [ :aRegName |
                registerState at: aRegName ]
!

----- Method: TargetAwareX86>>jmpOpcode (in category 'opcodes') -----
jmpOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2, pA8"
        ^16rE9!

----- Method: TargetAwareX86>>lockPrefix (in category 'opcodes') -----
lockPrefix
        ^16rF0!

----- Method: TargetAwareX86>>movALObOpcode (in category 'opcodes') -----
movALObOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2, pA7"
        ^16rA0!

----- Method: TargetAwareX86>>movAXOvOpcode (in category 'opcodes') -----
movAXOvOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2, pA7"
        ^16rA1!

----- Method: TargetAwareX86>>movEbGbOpcode (in category 'opcodes') -----
movEbGbOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2"
        ^16r88!

----- Method: TargetAwareX86>>movEvGvOpcode (in category 'opcodes') -----
movEvGvOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2, pA8"
        ^16r89!

----- Method: TargetAwareX86>>movGbEbOpcode (in category 'opcodes') -----
movGbEbOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2"
        ^16r8A!

----- Method: TargetAwareX86>>movGvEbOpcode (in category 'opcodes') -----
movGvEbOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A3, pA14"
        ^16rB6!

----- Method: TargetAwareX86>>movGvEvOpcode (in category 'opcodes') -----
movGvEvOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2, pA8"
        ^16r8B!

----- Method: TargetAwareX86>>movObALOpcode (in category 'opcodes') -----
movObALOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2, pA7"
        ^16rA2!

----- Method: TargetAwareX86>>movOvAXOpcode (in category 'opcodes') -----
movOvAXOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2, pA7"
        ^16rA3!

----- Method: TargetAwareX86>>nopOpcode (in category 'opcodes') -----
nopOpcode
        ^16r90!

----- Method: TargetAwareX86>>pc (in category 'accessing-abstract') -----
pc
        ^self eip!

----- Method: TargetAwareX86>>pc: (in category 'accessing-abstract') -----
pc: newPC
        ^self eip: newPC!

----- Method: TargetAwareX86>>pdl (in category 'target connection') -----
pdl
        ^FakeProcessorDescriptionX86 new!

----- Method: TargetAwareX86>>printOn: (in category 'printing') -----
printOn: aStream
        self gdb printRegistersOn: aStream
!

----- Method: TargetAwareX86>>pushWord:in: (in category 'cog') -----
pushWord: aValue in: aMemory
        | sp |
        sp := (self esp: self esp - 4).
        aMemory longAt: sp + 1 put: aValue bigEndian: false!

----- Method: TargetAwareX86>>remoteMemoryClass (in category 'target connection') -----
remoteMemoryClass
        ^Gem5SharedRAM!

----- Method: TargetAwareX86>>retOpcode (in category 'opcodes') -----
retOpcode
        "[1] IA-32 Intel® Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z.
                table A2, pA7"
        ^16rC3!

----- Method: TargetAwareX86>>runInMemory:minimumAddress:readOnlyBelow: (in category 'execution') -----
runInMemory: aMemory minimumAddress: minimumAddress readOnlyBelow: minimumWritableAddress
        | stopReason |
        stopReason := gdb c.
        stopReason signal = #SIGSEGV ifFalse: [ self shouldBeImplemented ].
        ^self
                handleExecutionPrimitiveFailureIn: aMemory
                minimumAddress: minimumAddress!

----- Method: TargetAwareX86>>setFramePointer:stackPointer: (in category 'accessing-abstract') -----
setFramePointer: framePointer stackPointer: stackPointer
        "Initialize the processor's frame and stack pointers"
        self ebp: framePointer.
        self esp: stackPointer!

----- Method: TargetAwareX86>>simulateLeafCallOf:nextpc:memory: (in category 'cog') -----
simulateLeafCallOf: address nextpc: nextpc memory: aMemory
"this should go back to the alien"
        self pushWord: nextpc in: aMemory.
        self eip: address!

----- Method: TargetAwareX86>>singleStepIn:minimumAddress:readOnlyBelow: (in category 'execution') -----
singleStepIn: aMemory minimumAddress: minimumAddress readOnlyBelow: minimumWritableAddress
        | stopReason |
        stopReason := gdb s.
        stopReason signal = #SIGTRAP ifTrue: [ ^self "no fault" ].
        ^self
                handleExecutionPrimitiveFailureIn: aMemory
                minimumAddress: minimumAddress!

----- Method: TargetAwareX86>>smashRegisterAccessors (in category 'accessing-abstract') -----
smashRegisterAccessors
        ^#(eax: ebx: ecx: edx: esi: edi:)!

----- Method: TargetAwareX86>>smashRegistersWithValuesFrom:by: (in category 'accessing-abstract') -----
smashRegistersWithValuesFrom: base by: step
        self smashRegisterAccessors
           withIndexDo:
                [:accessor :index|
                self perform: accessor with: index - 1 * step + base]!

----- Method: TargetAwareX86>>sp (in category 'accessing-abstract') -----
sp
        ^self esp!

----- Method: TargetAwareX86>>sp: (in category 'accessing-abstract') -----
sp: anAddress
        "Set whatever the processor considers its stack pointer to anAddress."
        self esp: anAddress!

----- Method: TargetAwareX86>>tcpPort (in category 'target connection') -----
tcpPort
        ^7000!

----- Method: TargetAwareX86>>topOfStackIn: (in category 'printing') -----
topOfStackIn: aMemory
        "The 32-bit word at the stack top"
        ^aMemory unsignedLongAtAddr: self esp bigEndian: false!