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! |
Free forum by Nabble | Edit this page |