Eliot Miranda uploaded a new version of Cog to project VM Maker: http://source.squeak.org/VMMaker/Cog-lw.48.mcz
==================== Summary ====================
Name: Cog-lw.48 Author: lw Time: 11 July 2012, 9:13:45.865 pm UUID: 5ae3e465-4b2c-2349-9b88-77b8f53d5acd Ancestors: Cog-eem.47
Added the GdbARMAlien, together with its tests and the plugin. Additionally, introduced CogProcessorAlien as a common superclass for BochsIA32Alien and GdbARMAlien to increase code reusage.
The same might be possible for the Plugins (BochsIA32/GdbARM), because they are also identical.
=============== Diff against Cog-eem.47 ===============
Item was changed: + CogProcessorAlien variableByteSubclass: #BochsIA32Alien - Alien variableByteSubclass: #BochsIA32Alien instanceVariableNames: '' classVariableNames: 'OpcodeExceptionMap PostBuildStackDelta' poolDictionaries: '' category: 'Cog-Processors'!
!BochsIA32Alien commentStamp: '<historical>' prior: 0! I am a wrapper around the Bochs C++ IA32 CPU emulator. Note that currently I provide no access to the x87/mmx FPU state, only providing access to the SSE/xmm registers.
Here is the configure script for the configuration this code assumes. Offsets of fields will change with different configurations so they must agree.
----8<---- conf.COG ----8<---- #!!/bin/sh
# this sets up the compile for Cog. Disable as much inessential stuff # as possible leaving only the cpu/fpu & memory interface
set echo # CFLAGS="-pipe -O3 -fomit-frame-pointer -finline-functions -falign-loops=16 -falign-jumps=16 -falign-functions=16 -falign-labels=16 -falign-loops-max-skip=15 -falign-jumps-max-skip=15 -fprefetch-loop-arrays $CFLAGS" CFLAGS="-m32 $CFLAGS" CFLAGS="-Dlongjmp=_longjmp -Dsetjmp=_setjmp $CFLAGS" CFLAGS="-pipe -O3 -fomit-frame-pointer -finline-functions $CFLAGS" CFLAGS="-g $CFLAGS" CPATH="/sw/include" CPPFLAGS="" CXXFLAGS="$CFLAGS" LDFLAGS="-L/sw/lib"
export CFLAGS export CPATH export CPPFLAGS export CXXFLAGS export LDFLAGS
./configure --enable-Cog \ --enable-cpu-level=6 \ --enable-sse=2 \ --enable-assert-checks \ --with-nogui \ --disable-x86-64 \ --disable-pae \ --disable-large-pages \ --disable-global-pages \ --disable-mtrr \ --disable-sb16 \ --disable-ne2000 \ --disable-pci \ --disable-acpi \ --disable-apic \ --disable-clgd54xx \ --disable-usb \ --disable-plugins \ ${CONFIGURE_ARGS}
# apic == Advanced programmable Interrupt Controller # acpi == Advanced Configuration and Power Interface # pci == Peripheral Component Interconnect local bus # clgd54xx == Cirrus Logic GD54xx video card ----8<---- conf.COG ----8<----!
Item was removed: - ----- Method: BochsIA32Alien>>disassembleFrom:to:in:on: (in category 'disassembly') ----- - disassembleFrom: startAddress to: endAddress in: memory on: aStream - | address | - address := startAddress. - [address < endAddress] whileTrue: - [[:size :string| - aStream nextPutAll: string; cr; flush. - address := address + size] - valueWithArguments: (self - primitiveDisassembleAt: address - inMemory: memory)]!
Item was removed: - ----- Method: BochsIA32Alien>>disassembleInstructionAt:In: (in category 'disassembly') ----- - disassembleInstructionAt: pc In: memory - ^(self primitiveDisassembleAt: pc inMemory: memory) last!
Item was removed: - ----- Method: BochsIA32Alien>>disassembleInstructionAt:In:into: (in category 'disassembly') ----- - disassembleInstructionAt: ip In: memory into: aBlock - | lenAndDi | - lenAndDi := self primitiveDisassembleAt: ip inMemory: memory. - ^aBlock value: lenAndDi last value: lenAndDi first!
Item was removed: - ----- Method: BochsIA32Alien>>disassembleNextInstructionIn: (in category 'disassembly') ----- - disassembleNextInstructionIn: memory - ^(self primitiveDisassembleAt: self eip inMemory: memory) last!
Item was removed: - ----- Method: BochsIA32Alien>>runInMemory: (in category 'execution') ----- - runInMemory: aMemory - | result | - result := self primitiveRunInMemory: aMemory minimumAddress: 0 readOnlyBelow: 0. - result ~~ self ifTrue: - [self error: 'eek!!']!
Item was removed: - ----- Method: BochsIA32Alien>>runInMemory:minimumAddress:readOnlyBelow: (in category 'execution') ----- - runInMemory: aMemory minimumAddress: minimumAddress readOnlyBelow: minimumWritableAddress - | result | - result := self primitiveRunInMemory: aMemory - minimumAddress: minimumAddress - readOnlyBelow: minimumWritableAddress. - result ~~ self ifTrue: - [self error: 'eek!!']!
Item was removed: - ----- Method: BochsIA32Alien>>runInMemory:readExecuteOnlyBelow: (in category 'execution') ----- - runInMemory: aMemory readExecuteOnlyBelow: minWriteMaxExecAddr - | result | - result := self primitiveRunInMemory: aMemory minimumAddress: 0 readOnlyBelow: minWriteMaxExecAddr. - result ~~ self ifTrue: - [self error: 'eek!!']!
Item was removed: - ----- Method: BochsIA32Alien>>singleStepIn: (in category 'execution') ----- - singleStepIn: aMemory - | result | - result := self primitiveSingleStepInMemory: aMemory minimumAddress: 0 readOnlyBelow: aMemory size. - result ~~ self ifTrue: - [self error: 'eek!!']!
Item was removed: - ----- Method: BochsIA32Alien>>singleStepIn:minimumAddress:readOnlyBelow: (in category 'execution') ----- - singleStepIn: aMemory minimumAddress: minimumAddress readOnlyBelow: minimumWritableAddress - | result | - result := self primitiveSingleStepInMemory: aMemory - minimumAddress: minimumAddress - readOnlyBelow: minimumWritableAddress. - result ~~ self ifTrue: - [self error: 'eek!!']!
Item was removed: - ----- Method: BochsIA32Alien>>singleStepIn:readExecuteOnlyBelow: (in category 'execution') ----- - singleStepIn: aMemory readExecuteOnlyBelow: minWriteMaxExecAddr - | result | - result := self primitiveSingleStepInMemory: aMemory minimumAddress: 0 readOnlyBelow: minWriteMaxExecAddr. - result ~~ self ifTrue: - [self error: 'eek!!']!
Item was added: + Alien variableByteSubclass: #CogProcessorAlien + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Cog-Processors'!
Item was added: + ----- Method: CogProcessorAlien>>abstractInstructionCompilerClass (in category 'Cog API') ----- + abstractInstructionCompilerClass + self subclassResponsibility!
Item was added: + ----- Method: CogProcessorAlien>>callOpcode (in category 'opcodes') ----- + callOpcode + self subclassResponsibility.!
Item was added: + ----- Method: CogProcessorAlien>>disassembleFrom:to:in:on: (in category 'disassembly') ----- + disassembleFrom: startAddress to: endAddress in: memory on: aStream + | address | + address := startAddress. + [address < endAddress] whileTrue: + [[:size :string| + aStream nextPutAll: string; cr; flush. + address := address + size] + valueWithArguments: (self + primitiveDisassembleAt: address + inMemory: memory)]!
Item was added: + ----- Method: CogProcessorAlien>>disassembleInstructionAt:In: (in category 'disassembly') ----- + disassembleInstructionAt: pc In: memory + ^(self primitiveDisassembleAt: pc inMemory: memory) last!
Item was added: + ----- Method: CogProcessorAlien>>disassembleInstructionAt:In:into: (in category 'disassembly') ----- + disassembleInstructionAt: ip In: memory into: aBlock + | lenAndDi | + lenAndDi := self primitiveDisassembleAt: ip inMemory: memory. + ^aBlock value: lenAndDi last value: lenAndDi first!
Item was added: + ----- Method: CogProcessorAlien>>disassembleNextInstructionIn: (in category 'disassembly') ----- + disassembleNextInstructionIn: memory + ^(self primitiveDisassembleAt: self pc inMemory: memory) last!
Item was added: + ----- Method: CogProcessorAlien>>nopOpcode (in category 'opcodes') ----- + nopOpcode + self subclassResponsibility.!
Item was added: + ----- Method: CogProcessorAlien>>printRegisterState:on: (in category 'printing') ----- + printRegisterState: registerStateVector on: aStream + + self subclassResponsibility.!
Item was added: + ----- Method: CogProcessorAlien>>printRegistersOn: (in category 'printing') ----- + printRegistersOn: aStream + self printRegisterState: self registerState on: aStream. + aStream flush!
Item was added: + ----- Method: CogProcessorAlien>>reportPrimitiveFailure (in category 'error handling') ----- + reportPrimitiveFailure + | errorAndLog | + errorAndLog := self primitiveErrorAndLog. + self error: 'Error ', errorAndLog first printString, (errorAndLog last ifNil: [''] ifNotNil: [:log| ': ', log])!
Item was added: + ----- Method: CogProcessorAlien>>runInMemory: (in category 'execution') ----- + runInMemory: aMemory + | result | + result := self primitiveRunInMemory: aMemory minimumAddress: 0 readOnlyBelow: 0. + result ~~ self ifTrue: + [self error: 'eek!!']!
Item was added: + ----- Method: CogProcessorAlien>>runInMemory:minimumAddress:readOnlyBelow: (in category 'execution') ----- + runInMemory: aMemory minimumAddress: minimumAddress readOnlyBelow: minimumWritableAddress + | result | + result := self primitiveRunInMemory: aMemory + minimumAddress: minimumAddress + readOnlyBelow: minimumWritableAddress. + result ~~ self ifTrue: + [self error: 'eek!!']!
Item was added: + ----- Method: CogProcessorAlien>>runInMemory:readExecuteOnlyBelow: (in category 'execution') ----- + runInMemory: aMemory readExecuteOnlyBelow: minWriteMaxExecAddr + | result | + result := self primitiveRunInMemory: aMemory minimumAddress: 0 readOnlyBelow: minWriteMaxExecAddr. + result ~~ self ifTrue: + [self error: 'eek!!']!
Item was added: + ----- Method: CogProcessorAlien>>singleStepIn: (in category 'execution') ----- + singleStepIn: aMemory + | result | + result := self primitiveSingleStepInMemory: aMemory minimumAddress: 0 readOnlyBelow: aMemory size. + result ~~ self ifTrue: + [self error: 'eek!!']!
Item was added: + ----- Method: CogProcessorAlien>>singleStepIn:minimumAddress:readOnlyBelow: (in category 'execution') ----- + singleStepIn: aMemory minimumAddress: minimumAddress readOnlyBelow: minimumWritableAddress + | result | + result := self primitiveSingleStepInMemory: aMemory + minimumAddress: minimumAddress + readOnlyBelow: minimumWritableAddress. + result ~~ self ifTrue: + [self error: 'eek!!']!
Item was added: + ----- Method: CogProcessorAlien>>singleStepIn:readExecuteOnlyBelow: (in category 'execution') ----- + singleStepIn: aMemory readExecuteOnlyBelow: minWriteMaxExecAddr + | result | + result := self primitiveSingleStepInMemory: aMemory minimumAddress: 0 readOnlyBelow: minWriteMaxExecAddr. + result ~~ self ifTrue: + [self error: 'eek!!']!
Item was added: + CogProcessorAlien variableByteSubclass: #GdbARMAlien + instanceVariableNames: '' + classVariableNames: 'OpcodeExceptionMap PostBuildStackDelta' + poolDictionaries: '' + category: 'Cog-Processors'!
Item was added: + ----- Method: GdbARMAlien class>>dataSize (in category 'instance creation') ----- + dataSize + + ^1536!
Item was added: + ----- Method: GdbARMAlien class>>defaultIntegerBaseInDebugger (in category 'debugger') ----- + defaultIntegerBaseInDebugger + ^16!
Item was added: + ----- Method: GdbARMAlien class>>new (in category 'instance creation') ----- + new + ^(self atAddress: self primitiveNewCPU) reset!
Item was added: + ----- Method: GdbARMAlien class>>primitiveNewCPU (in category 'primitives') ----- + primitiveNewCPU + "Answer the address of a new ARMulator C type ARMul_State instance." + <primitive: 'primitiveNewCPU' module: 'GdbARMPlugin'> + ^self primitiveFailed!
Item was added: + ----- Method: GdbARMAlien>>abstractInstructionCompilerClass (in category 'Cog API') ----- + abstractInstructionCompilerClass + ^CogARMCompiler!
Item was added: + ----- Method: GdbARMAlien>>branchAndLinkOpcodeWithOffset: (in category 'opcodes') ----- + branchAndLinkOpcodeWithOffset: aNumber + + | offset | + offset := (aNumber - 8) asInteger >> 2. + (offset bitAnd: 16rFF000000) ~= 0 ifTrue: [self error: 'The offset is to far. ARM does not support such far jumps.']. + ^ 16reb000000 bitOr: (offset bitAnd: 16r00FFFFFF)!
Item was added: + ----- Method: GdbARMAlien>>callOpcode (in category 'opcodes') ----- + callOpcode + "The call command does not generally exist. The most similar would be bl <offset>" + ^ self branchAndLinkOpcodeWithOffset: 0.!
Item was added: + ----- Method: GdbARMAlien>>cflag (in category 'accessing') ----- + cflag + ^self unsignedLongAt: 577!
Item was added: + ----- Method: GdbARMAlien>>eflags (in category 'accessing') ----- + eflags + + ^ (((self nflag << 5 bitOr: self zflag << 4) + bitOr: self cflag << 3) + bitOr: self vflag << 2) + bitOr: self ifflags!
Item was added: + ----- Method: GdbARMAlien>>handleExecutionPrimitiveFailureIn:minimumAddress:readOnlyBelow: (in category 'error handling') ----- + handleExecutionPrimitiveFailureIn: memoryArray "<Bitmap|ByteArray>" minimumAddress: minimumAddress "<Integer>" readOnlyBelow: minimumWritableAddress "<Integer>" + "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 pc) between: minimumAddress and: memoryArray byteSize - 1) ifTrue: + [opcode := memoryArray byteAt: pc + 1. + ^self + perform: (OpcodeExceptionMap at: opcode + 1) + with: pc + with: memoryArray + with: minimumWritableAddress]." + ^self reportPrimitiveFailure!
Item was added: + ----- Method: GdbARMAlien>>ifflags (in category 'accessing') ----- + ifflags + ^self unsignedLongAt: 585!
Item was added: + ----- Method: GdbARMAlien>>integerRegisterState (in category 'accessing-abstract') ----- + integerRegisterState + ^{ self r0. self r1. self r2. self r3. self r4. self r5. self r6. self r7. self r8. + self r9. self r10. self r11. self r12. self sp. self lr. self pc}!
Item was added: + ----- Method: GdbARMAlien>>lr (in category 'accessing') ----- + lr + ^self unsignedLongAt: 69!
Item was added: + ----- Method: GdbARMAlien>>lr: (in category 'accessing') ----- + lr: anUnsignedInteger + + ^self unsignedLongAt: 69 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>nflag (in category 'accessing') ----- + nflag + ^self unsignedLongAt: 569!
Item was added: + ----- Method: GdbARMAlien>>nopOpcode (in category 'opcodes') ----- + nopOpcode + "mov r0, r0" + ^ 16rE1A01001!
Item was added: + ----- Method: GdbARMAlien>>pc (in category 'accessing') ----- + pc + ^self unsignedLongAt: 73!
Item was added: + ----- Method: GdbARMAlien>>pc: (in category 'accessing') ----- + pc: anUnsignedInteger + + ^self unsignedLongAt: 73 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>primitiveDisassembleAt:inMemory: (in category 'primitives') ----- + primitiveDisassembleAt: address inMemory: memoryArray "<Bitmap|ByteArray>" + "Answer an Array of the size and the disassembled code string for the instruction at the current instruction pointer in memory." + <primitive: 'primitiveDisassembleAtInMemory' module: 'GdbARMPlugin'> + ^self primitiveFailed!
Item was added: + ----- Method: GdbARMAlien>>primitiveErrorAndLog (in category 'primitives') ----- + primitiveErrorAndLog + "Answer an array of the current error code and log contents" + <primitive: 'primitiveErrorAndLog' module: 'GdbARMPlugin'> + ^self primitiveFailed!
Item was added: + ----- Method: GdbARMAlien>>primitiveResetCPU (in category 'primitives') ----- + primitiveResetCPU + "Reset the receiver to registers all zero, and protected 32-bit mode." + <primitive: 'primitiveResetCPU' module: 'GdbARMPlugin'> + ^self reportPrimitiveFailure!
Item was added: + ----- Method: GdbARMAlien>>primitiveRunInMemory:minimumAddress:readOnlyBelow: (in category 'primitives') ----- + primitiveRunInMemory: memoryArray "<Bitmap|ByteArray>" minimumAddress: minimumAddress "<Integer>" readOnlyBelow: minimumWritableAddress "<Integer>" + "Run the receiver using the argument as the store. Origin the argument at 0. i.e. the first byte of the + memoryArray is address 0. Make addresses below minimumAddress illegal. Convert out-of-range + call, jump and memory read/writes into register instructions into ProcessorSimulationTrap signals." + <primitive: 'primitiveRunInMemoryMinimumAddressReadWrite' module: 'GdbARMPlugin' error: ec> + ^ec == #'inappropriate operation' + ifTrue: [self handleExecutionPrimitiveFailureIn: memoryArray + minimumAddress: minimumAddress + readOnlyBelow: minimumWritableAddress] + ifFalse: [self reportPrimitiveFailure] + + "self printRegistersOn: Transcript"!
Item was added: + ----- Method: GdbARMAlien>>primitiveSingleStepInMemory:minimumAddress:readOnlyBelow: (in category 'primitives') ----- + primitiveSingleStepInMemory: memoryArray "<Bitmap|ByteArray>" minimumAddress: minimumAddress "<Integer>" readOnlyBelow: minimumWritableAddress "<Integer>" + "Single-step the receiver using the argument as the store. Origin the argument at 0. i.e. the first byte of the + memoryArray is address 0. Make addresses below minimumAddress illegal. Convert out-of-range + call, jump and memory read/writes into register instructions into ProcessorSimulationTrap signals." + <primitive: 'primitiveSingleStepInMemoryMinimumAddressReadWrite' module: 'GdbARMPlugin' error: ec> + ^ec == #'inappropriate operation' + ifTrue: [self handleExecutionPrimitiveFailureIn: memoryArray + minimumAddress: minimumAddress + readOnlyBelow: minimumWritableAddress] + ifFalse: [self reportPrimitiveFailure]!
Item was added: + ----- Method: GdbARMAlien>>printRegisterState:on: (in category 'printing') ----- + printRegisterState: registerStateVector on: aStream + | rsvs fields| + aStream ensureCr. + rsvs := registerStateVector readStream. + fields := #( r0 r1 r2 r3 r4 r5 r6 cr r7 r8 r9 r10 r11 r12 cr sp lr pc eflags cr). + fields withIndexDo: + [:sym :index| | val | + sym = #cr + ifTrue: [aStream cr] + ifFalse: + [(val := rsvs next) isNil ifTrue: [^self]. + aStream nextPutAll: sym; nextPut: $:; space. + val printOn: aStream base: 16 length: 8 padded: true. + #eflags == sym + ifTrue: + [aStream space. + "'FIVCZN'"'--VCZN' withIndexDo: + [:flag :bitIndex| + flag ~= $- ifTrue: + [aStream nextPut: flag; nextPutAll: 'F='; print: (val bitAnd: 1 << (bitIndex - 1)) >> (bitIndex - 1); space]]] + ifFalse: + [val > 16 ifTrue: + [aStream space; nextPut: $(. + val printOn: aStream base: 10 length: 1 padded: false. + aStream nextPut: $)]]. + (fields at: index + 1) ~~ #cr ifTrue: + [aStream tab]]]!
Item was added: + ----- Method: GdbARMAlien>>r0 (in category 'accessing') ----- + r0 + ^self unsignedLongAt: 13!
Item was added: + ----- Method: GdbARMAlien>>r0: (in category 'accessing') ----- + r0: anUnsignedInteger + + ^self unsignedLongAt: 13 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r1 (in category 'accessing') ----- + r1 + ^self unsignedLongAt: 17!
Item was added: + ----- Method: GdbARMAlien>>r10 (in category 'accessing') ----- + r10 + ^self unsignedLongAt: 53!
Item was added: + ----- Method: GdbARMAlien>>r10: (in category 'accessing') ----- + r10: anUnsignedInteger + + ^self unsignedLongAt: 53 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r11 (in category 'accessing') ----- + r11 + ^self unsignedLongAt: 57!
Item was added: + ----- Method: GdbARMAlien>>r11: (in category 'accessing') ----- + r11: anUnsignedInteger + + ^self unsignedLongAt: 57 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r12 (in category 'accessing') ----- + r12 + ^self unsignedLongAt: 61!
Item was added: + ----- Method: GdbARMAlien>>r12: (in category 'accessing') ----- + r12: anUnsignedInteger + + ^self unsignedLongAt: 61 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r1: (in category 'accessing') ----- + r1: anUnsignedInteger + + ^self unsignedLongAt: 17 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r2 (in category 'accessing') ----- + r2 + ^self unsignedLongAt: 21!
Item was added: + ----- Method: GdbARMAlien>>r2: (in category 'accessing') ----- + r2: anUnsignedInteger + + ^self unsignedLongAt: 21 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r3 (in category 'accessing') ----- + r3 + ^self unsignedLongAt: 25!
Item was added: + ----- Method: GdbARMAlien>>r3: (in category 'accessing') ----- + r3: anUnsignedInteger + + ^self unsignedLongAt: 25 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r4 (in category 'accessing') ----- + r4 + ^self unsignedLongAt: 29!
Item was added: + ----- Method: GdbARMAlien>>r4: (in category 'accessing') ----- + r4: anUnsignedInteger + + ^self unsignedLongAt: 29 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r5 (in category 'accessing') ----- + r5 + ^self unsignedLongAt: 33!
Item was added: + ----- Method: GdbARMAlien>>r5: (in category 'accessing') ----- + r5: anUnsignedInteger + + ^self unsignedLongAt: 33 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r6 (in category 'accessing') ----- + r6 + ^self unsignedLongAt: 37!
Item was added: + ----- Method: GdbARMAlien>>r6: (in category 'accessing') ----- + r6: anUnsignedInteger + + ^self unsignedLongAt: 37 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r7 (in category 'accessing') ----- + r7 + ^self unsignedLongAt: 41!
Item was added: + ----- Method: GdbARMAlien>>r7: (in category 'accessing') ----- + r7: anUnsignedInteger + + ^self unsignedLongAt: 41 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r8 (in category 'accessing') ----- + r8 + ^self unsignedLongAt: 45!
Item was added: + ----- Method: GdbARMAlien>>r8: (in category 'accessing') ----- + r8: anUnsignedInteger + + ^self unsignedLongAt: 45 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>r9 (in category 'accessing') ----- + r9 + ^self unsignedLongAt: 49!
Item was added: + ----- Method: GdbARMAlien>>r9: (in category 'accessing') ----- + r9: anUnsignedInteger + + ^self unsignedLongAt: 49 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>registerState (in category 'accessing-abstract') ----- + registerState + ^{ self r0. self r1. self r2. self r3. self r4. self r5. self r6. self r7. + self r8. self r0. self r10. self r11. self r12. self sp. self lr. self pc. self eflags }!
Item was added: + ----- Method: GdbARMAlien>>reset (in category 'accessing') ----- + reset + self primitiveResetCPU!
Item was added: + ----- Method: GdbARMAlien>>retOpcode (in category 'opcodes') ----- + retOpcode + "the ret command does not generally exist. the most similar would be mov pc, lr" + ^ self halt.!
Item was added: + ----- Method: GdbARMAlien>>sflag (in category 'accessing') ----- + sflag + ^self unsignedLongAt: 589!
Item was added: + ----- Method: GdbARMAlien>>sp (in category 'accessing') ----- + sp + ^self unsignedLongAt: 65!
Item was added: + ----- Method: GdbARMAlien>>sp: (in category 'accessing') ----- + sp: anUnsignedInteger + + ^self unsignedLongAt: 65 put: anUnsignedInteger!
Item was added: + ----- Method: GdbARMAlien>>vflag (in category 'accessing') ----- + vflag + ^self unsignedLongAt: 581!
Item was added: + ----- Method: GdbARMAlien>>zflag (in category 'accessing') ----- + zflag + ^self unsignedLongAt: 573!
Item was added: + TestCase subclass: #GdbARMAlienTests + instanceVariableNames: 'processor' + classVariableNames: '' + poolDictionaries: '' + category: 'Cog-Processors-Tests'!
Item was added: + ----- Method: GdbARMAlienTests>>callTrapPerformance: (in category 'tests') ----- + callTrapPerformance: n + "Call a function that is out-of-range. Ensure the call is trapped." + "self new testCallTrap" + | memory | + "The address is out of range of memory every which way (whether relative or absolute and whether big-endian or little." + memory := ByteArray new: 1024. + memory replaceFrom: 1 to: 5 with: { self processor callOpcode. 0. 16r80. 16r80. 0. } asByteArray. + self processor + eip: 0; + esp: (memory size - 4). "Room for return address" + 1 to: n do: + [:ign| + [self processor singleStepIn: memory] + on: ProcessorSimulationTrap + do: [:ex|]]. + + "QSystemProfiler spyOn: [GdbARMAlienTests new callTrapPerformance: 1024*128]" + "Time millisecondsToRun: [GdbARMAlienTests new callTrapPerformance: 1024*128] 2463" + "Time millisecondsToRun: [1 to: 1024*1024*64 do: [:ign| nil yourself]] 636" + "Time millisecondsToRun: [1 to: 1024*1024*64 do: [:ign| nil perform: #ifNotNilDo: with: nil]] 3639" + "Time millisecondsToRun: [1 to: 1024*1024*64 do: [:ign| nil perform: #ifNotNilDo:ifNil: with: nil with: nil]] 12401"!
Item was added: + ----- Method: GdbARMAlienTests>>nfib (in category 'accessing') ----- + nfib + "long fib(long n) { return n <= 1 ? 1 : fib(n-1) + fib(n-2) + 1; } + as compiled by arm-elf-gnuabi-gcc fib.c -c -marm + also, the jumps are changed by hand." + "| bat nfib ip | + bat := GdbARMAlienTests new. + nfib := bat nfib asWordArray. + ip := 0. + 23 timesRepeat: + [bat processor disassembleInstructionAt: ip In: nfib into: + [:da :len| + Transcript nextPutAll: da; cr; flush. + ip := ip + len]]" + ^#("00000000 <fib>: + 0:" 16re92d4810 "push {r4, fp, lr} fp = r11, sp is changed in this command + 4:" 16re28db008 "add fp, sp, #8 now, the frame pointer is changed + 8:" 16re24dd00c "sub sp, sp, #12 + c:" 16re50b0010 "str r0, [fp, #-16] + 10:" 16re51b3010 "ldr r3, [fp, #-16] r3 <- [fp-16] <- r0 + 14:" 16re3530001 "cmp r3, #1 + 18:" 16rda00000c "ble 50 <fib+0x50> + 1c:" 16re51b3010 "ldr r3, [fp, #-16] + 20:" 16re2433001 "sub r3, r3, #1 + 24:" 16re1a00003 "mov r0, r3 + 28:" 16rebfffff4 "bl 0 <fib> + 2c:" 16re1a04000 "mov r4, r0 + 30:" 16re51b3010 "ldr r3, [fp, #-16] + 34:" 16re2433002 "sub r3, r3, #2 + 38:" 16re1a00003 "mov r0, r3 + 3c:" 16rebffffef "bl 0 <fib> + 40:" 16re1a03000 "mov r3, r0 + 44:" 16re0843003 "add r3, r4, r3 + 48:" 16re2833001 "add r3, r3, #1 + 4c:" 16rea000000 "b 54 <fib+0x54> + 50:" 16re3a03001 "mov r3, #1 + 54:" 16re1a00003 "mov r0, r3 + 58:" 16re24bd008 "sub sp, fp, #8 + 5c:" 16re8bd8810 "pop {r4, fp, pc}")!
Item was added: + ----- Method: GdbARMAlienTests>>processor (in category 'accessing') ----- + processor + processor ifNil: + [processor := GdbARMAlien new]. + ^processor!
Item was added: + ----- Method: GdbARMAlienTests>>registerGetters (in category 'accessing') ----- + registerGetters + ^#(r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 lr sp pc)!
Item was added: + ----- Method: GdbARMAlienTests>>registerSetters (in category 'accessing') ----- + registerSetters + ^#(r0: r1: r2: r3: r4: r5: r6: r7: r8: r9: r10: r11: r12: lr: sp: pc:)!
Item was added: + ----- Method: GdbARMAlienTests>>runNFib:disassemble:printRegisters: (in category 'execution') ----- + runNFib: n disassemble: disassemble printRegisters: printRegisters + "Run nfib wth the argument. Answer the result." + "self new runNFib: 5 disassemble: true printRegisters: true" + | memory | + memory := WordArray new: 1024 * 2 withAll: self processor nopOpcode. + memory replaceFrom: 1 to: self nfib size with: self nfib asWordArray startingAt: 1. + self processor + r0: n;"argument n" + lr: memory size * 2; "return address" + pc: 0; + sp: (memory size * 4) - 16. + printRegisters ifTrue: + [self processor printRegistersOn: Transcript. + Transcript cr; flush]. + "run until something goes wrong." + self processor runInMemory: memory readExecuteOnlyBelow: memory size / 2. + printRegisters ifTrue: + [self processor printRegistersOn: Transcript. + Transcript cr; flush]. + ^self processor r0!
Item was added: + ----- Method: GdbARMAlienTests>>singleStepNFib:disassemble:printRegisters: (in category 'execution') ----- + singleStepNFib: n disassemble: disassemble printRegisters: printRegisters + "Run nfib wth the argument. Answer the result." + "self new runNFib: 5 disassemble: true printRegisters: true" + | memory | + memory := WordArray new: 1024 * 2 withAll: self processor nopOpcode. + memory replaceFrom: 1 to: self nfib size with: self nfib asWordArray startingAt: 1. + self processor + r0: n; "argument n" + lr: self nfib size * 4; "return address" + pc: 0; + sp: (memory size * 4 - 12). "Room for return address, frame pointer and r4" + printRegisters ifTrue: + [self processor printRegistersOn: Transcript. + Transcript cr; flush]. + [disassemble ifTrue: + [Transcript nextPutAll: (self processor disassembleNextInstructionIn: memory); cr; flush]. + self processor singleStepIn: memory readExecuteOnlyBelow: memory size * 4 / 2. + printRegisters ifTrue: + [self processor printRegistersOn: Transcript. + Transcript cr; flush]. + "stop, once we leave the nfib code and step through the nops after that." + self processor pc < (self nfib size * 4)] whileTrue. + ^self processor r0!
Item was added: + ----- Method: GdbARMAlienTests>>testCallTrap (in category 'tests') ----- + testCallTrap + "Call a function that is out-of-range. Ensure the call is trapped." + "self new testCallTrap" + | memory | + memory := Bitmap new: 256 withAll: self processor nopOpcode. + memory longAt: 1 put: (self processor branchAndLinkOpcodeWithOffset: 1024) bigEndian: false. + memory := memory asByteArray. + self processor + pc: 0; + sp: (memory size - 4); "Room for return address" + singleStepIn: memory. + "We have to step twice, because the first step only changes the pc, but does not fetch anything from the address it points to." + self should: [self processor singleStepIn: memory] + raise: Error + withExceptionDo: + [:pst| + self assert: self processor pc = 1024. + self assert: self processor lr = 4. + self assert: pst messageText = 'Error 0: Illegal Instruction fetch address (0x00000400).'].!
Item was added: + ----- Method: GdbARMAlienTests>>testDisassembling (in category 'tests') ----- + testDisassembling + + | memory result | + memory := WordArray new: 2. + memory at: 1 put: 16rEF200000. + result := self processor + disassembleInstructionAt: 0 + In: memory + into: [:str :len | + self + assert: len = 4; + assert: str = 'svc 0x00200000'].!
Item was added: + ----- Method: GdbARMAlienTests>>testExecutionTrap (in category 'tests') ----- + testExecutionTrap + "Execute a run of nops. test executing beyond the executable limit is trapped." + "self new testExecutionTrap" + | memory | + "The address is out of range of memory every which way (whether relative or absolute and whether big-endian or little." + memory := (Bitmap new: 1024 * 2 withAll: self processor nopOpcode) asByteArray. + self processor + pc: 0; + sp: (memory size - 4). "Room for return address" + self should: [self processor runInMemory: memory minimumAddress: 0 readOnlyBelow: memory size / 2] + raise: Error + withExceptionDo: + [:err| + self assert: self processor pc = (memory size / 2). + self assert: ('Error 0: Illegal Instruction fetch address (0x00001000).' match: err messageText)]. + self processor pc: 0. + self should: [[self processor singleStepIn: memory minimumAddress: 0 readOnlyBelow: memory size / 2] repeat] + raise: Error + withExceptionDo: + [:err| + self assert: self processor pc = (memory size / 2). + self assert: ('Error 0: Illegal Instruction fetch address (0x00001000).' match: err messageText)]!
Item was added: + ----- Method: GdbARMAlienTests>>testFlags (in category 'tests') ----- + testFlags + "self new testFlags" + | memory | + memory := Bitmap new: 3. + memory longAt: 1 put: 16rE3A03001 bigEndian: false. "MOV r3, #1" + memory longAt: 5 put: 16rE3530001 bigEndian: false. "CMP r3, #1" + memory := memory asByteArray. + self processor + disassembleInstructionAt: 0 + In: memory + into: [:str :len | + self + assert: len = 4; + assert: str = 'mov r3, #1']. + self processor + disassembleInstructionAt: 4 + In: memory + into: [:str :len | + self + assert: len = 4; + assert: str = 'cmp r3, #1']. + self processor + pc: 0; + singleStepIn: memory; + singleStepIn: memory. + self + assert: self processor pc = 16r8; + assert: self processor r3 = 1; + assert: self processor zflag = 1; + assert: self processor cflag = 1; + assert: self processor vflag = 0; + assert: self processor nflag = 0. + self processor reset. + self assert: self processor eflags = 3. "IFFlags are both set."!
Item was added: + ----- Method: GdbARMAlienTests>>testMOVSD (in category 'tests') ----- + testMOVSD + "Test MOVSD indirecting through edx." + "self new testMOVSD" + self processor + edx: 0; + eip: 0; + singleStepIn: {16rF2. 16r0F. 16r10. 16r42. 16r04. 16r90. 16r01. 16r02. 16r03. 16r04. 16r05. 16r06} asByteArray "movsd %ds:0x4(%edx), %xmm0;nop;garbage". + self assert: self processor eip = 5. + self assert: self processor xmm0low = 16r0605040302019004!
Item was added: + ----- Method: GdbARMAlienTests>>testNfib1 (in category 'tests') ----- + testNfib1 + "self new testNfib1" + self should: [self runNFib: 1 disassemble: false printRegisters: true] + raise: Error + withExceptionDo: + [:err| self assert: err messageText = 'Error 0: Illegal Instruction fetch address (0x00001000).']. + self deny: (self processor pc between: 0 and: self nfib size). + self assert: self processor r0 = 1 benchFib!
Item was added: + ----- Method: GdbARMAlienTests>>testNfib16 (in category 'tests') ----- + testNfib16 + "self new testNfib16" + self should: [self runNFib: 16 disassemble: false printRegisters: false] + raise: Error. + self deny: (self processor pc between: 0 and: self nfib size). + self assert: self processor r0 = 16 benchFib!
Item was added: + ----- Method: GdbARMAlienTests>>testNfib2 (in category 'tests') ----- + testNfib2 + "self new testNfib2" + self should: [self runNFib: 2 disassemble: false printRegisters: false] + raise: Error. + self deny: (self processor pc between: 0 and: self nfib size). + self assert: self processor r0 = 2 benchFib!
Item was added: + ----- Method: GdbARMAlienTests>>testNfib4 (in category 'tests') ----- + testNfib4 + "self new testNfib4" + self should: [self runNFib: 4 disassemble: false printRegisters: false] + raise: Error. + self deny: (self processor pc between: 0 and: self nfib size). + self assert: self processor r0 = 4 benchFib!
Item was added: + ----- Method: GdbARMAlienTests>>testResetCPU (in category 'tests') ----- + testResetCPU + "self new testResetCPU" + self registerSetters do: + [:setter| + self processor perform: setter with: 16r55555555]. + self registerGetters do: + [:getter| + self assert: 16r55555555 = (self processor perform: getter)]. + self processor reset. + self registerGetters do: + [:getter| + self assert: 0 = (self processor perform: getter)]!
Item was added: + ----- Method: GdbARMAlienTests>>testStepNfib1 (in category 'tests') ----- + testStepNfib1 + "self new testStepNfib1" + self singleStepNFib: 1 disassemble: false printRegisters: false. + self assert: self processor pc = (self nfib asWordArray size * 4). + self assert: self processor r0 = 1 benchFib!
Item was added: + ----- Method: GdbARMAlienTests>>testStepNfib2 (in category 'tests') ----- + testStepNfib2 + "self new testStepNfib2" + self singleStepNFib: 2 disassemble: false printRegisters: false. + self assert: self processor pc = (self nfib size * 4). + self assert: self processor r0 = 2 benchFib!
Item was added: + ----- Method: GdbARMAlienTests>>testStepNfib4 (in category 'tests') ----- + testStepNfib4 + "self new testStepNfib4" + self singleStepNFib: 4 disassemble: false printRegisters: false. + self assert: self processor pc = (self nfib size * 4). + self assert: self processor r0 = 4 benchFib!
Item was added: + SmartSyntaxInterpreterPlugin subclass: #GdbARMPlugin + instanceVariableNames: 'prevInterruptCheckChain' + classVariableNames: '' + poolDictionaries: 'VMBasicConstants' + category: 'Cog-ProcessorPlugins'! + + !GdbARMPlugin commentStamp: '<historical>' prior: 0! + I provide access to the ARMulator ARM emulator and the libopcodes ARM disassembler.!
Item was added: + ----- Method: GdbARMPlugin class>>declareCVarsIn: (in category 'translation') ----- + declareCVarsIn: aCCodeGenerator + "prevInterruptCheckChain lives in sqGdbARMPlugin.c" + super declareCVarsIn: aCCodeGenerator. + aCCodeGenerator removeVariable: 'prevInterruptCheckChain'!
Item was added: + ----- Method: GdbARMPlugin class>>hasHeaderFile (in category 'translation') ----- + hasHeaderFile + "We need a header to declare newcpu and pull in bochs.h & cpu.h" + ^true!
Item was added: + ----- Method: GdbARMPlugin>>forceStopOnInterrupt (in category 'interruption') ----- + forceStopOnInterrupt + interpreterProxy getInterruptPending ifTrue: + [self forceStopRunning]!
Item was added: + ----- Method: GdbARMPlugin>>primitiveDisassembleAt:InMemory: (in category 'primitives') ----- + "cpuAlien <GdbARMAlien>" primitiveDisassembleAt: address "<Integer>" InMemory: memory "<Bitmap|ByteArray|WordArray>" + "Return an Array of the instruction length and its decompilation as a string for the instruction at address in memory." + | cpuAlien cpu instrLenOrErr resultObj log logLen logObj logObjData | + <var: #cpu type: #'void *'> + cpuAlien := self primitive: #primitiveDisassembleAtInMemory + parameters: #(Unsigned WordsOrBytes) + receiver: #Oop. + (cpu := self startOfData: cpuAlien) = 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadReceiver]. + instrLenOrErr := self disassembleFor: cpu + At: address + In: memory + Size: (interpreterProxy byteSizeOf: memory cPtrAsOop). + instrLenOrErr < 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrInappropriate]. + log := self getlog: (self cCode: [self addressOf: logLen] inSmalltalk: [logLen := 0]). + resultObj := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 2. + resultObj = 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrNoMemory]. + + "Easier keeping the damn thing on the stack than using pushRemappableOop:/popRemappableOop. + Where is topRemappableOop when you need it?" + interpreterProxy pushRemappableOop: resultObj. + logObj := interpreterProxy + instantiateClass: interpreterProxy classString + indexableSize: logLen. + interpreterProxy failed ifTrue: + [interpreterProxy popRemappableOop. + ^interpreterProxy primitiveFailFor: PrimErrNoMemory]. + logObjData := interpreterProxy arrayValueOf: logObj. + self cCode: 'memcpy(logObjData, log, logLen)' inSmalltalk: [logObjData. log]. + resultObj := interpreterProxy popRemappableOop. + interpreterProxy + storePointer: 0 + ofObject: resultObj + withValue: (interpreterProxy integerObjectOf: instrLenOrErr). + interpreterProxy storePointer: 1 ofObject: resultObj withValue: logObj. + + ^resultObj!
Item was added: + ----- Method: GdbARMPlugin>>primitiveErrorAndLog (in category 'primitives') ----- + primitiveErrorAndLog + | log logLen resultObj logObj logObjData | + <var: #log type: #'char *'> + <var: #logObjData type: #'char *'> + self primitive: #primitiveErrorAndLog parameters: #(). + + log := self getlog: (self cCode: [self addressOf: logLen] inSmalltalk: [logLen := 0]). + resultObj := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 2. + resultObj = 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrNoMemory]. + + interpreterProxy + storePointer: 0 + ofObject: resultObj + withValue: (interpreterProxy integerObjectOf: self errorAcorn). + + logLen > 0 ifTrue: + [interpreterProxy pushRemappableOop: resultObj. + logObj := interpreterProxy + instantiateClass: interpreterProxy classString + indexableSize: logLen. + interpreterProxy failed ifTrue: + [interpreterProxy popRemappableOop. + ^interpreterProxy primitiveFailFor: PrimErrNoMemory]. + + resultObj := interpreterProxy popRemappableOop. + logObjData := interpreterProxy arrayValueOf: logObj. + self cCode: 'memcpy(logObjData, log, logLen)' inSmalltalk: [logObjData. log]. + interpreterProxy storePointer: 1 ofObject: resultObj withValue: logObj]. + interpreterProxy pop: 1 thenPush: resultObj!
Item was added: + ----- Method: GdbARMPlugin>>primitiveFlushICacheFrom:To: (in category 'primitives') ----- + "cpuAlien <GdbARMAlien>" primitiveFlushICacheFrom: startAddress "<Integer>" To: endAddress "<Integer>" + "Flush the icache in the requested range" + | cpuAlien cpu | + <var: #cpu type: 'void *'> + cpuAlien := self primitive: #primitiveFlushICacheFromTo + parameters: #(Unsigned Unsigned) + receiver: #Oop. + (cpu := self startOfData: cpuAlien) = 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadReceiver]. + self flushICache: cpu From: startAddress To: endAddress!
Item was added: + ----- Method: GdbARMPlugin>>primitiveNewCPU (in category 'primitives') ----- + primitiveNewCPU + | cpu | + <var: #cpu type: 'void *'> + self primitive: #primitiveNewCPU parameters: #(). + + cpu := self cCode: 'newCPU()' inSmalltalk: [0]. + cpu = 0 ifTrue: + [^interpreterProxy primitiveFail]. + interpreterProxy + pop: 1 + thenPush: (interpreterProxy positive32BitIntegerFor: + (self cCoerceSimple: cpu + to: 'unsigned long'))!
Item was added: + ----- Method: GdbARMPlugin>>primitiveResetCPU (in category 'primitives') ----- + primitiveResetCPU + | cpuAlien cpu maybeErr | + <var: #cpu type: 'void *'> + cpuAlien := self primitive: #primitiveResetCPU parameters: #() receiver: #Oop. + (cpu := self startOfData: cpuAlien) = 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadReceiver]. + maybeErr := self resetCPU: cpu. + maybeErr ~= 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrInappropriate]. + ^cpuAlien!
Item was added: + ----- Method: GdbARMPlugin>>primitiveRunInMemory:minimumAddress:readOnlyBelow: (in category 'primitives') ----- + "cpuAlien <GdbARMAlien>" primitiveRunInMemory: memory "<Bitmap|ByteArray|WordArray>" minimumAddress: minAddress "<Integer>" readOnlyBelow: minWriteMaxExecAddress "<Integer>" + "Run the cpu using the first argument as the memory and the following arguments defining valid addresses, running until it halts or hits an exception." + | cpuAlien cpu maybeErr | + <var: #cpu type: #'void *'> + cpuAlien := self primitive: #primitiveRunInMemoryMinimumAddressReadWrite + parameters: #(WordsOrBytes Unsigned Unsigned) + receiver: #Oop. + (cpu := self startOfData: cpuAlien) = 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadReceiver]. + prevInterruptCheckChain := interpreterProxy setInterruptCheckChain: #forceStopOnInterrupt asSymbol. + prevInterruptCheckChain = #forceStopOnInterrupt asSymbol ifTrue: + [prevInterruptCheckChain = 0]. + maybeErr := self runCPU: cpu + In: memory + Size: (interpreterProxy byteSizeOf: memory cPtrAsOop) + MinAddressRead: minAddress + Write: minWriteMaxExecAddress. + interpreterProxy setInterruptCheckChain: prevInterruptCheckChain. + maybeErr ~= 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrInappropriate]. + ^cpuAlien!
Item was added: + ----- Method: GdbARMPlugin>>primitiveSingleStepInMemory:minimumAddress:readOnlyBelow: (in category 'primitives') ----- + "cpuAlien <GdbARMAlien>" primitiveSingleStepInMemory: memory "<Bitmap|ByteArray|WordArray>" minimumAddress: minAddress "<Integer>" readOnlyBelow: minWriteMaxExecAddress "<Integer>" + "Single-step the cpu using the first argument as the memory and the following arguments defining valid addresses." + | cpuAlien cpu maybeErr | + <var: #cpu type: #'void *'> + cpuAlien := self primitive: #primitiveSingleStepInMemoryMinimumAddressReadWrite + parameters: #(WordsOrBytes Unsigned Unsigned) + receiver: #Oop. + (cpu := self startOfData: cpuAlien) = 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrBadReceiver]. + maybeErr := self singleStepCPU: cpu + In: memory + Size: (interpreterProxy byteSizeOf: memory cPtrAsOop) + MinAddressRead: minAddress + Write: minWriteMaxExecAddress. + maybeErr ~= 0 ifTrue: + [^interpreterProxy primitiveFailFor: PrimErrInappropriate]. + ^cpuAlien!
Item was added: + ----- Method: GdbARMPlugin>>sizeField: (in category 'alien support') ----- + sizeField: rcvr + "Answer the first field of rcvr which is assumed to be an Alien of at least 8 bytes" + <inline: true> + ^self longAt: rcvr + BaseHeaderSize!
Item was added: + ----- Method: GdbARMPlugin>>startOfData: (in category 'alien support') ----- + startOfData: rcvr "<Alien oop> ^<Integer>" + "Answer the start of rcvr's data. For direct aliens this is the address of + the second field. For indirect and pointer aliens it is what the second field points to." + <inline: true> + ^(self sizeField: rcvr) > 0 + ifTrue: [rcvr + BaseHeaderSize + BytesPerOop] + ifFalse: [self longAt: rcvr + BaseHeaderSize + BytesPerOop]!
vm-dev@lists.squeakfoundation.org