SOURCE LINK: support DWARF4 24/27824/2
authorwoojin <woojin2.jung@samsung.com>
Fri, 19 Sep 2014 12:14:42 +0000 (21:14 +0900)
committerwoojin <woojin2.jung@samsung.com>
Fri, 19 Sep 2014 12:52:04 +0000 (21:52 +0900)
import and modify eclipse cdt edc plugin to support DWARF4

Change-Id: Ia855410047276871358b9157525c6bb41405fcae
Signed-off-by: woojin <woojin2.jung@samsung.com>
328 files changed:
org.eclipse.cdt.debug.edc/.classpath [new file with mode: 0644]
org.eclipse.cdt.debug.edc/.project [new file with mode: 0644]
org.eclipse.cdt.debug.edc/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.eclipse.cdt.debug.edc/META-INF/MANIFEST.MF [new file with mode: 0644]
org.eclipse.cdt.debug.edc/build.properties [new file with mode: 0644]
org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.debug.core_7.1.0.201109151620.jar [new file with mode: 0644]
org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.debug.edc.tcf.extension_2.0.0.201109151658.jar [new file with mode: 0644]
org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.dsf_2.2.0.201109151620.jar [moved from org.tizen.dynamicanalyzer/lib/org.eclipse.cdt.dsf_2.2.0.201109151620.jar with 100% similarity]
org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.launch_7.0.0.201109151620.jar [new file with mode: 0644]
org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.scripting_1.0.0.201109151658.jar [new file with mode: 0644]
org.eclipse.cdt.debug.edc/lib/org.eclipse.tm.tcf.core_0.4.1.201109151255.jar [new file with mode: 0644]
org.eclipse.cdt.debug.edc/lib/truezip-6.jar [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IAddressExpressionEvaluator.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IEDCConstants.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IJumpToAddress.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IStreamBuffer.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/ITCFAgentLauncher.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/ITCFConnectionListener.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/ITCFServiceManager.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/JumpToAddress.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/MemoryUtils.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/MessageLogger.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/AbstractFormattedValuesRequestCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/AbstractRegisterRequestCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/AvailableFormatsRequestCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/BaseRangeCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/BaseRequestCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/FormatedExpressionValueRequestCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/GetRegistersRequestCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/ICacheEntry.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/MemoryRangeCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/RegisterGroupsRequestCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/RegistersByNameRequestCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/AbstractDisassembler.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/AssemblyFormatter.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/CodeBufferUnderflowException.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/DisassembledInstruction.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/EDCInstruction.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/EDCInstructionFunctionInfo.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/EDCMixedInstruction.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/IDisassembledInstruction.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/IDisassembler.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/AbstractCompositeFormatProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/AbstractStringFormatter.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/AbstractVariableConverter.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/DefaultArrayFormatter.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/DefaultCStringFormatter.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/DefaultCompositeFormatter.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/EDCFormatterMessages.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/EDCFormatterMessages.properties [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/FormatUtils.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/ITypeContentProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/IVariableFormatProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/IVariableValueConverter.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/ByteBufferStreamBuffer.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCApplication.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCDebugPreferenceInitializer.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCDebugger.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCTrace.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/ExecutablesSourceContainer.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/FileStreamBuffer.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/HostOS.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/IMemoryAccess.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/MemoryStreamBuffer.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/NumberFormatUtils.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/PathUtils.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/PersistentCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/StreamBufferBase.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/TCFServiceManager.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/WaitForResult.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/ZipFileUtils.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTEvalMessages.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTEvalMessages.properties [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTEvaluationEngine.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTInstructionCompiler.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/ArrayDimensionType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/ArraySubscript.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/BinaryLogicalOperator.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/BinaryOperator.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/CompoundInstruction.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/EvaluateID.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/FieldReference.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/GetValue.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/IArrayDimensionType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/IInvalidExpression.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/Instruction.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/InstructionSequence.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/Interpreter.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/NoOp.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperandValue.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorAddrOf.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBinaryAnd.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBinaryOr.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBinaryXor.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBitwiseNot.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorCast.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorCastValue.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorDivide.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorEquals.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorGreaterEqual.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorGreaterThan.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorIndirection.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLessEqual.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLessThan.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLogicalAnd.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLogicalNot.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLogicalOr.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorMinus.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorModulo.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorMultiply.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorNotEquals.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorPlus.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorShiftLeft.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorShiftRight.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorUnaryMinus.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorUnaryPlus.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushBoolean.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushChar.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushDouble.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushFloat.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushLongOrBigInteger.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushString.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/SimpleInstruction.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/UnaryLogicalOperator.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/UnaryOperator.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/VariableWithValue.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/formatter/FormatExtensionManager.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/formatter/IVariableFormatManager.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/formatter/IVariableFormatProviderChooser.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/CSourceLookup.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/ServicesLaunchSequence.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/ShutdownSequence.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/SnapshotLaunch.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/SnapshotLaunchDelegate.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/BreakpointAttributeTranslator.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Breakpoints.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/EDCServicesMessages.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/EDCServicesMessages.properties [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Expressions.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/INoop.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/LineEntryMapper.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Memory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/MemoryCache.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Modules.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Noop.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Processes.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/RunControl.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Signals.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Snapshots.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Symbols.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/Album.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/AlbumSourceContainer.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/AlbumSourceContainerType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/ISnapshotAlbumEventListener.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/Snapshot.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/SnapshotLaunchSequence.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/SnapshotUtils.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ArrayBoundType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ArrayType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CPPBasicType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ClassType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CompileUnitScope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CompositeType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ConstType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/EDCSourceFilesProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Enumeration.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Enumerator.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/FieldType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/FileLineEntryProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/FunctionScope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IAggregate.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IArrayBoundType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IArrayType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IBasicType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ICPPBasicType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ICompositeType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IConstType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IEnumeration.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IField.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IForwardTypeReference.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IInheritance.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ILexicalBlockScope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IMayBeQualifedType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IPointerType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IQualifierType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IReferenceType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IRuntimeSection.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ISection.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ISubroutineType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ITemplateParam.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ITypedef.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/InheritanceType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/InvalidVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/LexicalBlockScope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/LineEntry.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/MayBeQualifiedType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/MemoryVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ModuleLineEntryProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/PointerType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ReferenceType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/RegisterOffsetVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/RegisterVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/RuntimeSection.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Scope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Section.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/StructType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/SubroutineType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Symbol.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/SymbolsMessages.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/SymbolsMessages.properties [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/TemplateParamType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Type.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/TypedefType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/UnionType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ValueVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Variable.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/VolatileType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfCompileUnit.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfConstants.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfDebugInfoProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfDebugInfoProviderFactory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFileHelper.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFrameRegisterProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFrameRegisters.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFunctionScope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfInfoReader.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfMessages.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfMessages.properties [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfModuleScope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfVariable.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/EDCSymbolReader.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/LocationEntry.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/LocationExpression.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/LocationList.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/RangeList.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/BufferedRandomReadAccessFile.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/ERandomAccessFile.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/Elf.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/IRandomReadAccessFile.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/README.txt [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/BaseExecutableSymbolicsReader.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/DebugInfoProviderFactory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ElfExecutableSymbolicsReader.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ElfExecutableSymbolicsReaderFactory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ExecutableSection.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ExecutableSymbolicsReaderFactory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/FileStatistics.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ISectionMapper.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/PEFileExecutableSymbolicsReader.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/PEFileExecutableSymbolicsReaderFactory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/SectionInfo.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/SectionMapper.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglerEABI.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglerWin32.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglerWin32EABI.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglingException.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/AbstractFinalLaunchSequence.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/AgentSettings.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/ChooseProcessItem.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/DebugServicesFactory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/EDCLaunch.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/EDCLaunchDelegate.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/ICacheManager.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/IEDCLaunchConfigurationConstants.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/LaunchMessages.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/LaunchMessages.properties [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/LaunchUtils.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/AbstractEDCService.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/AbstractTargetEnvironment.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/DMContext.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Disassembly.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/EDCServicesTracker.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IDSFServiceUsingTCF.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCDMContext.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCExecutionDMC.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCExpression.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCExpressions.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCMemory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCModuleDMContext.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCModules.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCService.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCSymbols.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IFrameRegisterProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IFrameRegisters.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/ISnapshots.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/ITargetEnvironment.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Messages.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Registers.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Stack.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/messages.properties [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/snapshot/IAlbum.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/snapshot/ISnapshotContributor.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ICompileUnitScope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IDebugInfoProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IDebugInfoProviderFactory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IEDCSymbolReader.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IEnumerator.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IExecutableSection.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IExecutableSymbolicsReader.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IExecutableSymbolicsReaderFactory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IFunctionScope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IInvalidVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ILineEntry.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ILineEntryProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ILocationProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IMemoryVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IModuleLineEntryProvider.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IModuleScope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IRangeList.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IRegisterOffsetVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IRegisterVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IScope.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ISymbol.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ISymbolReaderFactory.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IType.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IUnmangler.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IValueVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IVariable.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IVariableLocation.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/SymbolsMessages.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/SymbolsMessages.properties [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/TypeEngine.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/TypeUtils.java [new file with mode: 0644]
org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/VariableLocationFactory.java [new file with mode: 0644]
org.tizen.dynamicanalyzer/.classpath
org.tizen.dynamicanalyzer/META-INF/MANIFEST.MF
org.tizen.dynamicanalyzer/lib/org.eclipse.cdt.core_5.3.1.201109151620.jar [deleted file]
org.tizen.dynamicanalyzer/lib/org.eclipse.cdt.debug.edc_2.0.0.201109151658.jar [deleted file]

diff --git a/org.eclipse.cdt.debug.edc/.classpath b/org.eclipse.cdt.debug.edc/.classpath
new file mode 100644 (file)
index 0000000..16f53cb
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="lib" path="lib/truezip-6.jar"/>
+       <classpathentry kind="lib" path="lib/org.eclipse.cdt.debug.core_7.1.0.201109151620.jar"/>
+       <classpathentry kind="lib" path="lib/org.eclipse.cdt.launch_7.0.0.201109151620.jar"/>
+       <classpathentry kind="lib" path="lib/org.eclipse.cdt.scripting_1.0.0.201109151658.jar"/>
+       <classpathentry kind="lib" path="lib/org.eclipse.cdt.debug.edc.tcf.extension_2.0.0.201109151658.jar"/>
+       <classpathentry kind="lib" path="lib/org.eclipse.tm.tcf.core_0.4.1.201109151255.jar"/>
+       <classpathentry kind="lib" path="lib/org.eclipse.cdt.dsf_2.2.0.201109151620.jar"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.cdt.debug.edc/.project b/org.eclipse.cdt.debug.edc/.project
new file mode 100644 (file)
index 0000000..3f52031
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.eclipse.cdt.debug.edc</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/org.eclipse.cdt.debug.edc/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.cdt.debug.edc/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..dc7828d
--- /dev/null
@@ -0,0 +1,8 @@
+#Fri Sep 19 19:14:41 KST 2014
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/org.eclipse.cdt.debug.edc/META-INF/MANIFEST.MF b/org.eclipse.cdt.debug.edc/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..8007ddc
--- /dev/null
@@ -0,0 +1,28 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Edc
+Bundle-SymbolicName: org.eclipse.cdt.debug.edc
+Bundle-Version: 1.0.0.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Require-Bundle: org.eclipse.core.jobs;bundle-version="3.5.100",
+ org.eclipse.equinox.common;bundle-version="3.6.0",
+ org.eclipse.core.resources;bundle-version="3.7.100",
+ org.eclipse.equinox.preferences;bundle-version="3.4.1",
+ org.eclipse.osgi;bundle-version="3.7.1",
+ org.eclipse.debug.core;bundle-version="3.7.0",
+ org.eclipse.core.runtime;bundle-version="3.7.0",
+ org.apache.commons.codec;bundle-version="1.3.0",
+ org.eclipse.core.variables;bundle-version="3.2.500",
+ org.eclipse.cdt.core;bundle-version="5.3.2"
+Export-Package: org.eclipse.cdt.debug.edc.internal.symbols,
+ org.eclipse.cdt.debug.edc.internal.symbols.dwarf,
+ org.eclipse.cdt.debug.edc.internal.symbols.files,
+ org.eclipse.cdt.debug.edc.symbols
+Bundle-ClassPath: .,
+ lib/org.eclipse.cdt.debug.core_7.1.0.201109151620.jar,
+ lib/org.eclipse.cdt.debug.edc.tcf.extension_2.0.0.201109151658.jar,
+ lib/org.eclipse.cdt.dsf_2.2.0.201109151620.jar,
+ lib/org.eclipse.cdt.launch_7.0.0.201109151620.jar,
+ lib/org.eclipse.cdt.scripting_1.0.0.201109151658.jar,
+ lib/org.eclipse.tm.tcf.core_0.4.1.201109151255.jar,
+ lib/truezip-6.jar
diff --git a/org.eclipse.cdt.debug.edc/build.properties b/org.eclipse.cdt.debug.edc/build.properties
new file mode 100644 (file)
index 0000000..c34e114
--- /dev/null
@@ -0,0 +1,11 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               lib/org.eclipse.cdt.debug.core_7.1.0.201109151620.jar,\
+               lib/org.eclipse.cdt.debug.edc.tcf.extension_2.0.0.201109151658.jar,\
+               lib/org.eclipse.cdt.dsf_2.2.0.201109151620.jar,\
+               lib/org.eclipse.cdt.launch_7.0.0.201109151620.jar,\
+               lib/org.eclipse.cdt.scripting_1.0.0.201109151658.jar,\
+               lib/org.eclipse.tm.tcf.core_0.4.1.201109151255.jar,\
+               lib/truezip-6.jar
diff --git a/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.debug.core_7.1.0.201109151620.jar b/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.debug.core_7.1.0.201109151620.jar
new file mode 100644 (file)
index 0000000..1d61b19
Binary files /dev/null and b/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.debug.core_7.1.0.201109151620.jar differ
diff --git a/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.debug.edc.tcf.extension_2.0.0.201109151658.jar b/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.debug.edc.tcf.extension_2.0.0.201109151658.jar
new file mode 100644 (file)
index 0000000..bd617f9
Binary files /dev/null and b/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.debug.edc.tcf.extension_2.0.0.201109151658.jar differ
diff --git a/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.launch_7.0.0.201109151620.jar b/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.launch_7.0.0.201109151620.jar
new file mode 100644 (file)
index 0000000..f38eecd
Binary files /dev/null and b/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.launch_7.0.0.201109151620.jar differ
diff --git a/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.scripting_1.0.0.201109151658.jar b/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.scripting_1.0.0.201109151658.jar
new file mode 100644 (file)
index 0000000..78184d4
Binary files /dev/null and b/org.eclipse.cdt.debug.edc/lib/org.eclipse.cdt.scripting_1.0.0.201109151658.jar differ
diff --git a/org.eclipse.cdt.debug.edc/lib/org.eclipse.tm.tcf.core_0.4.1.201109151255.jar b/org.eclipse.cdt.debug.edc/lib/org.eclipse.tm.tcf.core_0.4.1.201109151255.jar
new file mode 100644 (file)
index 0000000..4893279
Binary files /dev/null and b/org.eclipse.cdt.debug.edc/lib/org.eclipse.tm.tcf.core_0.4.1.201109151255.jar differ
diff --git a/org.eclipse.cdt.debug.edc/lib/truezip-6.jar b/org.eclipse.cdt.debug.edc/lib/truezip-6.jar
new file mode 100644 (file)
index 0000000..92a8968
Binary files /dev/null and b/org.eclipse.cdt.debug.edc/lib/truezip-6.jar differ
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IAddressExpressionEvaluator.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IAddressExpressionEvaluator.java
new file mode 100644 (file)
index 0000000..9d57203
--- /dev/null
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Expression evaluator that computes jump-to address for a control-change
+ * instruction such as jump and call instruction. To evaluate an address
+ * expression, accessing registers and/or memory is required. And DSF services
+ * are invoked for those access.<br>
+ * <br>
+ * As the address expression is usually produced by disassembler, this evaluator
+ * implementation should stay in sync with corresponding disassembler
+ * implementation.
+ */
+public interface IAddressExpressionEvaluator {
+
+       /**
+        * Evaluate a expression synchronously.<br>
+        * <br>
+        * This method should be called only when control is at the instruction. As
+        * DSF services will be called, this method should also be called in DSF
+        * dispatch thread.
+        * 
+        * @param context
+        *            Execution DMC.
+        * @param expression
+        *            the address expression from a control-change instruction. This
+        *            expression is usually produced by disassembler.
+        * @param regService
+        *            EDC version of DSF IRegisters service for register access.
+        * @param memService
+        *            EDC version of DSF IMemory service for memory access.
+        * @return address computed.
+        * @throws CoreException
+        *             on any error.
+        */
+       IAddress evaluate(IExecutionDMContext context, String expression, IRegisters regService, IMemory memService)
+                       throws CoreException;
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IEDCConstants.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IEDCConstants.java
new file mode 100644 (file)
index 0000000..c4a0709
--- /dev/null
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc;
+
+public interface IEDCConstants {
+
+       /**
+        * This is the TCF peer attribute used to differentiate between available
+        * TCF peers distributed with stock CDT (e.g., windows, linux-x86).
+        */
+       final static String PEER_ATTR_DEBUG_SUPPORT = "DebugSupport";
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IJumpToAddress.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IJumpToAddress.java
new file mode 100644 (file)
index 0000000..1d3b4b9
--- /dev/null
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc;
+
+public interface IJumpToAddress {
+
+       /**
+        * Whether this address is the sole destination address after executing the
+        * current instruction. E.g. it's true for unconditional jump and subroutine
+        * call, but false for condition jump.
+        * 
+        * @return
+        */
+       public boolean isSoleDestination();
+
+       /**
+        * Whether the jump-to address is a subroutine address (namely whether the
+        * current instruction is a subroutine call instruction.
+        * 
+        * @return
+        */
+       public boolean isSubroutineAddress();
+
+       /**
+        * Is the address an immediate value (no calculation is needed) ?
+        * 
+        * @return
+        */
+       public boolean isImmediate();
+
+       /**
+        * Get the address.
+        * 
+        * @return IAddress object for immediate address, or an expression string
+        *         indicating how to calculate the actual address.
+        */
+       public Object getValue();
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IStreamBuffer.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/IStreamBuffer.java
new file mode 100644 (file)
index 0000000..b2ffc2f
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc;
+
+import java.nio.Buffer;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+
+/**
+ * This is an subset of the ByteBuffer interface used for read-only 
+ * scanning of a buffer.  Its implementation is optimized for streaming access
+ * (i.e. not random access) and for making cheap sub-buffers.
+ */
+public interface IStreamBuffer {
+       /**
+        * @see ByteBuffer#capacity()
+        */
+       public long capacity();
+
+       /**
+        * @see ByteBuffer#hasRemaining()
+        */
+       public boolean hasRemaining();
+
+       /**
+        * @see Buffer#remaining()
+        */
+       public long remaining();
+       
+    /**
+     * @see Buffer#position()
+     */
+    public long position();
+
+    /**
+     * @see Buffer#position(int)
+     */
+    public IStreamBuffer position(long newPosition);
+    /**
+     * Skip ahead in the buffer.
+     *
+     * @param amount the number of bytes to skip ahead
+     * @return this buffer
+     * @since 2.0
+     */
+    public IStreamBuffer skip(long amount);
+
+        /**
+         * @see ByteBuffer#get()
+         * @throws BufferUnderflowException
+     */
+    public abstract byte get();
+    
+    /**
+     * @see ByteBuffer#get(byte[], int, int)
+     * @throws BufferUnderflowException
+     */
+    public IStreamBuffer get(byte[] dst, int offset, int length);
+
+    /**
+     * @see ByteBuffer#get(byte[])
+     * @throws BufferUnderflowException
+     */
+    public IStreamBuffer get(byte[] dst);
+
+    /**
+     * @see ByteBuffer#getChar()
+     * @throws BufferUnderflowException
+     */
+    public abstract char getChar();
+    
+    /**
+     * @see ByteBuffer#getShort()
+     * @throws BufferUnderflowException
+     */
+    public abstract short getShort();
+    
+
+    /**
+     * @see ByteBuffer#getInt()
+     * @throws BufferUnderflowException
+     */
+    public abstract int getInt();
+
+    /**
+     * @see ByteBuffer#getLong()
+     * @throws BufferUnderflowException
+     */
+    public abstract long getLong();
+
+    /**
+     * Wrap a portion of the buffer.  This is a cheap operation whose
+     * returned buffer maintains references to the receiver but has an
+     * independent position.
+     * @param size the size to wrap, starting from the current {@link #position()}
+     */
+    IStreamBuffer wrapSubsection(long size);
+
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/ITCFAgentLauncher.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/ITCFAgentLauncher.java
new file mode 100644 (file)
index 0000000..0c18669
--- /dev/null
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc;
+
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.tm.tcf.protocol.IPeer;
+
+/**
+ * An implementation of this interface is provided by a tcgAgentLauncher
+ * extension. It's a way to advertise a TCF agent that may not yet be running
+ * and to provide a means to programatically launch it (or at least put up some
+ * GUI that informs the user how to manually launch it, in the case of an agent
+ * hosted remotely). Agents can advertise themselves once they are running via
+ * TCF UDP Discovery, but we need a way for a debugger to discover and launch
+ * agents that are not yet running. This interface assumes the agent hosts a
+ * single peer. An agent that hosts multiple peers can be described using
+ * multiple launchers with common launch logic.
+ */
+public interface ITCFAgentLauncher {
+
+       /**
+        * Gets the user friendly name of the peer this agent hosts. Same as calling
+        * getAttributes().get(IPeer#ATTR_NAME)
+        * 
+        * @return the name of the peer
+        */
+       String getPeerName();
+
+       /**
+        * Get the names of the services the peer implements.
+        * 
+        * @return list of service names, may be empty
+        */
+       List<String> getServiceNames();
+
+       /**
+        * Get the attributes of the peer this agent hosts.
+        * 
+        * @return the peer's attributes; at least the {@link IPeer#ATTR_NAME} will
+        *         be present
+        */
+       Map<String, String> getPeerAttributes();
+
+       /**
+        * Tell whether the agent can be launched.  This is mainly used to
+        * avoid considering the launcher for situations where it will never
+        * work (e.g., wrong OS host).  {@link #launch()} can, of course,
+        * fail for other reasons.
+        * @return true if launching is possible.
+        */
+       boolean isLaunchable();
+       
+       /**
+        * Launches the agent, if it's not already running
+        * 
+        * @throws Exception
+        *             on any error.
+        */
+       void launch() throws Exception;
+       
+       
+       /**
+        * Shuts down the agent if it was launched
+        * 
+        * @throws Exception
+        *                              on any error
+        */
+       void shutdown() throws Exception;
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/ITCFConnectionListener.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/ITCFConnectionListener.java
new file mode 100644 (file)
index 0000000..3747971
--- /dev/null
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc;
+
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IPeer;
+
+/**
+ * This listener on {@link ITCFServiceManager} allows a client to track the
+ * state of peers and channels managed by EDC.
+ * @since 2.0
+ */
+public interface ITCFConnectionListener {
+
+       /** 
+        * Called when ITCFServiceManager opens a channel on a peer.
+        * This is called on the TCF dispatch thread. 
+        * */
+       void peerChannelOpened(IPeer peer, IChannel channel);
+       
+       /** 
+        * Called when a channel was closed for a peer.
+        * This is called on the TCF dispatch thread. 
+        */
+       void peerChannelClosed(IPeer peer, IChannel channel, Throwable error);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/ITCFServiceManager.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/ITCFServiceManager.java
new file mode 100644 (file)
index 0000000..1bde259
--- /dev/null
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IPeer;
+
+/**
+ * This interface provides access to TCF services. It abstracts out the details
+ * of which agent provides the services, launching the agent if necessary, etc.
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITCFServiceManager {
+
+       /**
+        * Gets the channel used to talk to a peer. If no channel is open yet it
+        * will return null.
+        * 
+        * @param peer
+        *            the peer
+        * @return the channel used to communicate to the specified peer
+        */
+
+       public IChannel getChannelForPeer(IPeer peer);
+       
+       /**
+        * Find an open channel or create a new one and return it.  This blocks,
+        * and should not be called from the TCF dispatch thread.
+        * @param peer the peer
+        * @return the channel used to communicate to the specified peer, in open state
+        * @since 2.0
+        */
+       public IChannel findOrCreateChannelForPeer(IPeer peer) throws CoreException;
+       
+       /** 
+        * Add a listener. Duplicate listeners are ignored. 
+        * @param listener 
+        * @since 2.0 
+        */
+       public void addConnectionListener(ITCFConnectionListener listener);
+       /** 
+        * Remove a listener. Nonexistent listeners are ignored.
+        * @param listener 
+        * @since 2.0 
+        */
+       public void removeConnectionListener(ITCFConnectionListener listener);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/JumpToAddress.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/JumpToAddress.java
new file mode 100644 (file)
index 0000000..0fe6766
--- /dev/null
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.utils.Addr64;
+
+/**
+ * Representing the address to which control-change instruction (e.g. a jump
+ * instruction or subroutine call instruction) may jump to. <br>
+ * Contrast to: the address of the instruction right after this instruction in
+ * memory.<br>
+ * <br>
+ * Object of such class is supposed to be produced by disassembler and consumed
+ * by debugger for tasks such as stepping and stack crawling.<br>
+ * <br>
+ * For some jump or call instructions, the jump-to-address is an absolute
+ * immediate address encoded in the instruction, while for some instructions it
+ * is an indirect address whose value has to be computed by reading certain
+ * registers or memory when control is at the instruction. The computation
+ * detail is target processor dependent.
+ */
+public class JumpToAddress implements IJumpToAddress {
+       public static final String EXPRESSION_RETURN_NEAR = "ret-near";
+       public static final String EXPRESSION_RETURN_FAR = "ret-far";
+       /**
+        * @since 2.0
+        */
+       public static final String EXPRESSION_LR = "lr";
+
+       private final IAddress address;
+       private final String expression;
+       private final boolean isSoleDestination;
+       private final boolean isSubroutineAddress;
+
+       public JumpToAddress(IAddress address, boolean isSoleDestination, boolean isSubroutineAddress) {
+               this.address = address;
+               this.expression = null;
+               this.isSoleDestination = isSoleDestination;
+               this.isSubroutineAddress = isSubroutineAddress;
+       }
+
+       public JumpToAddress(long address, boolean isSoleDestination, boolean isSubroutineAddress) {
+               this(new Addr64(Long.toString(address)), isSoleDestination, isSubroutineAddress);
+       }
+
+       public JumpToAddress(String expression, boolean isSoleDestination, boolean isSubroutineAddress) {
+               this.address = null;
+               this.expression = expression;
+               this.isSoleDestination = isSoleDestination;
+               this.isSubroutineAddress = isSubroutineAddress;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IJumpToAddress#isSoleDestination()
+        */
+       public boolean isSoleDestination() {
+               return isSoleDestination;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IJumpToAddress#isSubroutineAddress()
+        */
+       public boolean isSubroutineAddress() {
+               return isSubroutineAddress;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IJumpToAddress#isImmediate()
+        */
+       public boolean isImmediate() {
+               return address != null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IJumpToAddress#getValue()
+        */
+       public Object getValue() {
+               if (address != null)
+                       return address;
+               else {
+                       assert expression != null;
+                       return expression;
+               }
+       }
+
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 1;
+               result = prime * result + ((address == null) ? 0 : address.hashCode());
+               result = prime * result + ((expression == null) ? 0 : expression.hashCode());
+               result = prime * result + (isSoleDestination ? 1231 : 1237);
+               result = prime * result + (isSubroutineAddress ? 1231 : 1237);
+               return result;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               JumpToAddress other = (JumpToAddress) obj;
+               if (address == null) {
+                       if (other.address != null)
+                               return false;
+               } else if (!address.equals(other.address))
+                       return false;
+               if (expression == null) {
+                       if (other.expression != null)
+                               return false;
+               } else if (!expression.equals(other.expression))
+                       return false;
+               if (isSoleDestination != other.isSoleDestination)
+                       return false;
+               if (isSubroutineAddress != other.isSubroutineAddress)
+                       return false;
+               return true;
+       }
+
+       @Override
+       public String toString() {
+               return "JumpToAddress [address="
+                        + ((address != null) ? address.toHexAddressString() : "null")
+                        + ", expression=" + expression
+                        + ", isSoleDestination=" + isSoleDestination
+                        + ", isSubroutineAddress=" + isSubroutineAddress + "]";
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/MemoryUtils.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/MemoryUtils.java
new file mode 100644 (file)
index 0000000..28ee2e5
--- /dev/null
@@ -0,0 +1,710 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.symbols.IBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.symbols.IEnumerator;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.MemoryByte;
+
+public class MemoryUtils {
+
+       public static final int LITTLE_ENDIAN = 0;
+       public static final int BIG_ENDIAN = 1;
+       public static final int ENDIANESS_UNKNOWN = 2;
+
+       /**
+        * Pad byte array with 0's or 1's when the byte array's length is shorter
+        * than what's expected by the conversion functions.
+        * 
+        * @param array
+        * @param size
+        * @param endianess
+        * @param isSigned
+        * @return an array of bytes
+        */
+       protected static byte[] fillArray(byte[] array, int size, int endianess, boolean isSigned) {
+
+               byte[] temp = new byte[size];
+
+               // either 0 fill or sign extend
+               byte fillByte = 0;
+               if (isSigned && ((array[array.length - 1] & 0x80) != 0))
+                       fillByte = (byte) 0xff;
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+
+                       for (int i = 0; i < array.length; i++) {
+                               temp[i] = array[i];
+                       }
+
+                       // fill up the rest of the array
+                       for (int i = array.length; i < size; i++) {
+                               temp[i] = fillByte;
+                       }
+
+                       array = temp;
+                       return array;
+               }
+
+               for (int i = 0; i < size - array.length; i++) {
+                       temp[i] = fillByte;
+               }
+
+               int j = 0;
+               // fill up the rest of the array
+               for (int i = size - array.length; i < size; i++) {
+                       temp[i] = array[j];
+                       j++;
+               }
+
+               array = temp;
+               return array;
+       }
+
+       /**
+        * Convert byte array to unsigned long.
+        * 
+        * @param data
+        * @param endianess
+        * @return result of the conversion in long
+        */
+       static public BigInteger convertByteArrayToUnsignedLong(MemoryByte[] data, int endianess) {
+               byte[] array = new byte[data.length];
+               for (int i = 0; i < array.length; i++) {
+                       array[i] = data[i].getValue();
+               }
+
+               if (array.length < 8) {
+                       array = fillArray(array, 8, endianess, false);
+               }
+
+               BigInteger value = new BigInteger("0"); //$NON-NLS-1$
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       for (int i = 0; i < 8; i++) {
+                               byte[] temp = new byte[1];
+                               temp[0] = array[i];
+                               BigInteger b = new BigInteger(temp);
+                               b = b.and(new BigInteger("ff", 16)); //$NON-NLS-1$
+                               b = b.shiftLeft(i * 8);
+                               value = value.or(b);
+                       }
+               } else {
+                       for (int i = 0; i < 8; i++) {
+                               byte[] temp = new byte[1];
+                               temp[0] = array[i];
+                               BigInteger b = new BigInteger(temp);
+                               b = b.and(new BigInteger("ff", 16)); //$NON-NLS-1$
+                               b = b.shiftLeft((7 - i) * 8);
+                               value = value.or(b);
+                       }
+               }
+               return value;
+       }
+
+       /**
+        * Convert byte array to signed long.
+        * 
+        * @param data
+        * @param endianess
+        * @return result of the conversion in long
+        */
+       static public long convertByteArrayToLong(MemoryByte[] data, int endianess) {
+               byte[] array = new byte[data.length];
+               for (int i = 0; i < array.length; i++) {
+                       array[i] = data[i].getValue();
+               }
+
+               if (array.length < 8) {
+                       array = fillArray(array, 8, endianess, true);
+               }
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       long value = 0;
+                       for (int i = 0; i < 8; i++) {
+                               long b = array[i];
+                               b &= 0xff;
+                               value |= (b << (i * 8));
+                       }
+                       return value;
+               }
+               long value = 0;
+               for (int i = 0; i < 8; i++) {
+                       long b = array[i];
+                       b &= 0xff;
+                       value |= (b << ((7 - i) * 8));
+               }
+
+               return value;
+       }
+
+       static public BigInteger convertByteArrayToSignedBigInt(byte[] array, int endianess) {
+               if (array.length < 16) {
+                       array = fillArray(array, 16, endianess, false);
+               }
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       // reverse bytes
+                       byte[] holder = new byte[16];
+                       int j = 15;
+                       for (int i = 0; i < 16; i++, j--) {
+                               holder[i] = array[j];
+                       }
+
+                       // create BigInteger
+                       BigInteger value = new BigInteger(holder);
+                       return value;
+               }
+               BigInteger value = new BigInteger(array);
+               return value;
+       }
+
+       static public BigInteger convertByteArrayToSignedBigInt(byte[] array, int endianess, int arraySize) {
+               if (array.length < arraySize) {
+                       array = fillArray(array, arraySize, endianess, true);
+               }
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       // reverse bytes
+                       byte[] holder = new byte[arraySize];
+                       int j = arraySize - 1;
+                       for (int i = 0; i < arraySize; i++, j--) {
+                               holder[i] = array[j];
+                       }
+
+                       // create BigInteger
+                       BigInteger value = new BigInteger(holder);
+                       return value;
+               }
+               BigInteger value = new BigInteger(array);
+               return value;
+       }
+
+       static public BigInteger convertByteArrayToUnsignedBigInt(byte[] array, int endianess) {
+               if (array.length < 16) {
+                       array = fillArray(array, 16, endianess, false);
+               }
+
+               BigInteger value = new BigInteger("0"); //$NON-NLS-1$
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       for (int i = 0; i < 16; i++) {
+                               byte[] temp = new byte[1];
+                               temp[0] = array[i];
+                               BigInteger b = new BigInteger(temp);
+                               b = b.and(new BigInteger("ff", 16)); //$NON-NLS-1$
+                               b = b.shiftLeft(i * 8);
+                               value = value.or(b);
+                       }
+               } else {
+                       for (int i = 0; i < 16; i++) {
+                               byte[] temp = new byte[1];
+                               temp[0] = array[i];
+                               BigInteger b = new BigInteger(temp);
+                               b = b.and(new BigInteger("ff", 16)); //$NON-NLS-1$
+                               b = b.shiftLeft((15 - i) * 8);
+                               value = value.or(b);
+                       }
+               }
+               return value;
+       }
+
+       static public BigInteger convertByteArrayToUnsignedBigInt(byte[] array, int endianess, int arraySize) {
+               if (array.length < arraySize) {
+                       array = fillArray(array, arraySize, endianess, false);
+               }
+
+               BigInteger value = new BigInteger("0"); //$NON-NLS-1$
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       for (int i = 0; i < arraySize; i++) {
+                               byte[] temp = new byte[1];
+                               temp[0] = array[i];
+                               BigInteger b = new BigInteger(temp);
+                               b = b.and(new BigInteger("ff", 16)); //$NON-NLS-1$
+                               b = b.shiftLeft(i * 8);
+                               value = value.or(b);
+                       }
+               } else {
+                       for (int i = 0; i < arraySize; i++) {
+                               byte[] temp = new byte[1];
+                               temp[0] = array[i];
+                               BigInteger b = new BigInteger(temp);
+                               b = b.and(new BigInteger("ff", 16)); //$NON-NLS-1$
+                               b = b.shiftLeft((arraySize - 1 - i) * 8);
+                               value = value.or(b);
+                       }
+               }
+               return value;
+       }
+
+       /**
+        * Convert byte array to integer.
+        * 
+        * @param array
+        * @param endianess
+        * @return result of the conversion in int
+        */
+       static public int convertByteArrayToInt(MemoryByte[] data, int endianess) {
+               byte[] array = new byte[data.length];
+               for (int i = 0; i < array.length; i++) {
+                       array[i] = data[i].getValue();
+               }
+
+               if (array.length < 4) {
+                       array = fillArray(array, 4, endianess, true);
+               }
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       int value = 0;
+                       for (int i = 0; i < 4; i++) {
+                               int b = array[i];
+                               b &= 0xff;
+                               value |= (b << (i * 8));
+                       }
+                       return value;
+               }
+               int value = 0;
+               for (int i = 0; i < 4; i++) {
+                       int b = array[i];
+                       b &= 0xff;
+                       value |= (b << ((3 - i) * 8));
+               }
+
+               return value;
+       }
+
+       /**
+        * Convert byte array to short.
+        * 
+        * @param array
+        * @param endianess
+        * @return result of teh conversion in short
+        */
+       static public short convertByteArrayToShort(MemoryByte[] data, int endianess) {
+               byte[] array = new byte[data.length];
+               for (int i = 0; i < array.length; i++) {
+                       array[i] = data[i].getValue();
+               }
+               if (array.length < 2) {
+                       array = fillArray(array, 2, endianess, true);
+               }
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       short value = 0;
+                       for (int i = 0; i < 2; i++) {
+                               short b = array[i];
+                               b &= 0xff;
+                               value |= (b << (i * 8));
+                       }
+                       return value;
+               }
+               short value = 0;
+               for (int i = 0; i < 2; i++) {
+                       short b = array[i];
+                       b &= 0xff;
+                       value |= (b << ((1 - i) * 8));
+               }
+               return value;
+       }
+
+       /**
+        * Convert big integer to byte array.
+        * 
+        * @param i
+        * @param endianess
+        * @return result of the conversion in raw byte array
+        */
+       static public byte[] convertBigIntegerToByteArray(BigInteger i, int endianess) {
+               byte buf[] = new byte[16];
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       for (int j = 0; j < 16; j++) {
+                               BigInteger x = i.shiftRight(j * 8);
+                               buf[j] = x.byteValue();
+                       }
+                       return buf;
+               }
+               for (int j = 15; j >= 0; j--) {
+                       BigInteger x = i.shiftRight((15 - j) * 8);
+                       buf[j] = x.byteValue();
+               }
+               return buf;
+       }
+
+       static public byte[] convertSignedBigIntToByteArray(BigInteger i, int endianess, int arraySize) {
+               byte buf[] = new byte[arraySize];
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       for (int j = 0; j < arraySize; j++) {
+                               BigInteger x = i.shiftRight(j * 8);
+                               buf[j] = x.byteValue();
+                       }
+                       return buf;
+               }
+               for (int j = arraySize - 1; j >= 0; j--) {
+                       BigInteger x = i.shiftRight((arraySize - 1 - j) * 8);
+                       buf[j] = x.byteValue();
+               }
+               return buf;
+       }
+
+       /**
+        * Convert big integer to byte array.
+        * 
+        * @param i
+        * @param endianess
+        * @return result of the conversion in raw byte array
+        */
+       static public byte[] convertUnsignedBigIntegerToByteArray(BigInteger i, int endianess) {
+               byte buf[] = new byte[32];
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       for (int j = 0; j < 32; j++) {
+                               BigInteger x = i.shiftRight(j * 8);
+                               buf[j] = x.byteValue();
+                       }
+                       return buf;
+               }
+               for (int j = 31; j >= 0; j--) {
+                       BigInteger x = i.shiftRight((31 - j) * 8);
+                       buf[j] = x.byteValue();
+               }
+               return buf;
+       }
+
+       static public byte[] convertUnsignedBigIntToByteArray(BigInteger i, int endianess, int arraySize) {
+               byte buf[] = new byte[arraySize * 2];
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       for (int j = 0; j < arraySize * 2; j++) {
+                               BigInteger x = i.shiftRight(j * 8);
+                               buf[j] = x.byteValue();
+                       }
+                       return buf;
+               }
+               for (int j = (arraySize * 2) - 1; j >= 0; j--) {
+                       BigInteger x = i.shiftRight(((arraySize * 2) - 1 - j) * 8);
+                       buf[j] = x.byteValue();
+               }
+               return buf;
+       }
+
+       /**
+        * Convert long to byte array.
+        * 
+        * @param i
+        * @param endianess
+        * @return result of the conversion in raw byte array
+        */
+       static public byte[] convertLongToByteArray(long i, int endianess) {
+               byte buf[] = new byte[8];
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       for (int j = 0; j < 8; j++) {
+                               buf[j] = new Long(i >> j * 8).byteValue();
+                       }
+                       return buf;
+               }
+               for (int j = 7; j >= 0; j--) {
+                       buf[j] = new Long(i >> (7 - j) * 8).byteValue();
+               }
+               return buf;
+       }
+
+       /**
+        * Convert integer to byte array.
+        * 
+        * @param i
+        * @param endianess
+        * @return result of the conversion in raw byte array
+        */
+       static public byte[] convertIntToByteArray(int i, int endianess) {
+               byte buf[] = new byte[4];
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       for (int j = 0; j < 4; j++) {
+                               buf[j] = new Integer(i >> j * 8).byteValue();
+                       }
+                       return buf;
+               }
+               for (int j = 3; j >= 0; j--) {
+                       buf[j] = new Integer(i >> (3 - j) * 8).byteValue();
+               }
+               return buf;
+       }
+
+       /**
+        * Convert short to byte array.
+        * 
+        * @param i
+        * @param endianess
+        * @return result of the conversion in raw byte array
+        */
+       static public byte[] convertShortToByteArray(short i, int endianess) {
+               byte buf[] = new byte[2];
+
+               if (endianess == MemoryUtils.LITTLE_ENDIAN) {
+                       for (short j = 0; j < 2; j++) {
+                               buf[j] = new Integer(i >> j * 8).byteValue();
+                       }
+                       return buf;
+               }
+               for (short j = 1; j >= 0; j--) {
+                       buf[j] = new Integer(i >> (1 - j) * 8).byteValue();
+               }
+               return buf;
+       }
+
+       /**
+        * byte array to Hex string helper replaces the Integer.toHexString() which
+        * can't convert byte values properly (always pads with FFFFFF)
+        */
+       static public String convertByteArrayToHexString(byte[] byteArray) {
+               StringBuffer strBuffer = new StringBuffer();
+               char charArray[];
+
+               for (byte element : byteArray) {
+                       charArray = MemoryUtils.convertByteToCharArray(element);
+                       strBuffer.append(charArray);
+               }
+
+               return strBuffer.toString();
+       }
+
+       static public char[] convertByteToCharArray(byte aByte) {
+               char charArray[] = new char[2];
+               int val = aByte;
+               if (val < 0)
+                       val += 256;
+               charArray[0] = Character.forDigit(val / 16, 16);
+               charArray[1] = Character.forDigit(val % 16, 16);
+
+               return charArray;
+       }
+
+       /**
+        * Convert raw memory data to byte array
+        * 
+        * @param str
+        * @param numBytes
+        * @param numCharsPerByte
+        *            - number of characters per byte of data
+        * @return an array of byte, converted from a hex string
+        * @throws NumberFormatException
+        */
+       public static byte[] convertHexStringToByteArray(String str, int numBytes, int numCharsPerByte)
+                       throws NumberFormatException {
+               if (str.length() == 0)
+                       return null;
+
+               StringBuffer buf = new StringBuffer(str);
+
+               // pad string with zeros
+               int requiredPadding = numBytes * numCharsPerByte - str.length();
+               while (requiredPadding > 0) {
+                       buf.insert(0, "0"); //$NON-NLS-1$
+                       requiredPadding--;
+               }
+
+               byte[] bytes = new byte[numBytes];
+               str = buf.toString();
+
+               // set data in memory
+               for (int i = 0; i < bytes.length; i++) {
+                       // convert string to byte
+                       String oneByte = str.substring(i * 2, i * 2 + 2);
+
+                       Integer number = Integer.valueOf(oneByte, 16);
+                       if (number.compareTo(Integer.valueOf(Byte.toString(Byte.MAX_VALUE))) > 0) {
+                               int temp = number.intValue();
+                               temp = temp - 256;
+
+                               String tempStr = Integer.toString(temp);
+
+                               Byte myByte = Byte.valueOf(tempStr);
+                               bytes[i] = myByte.byteValue();
+                       } else {
+                               Byte myByte = Byte.valueOf(oneByte, 16);
+                               bytes[i] = myByte.byteValue();
+                       }
+               }
+
+               return bytes;
+       }
+
+       public static String convertMemoryBytesToHexString(MemoryByte[] bytes) {
+               StringBuffer strBuffer = new StringBuffer();
+               char charArray[];
+
+               for (MemoryByte b : bytes) {
+                       charArray = MemoryUtils.convertByteToCharArray(b.getValue());
+                       strBuffer.append(charArray);
+               }
+
+               return strBuffer.toString();
+       }
+
+       /**
+        * Convert raw memory data to byte array
+        * 
+        * @param str
+        * @param numBytes
+        * @param numCharsPerByte
+        *            - number of characters per byte of data
+        * @return an array of byte, converted from a hex string
+        * @throws NumberFormatException
+        */
+       public static MemoryByte[] convertHexStringToMemoryBytes(String str, int numBytes, int numCharsPerByte)
+                       throws NumberFormatException {
+               if (str.length() == 0)
+                       return null;
+
+               StringBuffer buf = new StringBuffer(str);
+
+               // pad string with zeros
+               int requiredPadding = numBytes * numCharsPerByte - str.length();
+               while (requiredPadding > 0) {
+                       buf.insert(0, "0"); //$NON-NLS-1$
+                       requiredPadding--;
+               }
+
+               MemoryByte[] bytes = new MemoryByte[numBytes];
+               str = buf.toString();
+
+               // set data in memory
+               for (int i = 0; i < bytes.length; i++) {
+                       // convert string to byte
+                       String oneByte = str.substring(i * 2, i * 2 + 2);
+
+                       Integer number = Integer.valueOf(oneByte, 16);
+                       if (number.compareTo(Integer.valueOf(Byte.toString(Byte.MAX_VALUE))) > 0) {
+                               int temp = number.intValue();
+                               temp = temp - 256;
+
+                               String tempStr = Integer.toString(temp);
+
+                               Byte myByte = Byte.valueOf(tempStr);
+                               bytes[i] = new MemoryByte(myByte.byteValue());
+                       } else {
+                               Byte myByte = Byte.valueOf(oneByte, 16);
+                               bytes[i] = new MemoryByte(myByte.byteValue());
+                       }
+               }
+
+               return bytes;
+       }
+       
+       public static class TypeCharacteristics {
+               public int basicType = IBasicType.t_unspecified;
+               public boolean isSigned = false;
+               public boolean isShort = false;
+               public boolean isLong = false;
+               public boolean isLongLong = false;
+               public boolean isComplex = false;
+               
+               public TypeCharacteristics(IType varType) {
+                       if (varType instanceof IBasicType) {
+                               IBasicType type = (IBasicType) varType;
+                               basicType = type.getBaseType();
+                               isSigned = type.isSigned();
+                               isShort = type.isShort();
+                               isLong = type.isLong();
+                               
+                               if (varType instanceof ICPPBasicType) {
+                                       ICPPBasicType cppType = (ICPPBasicType) varType;
+                                       isLongLong = cppType.isLongLong();
+                                       isComplex  = cppType.isComplex();
+                               }
+                       } else if (varType instanceof IPointerType) {
+                               // treat pointer as an unsigned int
+                               basicType = IBasicType.t_int;
+                       } else if (varType instanceof IEnumerator){
+                               // treat enumerator as a signed int
+                               basicType = IBasicType.t_int;
+                               isSigned = true;
+                       } else {
+                               // treat unknown type as an unsigned int
+                               basicType = IBasicType.t_int;
+                       }
+               }
+       }
+
+       public static BigInteger convertValueToMemory(IType varType, Number value) throws CoreException {
+               BigInteger result = null;
+               if (varType == null)
+                       throw EDCDebugger.newCoreException("Unknown type");
+               int varSize = varType.getByteSize();
+               if (varSize <= 0)
+                       throw EDCDebugger.newCoreException("Type has no size");
+                       
+               TypeCharacteristics characteristics = new TypeCharacteristics(varType);
+       
+               // all other locations
+               switch (characteristics.basicType) {
+               case IBasicType.t_float:
+               case IBasicType.t_double:
+                       if (varSize == 4) {
+                               result = BigInteger.valueOf(Float.floatToIntBits(value.floatValue()));
+                       } else if (varSize == 8) {
+                               result = BigInteger.valueOf(Double.doubleToLongBits(value.doubleValue()));
+                       }
+                       break;
+       
+               case ICPPBasicType.t_bool:
+               case ICPPBasicType.t_wchar_t:
+               case IBasicType.t_char:
+               case IBasicType.t_int:
+               case IBasicType.t_void:
+                       if (characteristics.isSigned) {
+                               // as needed, mask the value and sign-extend
+                               if (varSize == 4) {
+                                       result = BigInteger.valueOf(value.intValue());
+                               } else if (varSize == 2) {
+                                       int intResult = value.intValue() & 0xffff;
+                                       if ((intResult & 0x00008000) != 0)
+                                               intResult |= 0xffff0000;
+                                       result = BigInteger.valueOf(intResult);
+                               } else if (varSize == 1) {
+                                       int intResult = value.intValue() & 0xff;
+                                       if ((intResult & 0x00000080) != 0)
+                                               intResult |= 0xffffff00;
+                                       result = BigInteger.valueOf(intResult);
+                               } else {
+                                       // assume an 8-byte long is the default
+                                       result = BigInteger.valueOf(value.longValue());
+                               }
+                       } else {
+                               if (varSize == 4) {
+                                       result = BigInteger.valueOf(value.longValue() & 0xffffffffL);  // keep it unsigned
+                               } else if (varSize == 2) {
+                                       result = BigInteger.valueOf(value.intValue() & 0xffff);
+                               } else if (varSize == 1) {
+                                       result = BigInteger.valueOf(value.intValue() & 0xff);
+                               } else {
+                                       // assume an 8-byte long is the default
+                                       result = BigInteger.valueOf(value.longValue());
+                               }
+                       }
+                       break;
+       
+               case IBasicType.t_unspecified:
+               default:
+                       assert false;
+                       throw EDCDebugger.newCoreException("Unhandled type");
+               }
+               return result;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/MessageLogger.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/MessageLogger.java
new file mode 100644 (file)
index 0000000..5440abd
--- /dev/null
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * This class performs error logging. The error can be logged, shown or both. It
+ * is important to log errors to clearly identify the plug-in as the source of
+ * problems.
+ * <p>
+ * The goals of the logging and the showing are different:
+ * <p>
+ * A logged message should retain enough information so it's not useless, while
+ * not having empty top-level messages or unnecessary levels of nesting.
+ * <p>
+ * A reported message, which is meant to be more user-friendly, does not show a
+ * stack trace or exception names, so it should not expose the StatusDialog's
+ * weaknesses of reporting empty messages, empty details, or details which are
+ * the same as the main message.
+ */
+public abstract class MessageLogger {
+
+       public static final String MISSING_MESSAGE_PLACEHOLDER = "Internal error";
+       public static final String MULTIPLE_MESSAGE_PLACEHOLDER = "Multiple problems have occurred";
+
+       public interface Listener {
+               void statusLogged(IStatus status);
+       }
+
+       private static List<Listener> listeners = new ArrayList<Listener>();
+
+       public MessageLogger() {
+       }
+
+       /**
+        * Add listener to logged errors for all instances of ErrorLogger.
+        * 
+        * @param listener
+        *            listener, duplicates ignored
+        */
+       public static synchronized void addListener(Listener listener) {
+               if (!listeners.contains(listener))
+                       listeners.add(listener);
+       }
+
+       /**
+        * Remove listener for logged errors for all instances of ErrorLogger.
+        * 
+        * @param listener
+        *            listener,missing ignored
+        */
+       public static synchronized void removeListener(Listener listener) {
+               listeners.remove(listener);
+       }
+
+       protected static void fireListener(IStatus status) {
+               Listener[] array;
+               synchronized (listeners) {
+                       array = listeners.toArray(new Listener[listeners.size()]);
+               }
+               for (Listener listener : array) {
+                       listener.statusLogged(status);
+               }
+       }
+
+       /**
+        * Log a finalized status message.
+        * 
+        * @param status
+        */
+       protected void doLog(IStatus status) {
+               if (getPlugin() != null) {
+                       getPlugin().getLog().log(status);
+               } else {
+                       System.err.println(status.toString());
+                       if (status.getException() != null)
+                               status.getException().printStackTrace(System.err);
+               }
+
+               fireListener(status);
+       }
+
+       /**
+        * Create a status with as much information as possible at the top level
+        * (IStatus#getMessage), reading the message from the exception or a nested
+        * exception if possible. Favor a CoreException's IStatus if the mainMessage
+        * is null.
+        * 
+        * @param severity
+        * @param mainMessage
+        * @param exception
+        * @return new or existing IStatus
+        * @since 2.0
+        */
+       public IStatus createStatus(int severity, String mainMessage, Throwable exception) {
+               String pluginID = getPluginID();
+               IStatus status;
+
+               // use an available status if possible
+               if (isEmpty(mainMessage) && exception instanceof CoreException) {
+                       status = ((CoreException) exception).getStatus();
+                       exception = null;
+
+                       // the CoreException message is just the status message
+                       if (!isEmpty(status.getMessage())) {
+                               if (!isRealMultiStatus(status))
+                                       return status;
+                               mainMessage = MULTIPLE_MESSAGE_PLACEHOLDER;
+                       }
+
+                       if (status.getException() != null && status.getException().getMessage() != null) {
+                               // make a new status -- the current one isn't very useful
+                               mainMessage = status.getException().getMessage();
+                               exception = status.getException();
+                       } else {
+                               return status;
+                       }
+               }
+
+               // peek to see if the exception is a simple wrapper
+               if (isEmpty(mainMessage)) {
+                       Throwable base = exception;
+                       while (base != null && isEmpty(base.getMessage()))
+                               base = base.getCause();
+                       if (base != null && !isEmpty(base.getMessage()))
+                               mainMessage = base.getMessage();
+                       else
+                               mainMessage = MISSING_MESSAGE_PLACEHOLDER;
+               }
+
+               status = new Status(severity, pluginID, mainMessage, exception);
+               return status;
+       }
+
+       private static boolean isEmpty(String text) {
+               return text == null || text.length() == 0;
+       }
+
+       /**
+        * Log a status message.
+        * 
+        * @param status
+        */
+       public void log(IStatus status) {
+               if (status.getSeverity() == IStatus.CANCEL)
+                       return;
+               if (isEmpty(status.getMessage()) && !isRealMultiStatus(status))
+                       status = createStatus(status.getSeverity(), null, status.getException());
+               doLog(status);
+       }
+
+       /**
+        * @param status
+        * @return
+        */
+       private boolean isRealMultiStatus(IStatus status) {
+               return status.isMultiStatus() && ((MultiStatus) status).getChildren().length > 0;
+       }
+
+       /**
+        * Log a message
+        * 
+        * @param severity
+        *            one of {@value IStatus#ERROR} {@value IStatus#WARNING}
+        *            {@value IStatus#INFO}
+        * @param mainMessage
+        *            the error message (may be <code>null</code> to use the
+        *            exception message)
+        * @param exception
+        *            the exception caused by the error (may be <code>null</code>)
+        */
+       public void log(int severity, String mainMessage, Throwable exception) {
+               IStatus status = createStatus(severity, mainMessage, exception);
+               log(status);
+       }
+
+       /**
+        * Log an error.
+        * 
+        * @param mainMessage
+        *            the error message (may be <code>null</code> to use the
+        *            exception message)
+        * @param exception
+        *            the exception caused by the error (may be <code>null</code>)
+        */
+       public void logError(String mainMessage, Throwable t) {
+               log(IStatus.ERROR, mainMessage, t);
+       }
+
+       /**
+        * Log an exception.
+        * 
+        * @param exception
+        *            the exception caused by the error (may be <code>null</code>)
+        * @since 2.0
+        */
+       public void logException(Throwable t) {
+               log(IStatus.ERROR, null, t);
+       }
+
+       public abstract Plugin getPlugin();
+
+       public abstract String getPluginID();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/AbstractFormattedValuesRequestCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/AbstractFormattedValuesRequestCache.java
new file mode 100644 (file)
index 0000000..72f78d6
--- /dev/null
@@ -0,0 +1,36 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+
+/**
+ * Base class for ACPM objects that cache information obtained from
+ * {@link IFormattedValues}
+ * 
+ * @param <V>
+ *            the specific type of information requested
+ * @since 2.0
+ */
+public abstract class AbstractFormattedValuesRequestCache<V> extends BaseRequestCache<V> {
+
+       /** Constructor */
+       public AbstractFormattedValuesRequestCache(IFormattedValues service, IDMContext ctx) {
+        super(service, ctx);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.acmp.BaseRequestCache#resumedEventHandler(org.eclipse.cdt.dsf.datamodel.IDMEvent)
+        */
+       @DsfServiceEventHandler
+       public void resumedEventHandler(IDMEvent<?> e) {
+               // TODO: for now, we defer to the default behavior of losing confidence
+               // in our data on *any* debug event. We should be more discriminating,
+               // but this will be tricky from here since technically we're dealing
+               // with a generic IFormattedValues object. Could be a register, an
+               // expression, or something else. I don't know that we can cleanly
+               // determine what events will invalidate out data.
+               super.resumedEventHandler(e);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/AbstractRegisterRequestCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/AbstractRegisterRequestCache.java
new file mode 100644 (file)
index 0000000..99227a7
--- /dev/null
@@ -0,0 +1,33 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+
+/**
+ * Base class for ACPM objects that cache information obtained from
+ * {@link IRegisters}
+ * 
+ * @param <V>
+ *            the specific type of information requested
+ * @since 2.0            
+ */
+public abstract class AbstractRegisterRequestCache<V> extends BaseRequestCache<V> {
+
+       /** Constructor */
+       public AbstractRegisterRequestCache(IRegisters service, IDMContext ctx) {
+        super(service, ctx);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.acmp.BaseRequestCache#resumedEventHandler(org.eclipse.cdt.dsf.datamodel.IDMEvent)
+        */
+       @DsfServiceEventHandler
+       public void resumedEventHandler(IDMEvent<?> e) {
+               // By default, don't invalidate our data on any event. Our derivatives
+               // store information *about* the registers, not the contents of
+               // registers. The former typically does not change over the course
+               // of a debug session
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/AvailableFormatsRequestCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/AvailableFormatsRequestCache.java
new file mode 100644 (file)
index 0000000..e85df53
--- /dev/null
@@ -0,0 +1,33 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext;
+
+/**
+ * Cached result of {@link IFormattedValues#getAvailableFormats(IFormattedDataDMContext, DataRequestMonitor)} 
+ * 
+ * @param <V>
+ *            the specific type of information requested
+ * @since 2.0            
+ */
+public class AvailableFormatsRequestCache extends AbstractFormattedValuesRequestCache<String[]> {
+
+       /** Constructor */
+       public AvailableFormatsRequestCache(IFormattedValues service, IDMContext ctx) {
+        super(service, ctx);
+    }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.concurrent.RequestCache#retrieve(org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       protected void retrieve(final DataRequestMonitor<String[]> rm) {
+               ((IFormattedValues)fService).getAvailableFormats((IFormattedDataDMContext)fCtx, new DataRequestMonitor<String[]>(fService.getExecutor(), rm) {
+                       public void handleSuccess() {
+                               rm.setData(getData());
+                               rm.done();
+                       }
+               });
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/BaseRangeCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/BaseRangeCache.java
new file mode 100644 (file)
index 0000000..0271eab
--- /dev/null
@@ -0,0 +1,113 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import java.util.List;
+
+import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.RangeCache;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * Base EDC class for ACPM range-based caches. See {@link RangeCache}. 
+ * @since 2.0
+ */
+public abstract class BaseRangeCache<V> extends RangeCache<V> implements ICacheEntry {
+
+       /** See {@link #getService()} */
+       protected final IDsfService fService;
+       
+       /** See {@link #getContext()} */
+       protected final IDMContext fCtx;
+       
+       /** See {@link #getMetaData()} */
+       private Object fMetaData;
+
+       /**
+        * Constructor
+        * 
+        * @param service
+        *            The DSF service that will provide the data
+        * @param ctx
+        *            The primary context the data is for
+        */
+       public BaseRangeCache(IDsfService service, IDMContext ctx) {
+               super(new ImmediateInDsfExecutor(service.getExecutor()));
+               fService = service;
+               fCtx = ctx;
+       }
+       
+       /** Returns the DSF service that provides the data */
+       public IDsfService getService() {
+               return fService;
+       }
+
+       /**
+        * Returns the primary context the data is for. Additional qualifications
+        * may be held by derivative classes
+        */
+       public IDMContext getContext() {
+               return fCtx;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.acmp.ICacheEntry#setMetaData(java.lang.Object)
+        */
+       public void setMetaData(Object data) {
+               fMetaData = data;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.acmp.ICacheEntry#getMetaData()
+        */
+       public Object getMetaData() {
+               return fMetaData;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.concurrent.AbstractCache#reset()
+        */
+       protected void reset() {
+               super.reset();
+
+               // Once we're invalid, there's no point in listening for events; we
+               // don't support going back to the valid state via a notification--too
+               // much work. A fresh asynchronous query is the only way to get back to
+               // the valid state
+               fService.getSession().removeServiceEventListener(this);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.concurrent.RequestCache#set(java.lang.Object, org.eclipse.core.runtime.IStatus)
+        */
+       protected void set(long offset, int count, List<V> data, IStatus status) {
+               super.set(offset, count, data, status);
+               
+               // Now that we are valid, listen for debug events to find out when we
+               // need to move ourselves to the invalid state
+           fService.getSession().addServiceEventListener(this, null);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.acmp.BaseRequestCache#dispose()
+        */
+       public void dispose() {
+               reset();
+       }
+       
+       @DsfServiceEventHandler
+       public void resumedEventHandler(IDMEvent<?> e) {
+               // We are extremely sensitive. *Any* debug event will cause us to lose
+               // confidence in our data. We should be more discriminating and react to
+               // specific events that we know may affect the data. E.g., there is no
+               // need to invalidate ourselves if a breakpoint creation event occurs.
+               reset();
+       }
+
+       public RequestMonitor getRequestMonitor() {
+               return null; // TODO: how to handle this???
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/BaseRequestCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/BaseRequestCache.java
new file mode 100644 (file)
index 0000000..75ea084
--- /dev/null
@@ -0,0 +1,112 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestCache;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * Base EDC class for ACPM caches. See {@link RequestCache} 
+ * @since 2.0
+ */
+public abstract class BaseRequestCache<V> extends RequestCache<V> implements ICacheEntry {
+
+       /** See {@link #getService()} */
+       protected final IDsfService fService;
+       
+       /** See {@link #getContext()} */
+       protected final IDMContext fCtx;
+       
+       /** See {@link #getMetaData()} */
+       private Object fMetaData;
+       
+       /**
+        * Constructor
+        * 
+        * @param service
+        *            The DSF service that will provide the data
+        * @param ctx
+        *            The primary context the data is for
+        */
+       public BaseRequestCache(IDsfService service, IDMContext ctx) {
+               super(new ImmediateInDsfExecutor(service.getExecutor()));
+               fService = service;
+               fCtx = ctx;
+       }
+       
+       /** Returns the DSF service that provides the data */
+       public IDsfService getService() {
+               return fService;
+       }
+
+       /**
+        * Returns the primary context the data is for. Additional qualifications
+        * may be held by derivative classes
+        */
+       public IDMContext getContext() {
+               return fCtx;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.acmp.ICacheEntry#setMetaData(java.lang.Object)
+        */
+       public void setMetaData(Object data) {
+               fMetaData = data;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.acmp.ICacheEntry#getMetaData()
+        */
+       public Object getMetaData() {
+               return fMetaData;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.acmp.ICacheEntry#dispose()
+        */
+       public void dispose() {
+               if (isValid()) {
+                       reset();
+               }
+       }
+       
+       @DsfServiceEventHandler
+       public void resumedEventHandler(IDMEvent<?> e) {
+               // The default behavior is to be extremely sensitive. *Any* debug event
+               // will cause us to lose confidence in our data. Subclasses should be
+               // more discriminating and react to specific events that we know may
+               // affect the data. E.g., there is no need to invalidate ourselves if a
+               // breakpoint creation event occurs.
+               if (isValid()) {
+                       reset();
+               }
+       }
+
+       protected void set(V data, IStatus status) {
+               super.set(data, status);
+               
+               // Now that we are valid, listen for debug events to find out when we
+               // need to move ourselves to the invalid state
+               fService.getSession().addServiceEventListener(this, null);
+       }
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.concurrent.AbstractCache#reset()
+        */
+       protected void reset() {
+               super.reset();
+
+               // Once we're invalid, there's no point in listening for events; we
+               // don't support going back to the valid state via a notification--too
+               // much work. A fresh asynchronous query is the only way to get back to
+               // the valid state
+               fService.getSession().removeServiceEventListener(this);
+       }
+       
+       public RequestMonitor getRequestMonitor() {
+               return fRm;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/FormatedExpressionValueRequestCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/FormatedExpressionValueRequestCache.java
new file mode 100644 (file)
index 0000000..ecafb72
--- /dev/null
@@ -0,0 +1,30 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+
+/**
+ * An ACPM cache for {@link IFormattedValues#getFormattedExpressionValue(FormattedValueDMContext, DataRequestMonitor)} 
+ * @since 2.0
+ */
+public class FormatedExpressionValueRequestCache extends AbstractFormattedValuesRequestCache<FormattedValueDMData> {
+
+       public FormatedExpressionValueRequestCache(IFormattedValues service, FormattedValueDMContext ctx) {
+        super(service, ctx);
+    }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.concurrent.RequestCache#retrieve(org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       protected void retrieve(final DataRequestMonitor<FormattedValueDMData> rm) {
+
+               ((IFormattedValues)fService).getFormattedExpressionValue((FormattedValueDMContext)fCtx, new DataRequestMonitor<FormattedValueDMData>(fService.getExecutor(), rm) {
+                       public void handleSuccess() {
+                               rm.setData(getData());
+                               rm.done();
+                       }
+               });
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/GetRegistersRequestCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/GetRegistersRequestCache.java
new file mode 100644 (file)
index 0000000..b69d355
--- /dev/null
@@ -0,0 +1,24 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
+
+/**
+ * An ACPM cache for {@link IRegisters#getRegisters(IDMContext, DataRequestMonitor) 
+ * @since 2.0
+ */
+public class GetRegistersRequestCache extends AbstractRegisterRequestCache<IRegisterDMContext[]> {
+
+       public GetRegistersRequestCache(IRegisters service, IDMContext ctx) {
+        super(service, ctx);
+    }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.concurrent.RequestCache#retrieve(org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       protected void retrieve(DataRequestMonitor<IRegisterDMContext[]> rm) {
+               ((IRegisters)fService).getRegisters(fCtx, rm);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/ICacheEntry.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/ICacheEntry.java
new file mode 100644 (file)
index 0000000..2ea2483
--- /dev/null
@@ -0,0 +1,52 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+
+/**
+ * EDC ACPM cache objects must implement this interface in order to be
+ * manageable by an ICacheManager. Some cache manager implementations need to
+ * attach meta data to the cache objects in order to track them and decide which
+ * ones should be discarded first.
+ * 
+ * @since 2.0
+ */
+public interface ICacheEntry {
+       /**
+        * Called by a cache manager to attach meta data for tracking purposes
+        * 
+        * @param data
+        *            the meta data
+        */
+       void setMetaData(Object data);
+
+       /**
+        * Called by a cache manager to retrieve the data it has previously attached
+        * via {@link #setMetaData(Object)}
+        * 
+        * @return the meta data
+        */
+       Object getMetaData();
+
+       /**
+        * Called by a cache manager when it discards a cache object in order to
+        * make room for more. The implementation should clear any data it has been
+        * storing from its source.
+        */
+       void dispose();
+
+       /**
+        * Returns the RM the cache object passes to its derivative's retrieval
+        * method. Cache objects that are containers for other cache objects can
+        * return null. They are responsible for managing the lifetime of their own
+        * cache objects. We manage the lifetime of the collection as a whole.
+        */
+       RequestMonitor getRequestMonitor();
+
+       
+       /**
+        * Returns the primary context the cache object is associated with
+        */
+       IDMContext getContext();
+}
+
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/MemoryRangeCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/MemoryRangeCache.java
new file mode 100644 (file)
index 0000000..be41579
--- /dev/null
@@ -0,0 +1,71 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.debug.core.model.MemoryByte;
+
+/**
+ * An ACPM cache for
+ * {@link IMemory#getMemory(IMemoryDMContext, IAddress, long, int, int, DataRequestMonitor)}
+ * 
+ * @since 2.0
+ */
+public class MemoryRangeCache extends BaseRangeCache<MemoryByte> {
+       
+       /** See {@link #getAddress()} */
+       final private IAddress fAddress;
+       
+       /** See {@link #getWordSize()} */
+       final private int fWordSize;
+
+       public MemoryRangeCache(IMemory service, IDMContext ctx, IAddress address, int wordSize) {
+        super(service, ctx);
+        fAddress = address;
+        fWordSize = wordSize;
+    }
+
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.concurrent.RangeCache#retrieve(long, int, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       @Override
+       protected void retrieve(long offset, int count, final DataRequestMonitor<List<MemoryByte>> rm) {
+               ((IMemory)fService).getMemory((IMemoryDMContext)fCtx, fAddress, offset, fWordSize, count, new DataRequestMonitor<MemoryByte[]>(fService.getExecutor(), rm) {
+                       public void handleSuccess() {
+                               rm.setData(Arrays.asList(getData()));
+                               rm.done();
+                       }
+               });
+       }
+
+       @DsfServiceEventHandler
+       public void resumedEventHandler(IDMEvent<?> e) {
+               // TODO: be more discriminating instead instead of calling our super
+               // class for any event
+               super.resumedEventHandler(e);
+       }
+
+       /** The base address range requests are relative to */
+       public IAddress getAddress() {
+               return fAddress;
+       }
+
+       /** The the size, in bytes, of an addressable item */
+       public int getWordSize() {
+               return fWordSize;
+       }
+
+
+       public boolean wasCanceled() {
+               // TODO Auto-generated method stub
+               return false;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/RegisterGroupsRequestCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/RegisterGroupsRequestCache.java
new file mode 100644 (file)
index 0000000..ee62b83
--- /dev/null
@@ -0,0 +1,26 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
+
+/**
+ * An ACPM cache for
+ * {@link IRegisters#getRegisters(IDMContext, DataRequestMonitor)}
+ * 
+ * @since 2.0
+ */
+public class RegisterGroupsRequestCache extends AbstractRegisterRequestCache<IRegisterGroupDMContext[]> {
+
+       public RegisterGroupsRequestCache(IRegisters service, IDMContext ctx) {
+        super(service, ctx);
+    }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.concurrent.RequestCache#retrieve(org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       protected void retrieve(DataRequestMonitor<IRegisterGroupDMContext[]> rm) {
+               ((IRegisters)fService).getRegisterGroups(fCtx, rm);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/RegistersByNameRequestCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/acpm/RegistersByNameRequestCache.java
new file mode 100644 (file)
index 0000000..b29aab5
--- /dev/null
@@ -0,0 +1,63 @@
+package org.eclipse.cdt.debug.edc.acpm;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.services.DMContext;
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
+
+/**
+ * An ACPM cache of the collection of all available registers for the given
+ * context, indexed by name. The name is provided by TCF via the property
+ * {@link org.eclipse.tm.tcf.services.IRegisters#PROP_NAME}
+ * 
+ * @since 2.0
+ */
+public class RegistersByNameRequestCache extends AbstractRegisterRequestCache< Map<String, IRegisterDMContext> > {
+
+       public RegistersByNameRequestCache(IRegisters service, IDMContext ctx) {
+        super(service, ctx);
+    }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.concurrent.RequestCache#retrieve(org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       protected void retrieve(final DataRequestMonitor< Map<String, IRegisterDMContext> > rm) {
+               final Map<String, IRegisterDMContext> registerMap = new HashMap<String, IRegisterDMContext>();
+               ((IRegisters)fService).getRegisterGroups(fCtx, new DataRequestMonitor<IRegisterGroupDMContext[]>(fService.getExecutor(), rm) {
+                       public void handleSuccess() {
+                               final List<IRegisterDMContext> registers = new ArrayList<IRegisterDMContext>();
+                               final IRegisterGroupDMContext[] groups = getData(); 
+                               final CountingRequestMonitor crm = new CountingRequestMonitor(fService.getExecutor(), rm) {
+                                       public void handleSuccess() {
+                                               for (IRegisterDMContext register : registers) {
+                                                       String regname = (String)((DMContext)register).getProperties().get(org.eclipse.tm.tcf.services.IRegisters.PROP_NAME);
+                                                       registerMap.put(regname, register);
+                                               }
+                                               rm.setData(registerMap);
+                                               rm.done();
+                                       }
+                               };
+                               crm.setDoneCount(groups.length);
+                               for (IRegisterGroupDMContext group : groups) {
+                                       ((IRegisters)fService).getRegisters(group, new DataRequestMonitor<IRegisterDMContext[]>(fService.getExecutor(), crm) {
+                                               public void handleSuccess() {
+                                                       IRegisterDMContext[] regs = getData();
+                                                       for (IRegisterDMContext reg : regs) {
+                                                               registers.add(reg);
+                                                       }
+                                                       crm.done();
+                                               }
+                                       });
+                               }
+                       }
+               });
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/AbstractDisassembler.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/AbstractDisassembler.java
new file mode 100644 (file)
index 0000000..81ba6ad
--- /dev/null
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.disassembler;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
+import org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Abstract disassembler that implements the platform neutral methods.
+ */
+public abstract class AbstractDisassembler implements IDisassembler {
+
+       private final ITargetEnvironment targetEnvironment;
+
+       /**
+        * Don't allow constructor without passing ITargetEnvironment
+        * @see org.eclipse.cdt.debug.edc.AbstractDisassembler#disassemblerAbstractDisassembler(ITargetEnvironment)
+        */
+       @SuppressWarnings("unused")
+       private AbstractDisassembler() { targetEnvironment = null; }
+
+       /**
+        * Since a disassembler is generally created within the implementor of 
+        * {@link ITargetEnvironment#getDisassembler()}, this constructor together
+        * with the private default constructor forces the implementation to pass
+        * it's own "this" pointer for use in later disassembler processing.
+        * @since 2.0
+        */
+       protected AbstractDisassembler(ITargetEnvironment env) {
+               targetEnvironment = env;
+       }
+
+       /**
+        * Returns the ITargetEnvironment used by the disassembler.
+        * @since 2.0
+        */
+       protected ITargetEnvironment getTargetEnvironment() {
+               return targetEnvironment;
+       }
+
+       /**
+        * Translates the raw memory in the buffer into a list of disassembled instructions.
+        *
+        * @param startAddress the start address
+        * @param endAddress the end address
+        * @param codeBuffer the code buffer
+        * @param options the options, often target environment specific, that are used for disassembly
+        * @param dmc the disassembly context
+        * @return the list of disassembled instructions
+        * @throws CoreException the core exception
+        * @since 2.0
+        */
+       public List<IDisassembledInstruction> disassembleInstructions(IAddress startAddress, IAddress endAddress,
+                               ByteBuffer codeBuffer, Map<String, Object> options, IDisassemblyDMContext dmc)
+                       throws CoreException {
+               IDisassembledInstruction inst = null;
+               ArrayList<IDisassembledInstruction> result = new ArrayList<IDisassembledInstruction>();
+               IAddress address = startAddress;
+
+               while (codeBuffer.hasRemaining() && address.compareTo(endAddress) < 0) {
+                       try {
+                               inst = disassembleOneInstruction(address, codeBuffer, options, dmc);
+                               result.add(inst);
+
+                               // next instruction address
+                               // Note at this point the current position of code buffer should
+                               // point to the next instruction.
+                               address = address.add(inst.getSize());
+                       } catch (CodeBufferUnderflowException e) {
+                               if (result.size() == 0) {
+                                       if (options.containsKey(IDisassemblerOptions.ADDRESS_IS_PC)) {
+                                               throwAnnotated(e, address);
+                                       }
+                                       throw e;
+                               }
+                               break;
+                       } catch (CoreException e) {
+                               throwAnnotated(e, address);
+                       }
+               }
+
+               return result;
+       }
+
+       private void throwAnnotated(CoreException e, IAddress address) throws CoreException {
+               throw EDCDebugger.newCoreException("Fail to disassemble instruction at "
+                               + address.toHexAddressString() + "\nCause: " + e.getLocalizedMessage(), e);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/AssemblyFormatter.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/AssemblyFormatter.java
new file mode 100644 (file)
index 0000000..162cf76
--- /dev/null
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.disassembler;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.cdt.core.IAddress;
+
+public class AssemblyFormatter {
+
+       private static final int ADDRESS_COLUMN_SIZE = 12;
+       private static final int CODE_BYTE_COLUMN_SIZE = 32;
+       protected static final int INST_NAME_COLUMN_SIZE = 10;
+       public static final char OPEN = '(';
+       public static final char CLOSE = ')';
+       public static final char SEPARATOR = ',';
+       public static final char SCALE = ',';
+       public static final char PREFIX_IMMEDIATE = '$';
+       public static final char PREFIX_REGISTER = '%';
+
+       public static String toHexString(IAddress addr, boolean show0x) {
+               // this gives "800000"
+               String ret = Integer.toHexString(addr.getValue().intValue());
+               if (show0x)
+                       ret = "0x" + ret;
+       
+               return ret;
+       }
+
+       /**
+        * get hexString representation of a byte data. <br>
+        * E.g. 0x12 => "12" or "0x12" <br>
+        * 2 = > "02" or "0x02".
+        * 
+        * @param b
+        * @param show0x
+        * @return
+        */
+       public static String toHexString(byte b, boolean show0x) {
+               String s = Integer.toHexString(b & 0xff);
+               if (s.length() == 1)
+                       // padding
+                       s = "0" + s;
+               if (show0x)
+                       s = "0x" + s;
+       
+               return s;
+       }
+
+       public static String toHexString(long i, boolean show0x) {
+               String ret = Long.toHexString(i);
+               if (show0x)
+                       ret = "0x" + ret;
+       
+               return ret;
+       }
+       public static String toHexString(int i, boolean show0x) {
+               String ret = Integer.toHexString(i);
+               if (show0x)
+                       ret = "0x" + ret;
+       
+               return ret;
+       }
+
+       public static String toHexString(short i, boolean show0x) {
+               String ret = Integer.toHexString(i & 0xffff);
+               if (show0x)
+                       ret = "0x" + ret;
+       
+               return ret;
+       }
+
+       public static String formatFarPointer(short segment, int offset) {
+               return "$" + toHexString(segment, true) + ",$" + toHexString(offset, true);
+       }
+
+       /**
+        * Format address for displaying in format column.
+        */
+       public static String formatForAddressColumn(IAddress addr) {
+               String addrStr = toHexString(addr, false);
+       
+               // Padding space at the end.
+               StringBuffer buf = new StringBuffer(addrStr).append(':');
+               for (int i = 0; i < ADDRESS_COLUMN_SIZE - addrStr.length(); i++)
+                       buf.append(' ');
+       
+               return buf.toString();
+       }
+
+       /**
+        * Format bytes for displaying in byte column.
+        * 
+        * @param codeBuffer
+        *            - code byte buffer.
+        * @param startPosition
+        *            - position of the first byte in the code buffer.
+        * @param length
+        *            - number of bytes to display.
+        * @return
+        */
+       public static String formatForByteColumn(ByteBuffer codeBuffer, int startPosition,
+                       int length) {
+                               StringBuffer tmp = new StringBuffer();
+                       
+                               codeBuffer.position(startPosition);
+                               for (int i = 0; i < length; i++) {
+                                       byte b = codeBuffer.get();
+                                       tmp.append(toHexString(b, false)).append(' ');
+                               }
+                       
+                               int cnt = tmp.length();
+                       
+                               // padding
+                               for (int i = 0; i < CODE_BYTE_COLUMN_SIZE - cnt; i++)
+                                       tmp.append(' ');
+                       
+                               return tmp.toString();
+                       }
+
+       public static String formatForCode(IAddress addr) {
+               return toHexString(addr, true);
+       }
+
+       public static String formatImmediate(long imm) {
+               /* Not signed. */
+               return PREFIX_IMMEDIATE + toHexString(imm, true);
+       }
+
+       public static String formatImmediate(int imm) {
+               /* Not signed. */
+               return PREFIX_IMMEDIATE + toHexString(imm, true);
+       }
+       
+       public static String formatDisplacement(int displacement) {
+               if (displacement < 0)
+                       return "-" + toHexString(-displacement, true); // negative hex
+               else
+                       return toHexString(displacement, true); // signed hex
+       }
+
+       public static String formatOffset(int offset) {
+               // Offset is never negative.
+               return toHexString(offset, true); // signed hex
+       }
+
+       public static String formatRegister(String regName, boolean fIndirectAddressing) {
+               String ret = "";
+               if (fIndirectAddressing)
+                       ret += OPEN;
+       
+               ret += PREFIX_REGISTER + regName;
+       
+               if (fIndirectAddressing)
+                       ret += CLOSE;
+       
+               return ret;
+       }
+
+       public static String instructionNameSizeSuffix(int size) {
+               return size == 8 ? "b" : (size == 16 ? "w" : "l");
+       }
+
+       public AssemblyFormatter() {
+               super();
+       }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/CodeBufferUnderflowException.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/CodeBufferUnderflowException.java
new file mode 100644 (file)
index 0000000..be4e7dc
--- /dev/null
@@ -0,0 +1,28 @@
+package org.eclipse.cdt.debug.edc.disassembler;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Exists to help identify the precise CoreException being thrown by
+ * instruction parsers so that the disassemblers can perform error
+ * recovery more gracefully.  <br>Extends CoreException so that
+ * existing handlers can catch it without having to be modified.
+ * @since 2.0
+ */
+public class CodeBufferUnderflowException extends CoreException {
+       private static final long serialVersionUID = 2725920360107613447L;
+
+       /**
+        * Exists to help identify the precise CoreException being
+        * thrown by instruction parsers so that the disassemblers
+        * can perform error recovery more gracefully.
+        * @param t the original thrown object, for reference as necessary
+        */
+       public CodeBufferUnderflowException(Throwable t) {
+               super(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID,
+                                                " end of code buffer reached.", t));
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/DisassembledInstruction.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/DisassembledInstruction.java
new file mode 100644 (file)
index 0000000..ae2528f
--- /dev/null
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.disassembler;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.IJumpToAddress;
+
+/**
+ * Class describing an instruction output from a disassembler.
+ */
+public class DisassembledInstruction implements IDisassembledInstruction {
+       // Address of the instruction
+       private IAddress address;
+       // size of instruction in 8-bit bytes
+       private int size;
+       // mnemonics, including instruction name & arguments. May include
+       // address and raw bytes, depending on disassembler options.
+       private String mnemonics;
+       // jump-to-address for a control-change instruction (branch, call, ret,
+       // etc.).
+       // Null for the other instructions.
+       private IJumpToAddress jumpToAddress;
+
+       public DisassembledInstruction() {
+               address = null;
+               size = 0;
+               mnemonics = null;
+               jumpToAddress = null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.disassembler.IDisassembledInstruction#getAddress()
+        */
+       public IAddress getAddress() {
+               return address;
+       }
+
+       public void setAddress(IAddress address) {
+               this.address = address;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.disassembler.IDisassembledInstruction#isValid()
+        */
+       public boolean isValid() {
+               return size > 0;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.disassembler.IDisassembledInstruction#getSize()
+        */
+       public int getSize() {
+               return size;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.disassembler.IDisassembledInstruction#getMnemonics()
+        */
+       public String getMnemonics() {
+               return mnemonics;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.disassembler.IDisassembledInstruction#getJumpToAddress()
+        */
+       public IJumpToAddress getJumpToAddress() {
+               return jumpToAddress;
+       }
+
+       public void setSize(int size) {
+               this.size = size;
+       }
+
+       public void setMnemonics(String mnemonics) {
+               this.mnemonics = mnemonics;
+       }
+
+       public void setJumpToAddress(IJumpToAddress jta) {
+               this.jumpToAddress = jta;
+       }
+
+       @Override
+       public String toString() {
+               return "(length: " + size + ")  " + Integer.toHexString(address.getValue().intValue()) + ":  " + mnemonics
+                               + (jumpToAddress != null ? "  [BranchAddress: " + jumpToAddress.toString() + "]" : "");
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/EDCInstruction.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/EDCInstruction.java
new file mode 100644 (file)
index 0000000..f864d84
--- /dev/null
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.disassembler;
+
+import java.math.BigInteger;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.dsf.debug.service.AbstractInstruction;
+import org.eclipse.cdt.dsf.debug.service.IInstruction;
+
+public class EDCInstruction extends AbstractInstruction {
+
+       private final IDisassembledInstruction instruction;
+       private String functionName;
+       private int offset;
+
+       public EDCInstruction(IDisassembledInstruction instruction) {
+               this.instruction = instruction;
+               functionName = null;
+               offset = 0;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.cdt.dsf.debug.service.IInstruction#getAdress()
+        */
+       public BigInteger getAdress() {
+               return instruction.getAddress().getValue();
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.cdt.dsf.debug.service.IInstruction#getArgs()
+        */
+       public String getArgs() {
+               // It's assumed the disassembler does not put extras like address
+               // and raw bytes in the output.
+               String ret = null;
+               String asm = instruction.getMnemonics();
+               StringTokenizer tzer = new StringTokenizer(asm);
+               if (tzer.countTokens() == 1) { // no arguments
+                       return ret;
+               } else {
+                       tzer.nextToken(); // skip the instruction name
+                       ret = tzer.nextToken();
+                       while (tzer.hasMoreTokens())
+                               ret += " " + tzer.nextToken();
+               }
+
+               return ret;
+       }
+
+       /**
+        * Sets the function name, if any, for this instruction..
+        *
+        * @param functionName the new function name
+        * @since 2.0
+        */
+       public void setFunctionName(String functionName) {
+               this.functionName = functionName;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.cdt.dsf.debug.service.IInstruction#getFuntionName()
+        */
+       public String getFuntionName() {
+               return functionName;
+       }
+       /**
+        * not a true override; the name is "misspelled" in {@link IInstruction}
+        * @since 2.0
+        * @see org.eclipse.cdt.dsf.debug.service.IInstruction#getFuntionName()
+        */
+       public String getFunctionName() {
+               return functionName;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.cdt.dsf.debug.service.IInstruction#getInstruction()
+        */
+       public String getInstruction() {
+               // Hmm, this actually needs the whole instruction.
+               return instruction.getMnemonics();
+       }
+
+       /**
+        * Sets the offset for this instruction.
+        *
+        * @param offset the new offset
+        * @since 2.0
+        */
+       public void setOffset(int offset) {
+               this.offset = offset;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.cdt.dsf.debug.service.IInstruction#getOffset()
+        */
+       public long getOffset() {
+               return offset;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.cdt.dsf.debug.service.IInstruction#getOpcode()
+        */
+       public String getOpcode() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       /**
+        * Needed for DisassemblyBackendDsf#insertDisassembly() ;
+        * for HEAD see the first reference; for CDT_7_0, see the second reference
+        * @see org.eclipse.cdt.dsf.debug.service.IInstruction#getSize()
+        * @see org.eclipse.cdt.dsf.debug.internal.provisional.service.IInstructionWithSize#getSize()
+        * @since 2.0
+        */
+       public Integer getSize() {
+               return instruction.getSize();
+       }
+       
+       @Override
+       public String toString() {
+               return instruction.toString();
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/EDCInstructionFunctionInfo.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/EDCInstructionFunctionInfo.java
new file mode 100644 (file)
index 0000000..8780d9b
--- /dev/null
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.disassembler;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.services.IEDCModuleDMContext;
+import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+
+/**
+ * Information for an instruction, line, or block that can be used
+ * when constructing EDCInstruction objects to collect and pass to
+ * DisassemblyBackendDsf for display in the disassembly view.
+ * @author kirk.beitz@nokia.com
+ * @since 2.0
+ */
+public class EDCInstructionFunctionInfo {
+       private final String functionName;
+       private final IAddress functionStartAddress;
+
+       /**
+        * simple constructor
+        * @param name function for the block this object represents
+        * @param address beginning of the function
+        */
+       public EDCInstructionFunctionInfo(String name, IAddress address) {
+               functionName = name;
+               functionStartAddress = address;
+       }
+
+       /**
+        * constructor for a block whose function may not be known
+        * @param module container of the item for which to find function/address info
+        * @param line source location from LNT for which to find function/address info
+        */
+       public EDCInstructionFunctionInfo(IEDCModuleDMContext module, ILineEntry line) {
+               String name = null;
+               IAddress start = null;
+               IEDCSymbolReader reader = module.getSymbolReader();
+               if (reader != null) {
+                       IScope scope = reader.getModuleScope().getScopeAtAddress(line.getLowAddress());
+                       while (scope != null && !(scope instanceof IFunctionScope)) {
+                               scope = scope.getParent();
+                       }
+
+                       if (scope != null) {
+                               name = scope.getName();
+                               start = ((IFunctionScope)scope).getLowAddress();
+                       }
+               }
+               functionName = name;
+               functionStartAddress = start;
+       }
+
+       /**
+        * @return function name for block, null if never established
+        */
+       public String getFunctionName() {
+               return functionName;
+       }
+
+       /**
+        * @return starting address of function, null if never established
+        */
+       public IAddress getFunctionStartAddress() {
+               return functionStartAddress;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/EDCMixedInstruction.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/EDCMixedInstruction.java
new file mode 100644 (file)
index 0000000..43a9d94
--- /dev/null
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.disassembler;
+
+import org.eclipse.cdt.dsf.debug.service.IInstruction;
+import org.eclipse.cdt.dsf.debug.service.IMixedInstruction;
+
+public class EDCMixedInstruction implements IMixedInstruction {
+
+       private final String fileName;
+       private final int lineNumber;
+       private final IInstruction[] instructions;
+
+       public EDCMixedInstruction(String fileName, int lineNumber, IInstruction[] instructions) {
+               this.fileName = fileName;
+               this.lineNumber = lineNumber;
+               this.instructions = instructions;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.cdt.dsf.debug.service.IMixedInstruction#getFileName()
+        */
+       public String getFileName() {
+               return fileName;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * org.eclipse.cdt.dsf.debug.service.IMixedInstruction#getInstructions()
+        */
+       public IInstruction[] getInstructions() {
+               return instructions;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.cdt.dsf.debug.service.IMixedInstruction#getLineNumber()
+        */
+       public int getLineNumber() {
+               return lineNumber;
+       }
+
+       @Override
+       public String toString() {
+               StringBuffer buf = new StringBuffer();
+
+               buf.append("Source File: ").append(fileName).append("\n");
+               buf.append(" line #").append(lineNumber).append(":\n");
+               for (IInstruction i : instructions)
+                       buf.append("\t").append(i).append("\n");
+
+               return buf.toString();
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/IDisassembledInstruction.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/IDisassembledInstruction.java
new file mode 100644 (file)
index 0000000..048dd06
--- /dev/null
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.disassembler;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.IJumpToAddress;
+import org.eclipse.cdt.debug.edc.JumpToAddress;
+
+public interface IDisassembledInstruction {
+
+       public IAddress getAddress();
+
+       public boolean isValid();
+
+       public int getSize();
+
+       public String getMnemonics();
+
+       /**
+        * Get {@link JumpToAddress} of the instruction. Return null for non
+        * control-change instruction.
+        * 
+        * @return
+        */
+       public IJumpToAddress getJumpToAddress();
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/IDisassembler.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/disassembler/IDisassembler.java
new file mode 100644 (file)
index 0000000..32092c6
--- /dev/null
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.disassembler;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Generic interface for disassemblers.
+ * 
+ */
+public interface IDisassembler {
+
+       /**
+        * A known static value for assembly instruction parsers to use to
+        * indicate an instruction that cannot be parsed, and against which
+        * abstract/generic members of Disassembly services can compare.
+        * @since 2.0
+        */
+       public static final String INVALID_OPCODE = "invalid opcode";
+       
+       /**
+        * Disassembler options that are common to all targets. Different targets
+        * may have its own disassembler options.
+        */
+       public static interface IDisassemblerOptions {
+               /*
+                * Option key names.
+                */
+               public final static String GET_BRANCH_ADDRESS = "GetBranchAddress";
+               public final static String GET_MNEMONICS = "GetMnemonics";
+
+               // Following are sub-options when GetMnemonics is true.
+               //
+               /**
+                * Show address of the instruction in disassembler output.
+                */
+               public final static String MNEMONICS_SHOW_ADDRESS = "ShowAddresses";
+               /**
+                * Show original bytes of the instruction in disassembler output.
+                */
+               public final static String MNEMONICS_SHOW_BYTES = "ShowBytes";
+               /**
+                * Show symbol in the address in disassembler output.
+                */
+               public final static String MNEMONICS_SHOW_SYMBOL = "ShowSymbol";
+
+               /**
+                * Indicates that the address being disassembled is the PC
+                * @since 2.0
+                */
+               public static final String ADDRESS_IS_PC = "AddressIsPC";
+       }
+
+       /**
+        * Disassemble one instruction at the beginning of the given byte array.
+        * 
+        * @param address
+        *            address of the code bytes
+        * @param code_bytes
+        *            memory bytes containing instructions.
+        * @param options
+        *            disassembler options.
+        * @param dmc
+        *                        for context specific needs of the implementor (may be null)
+        * @return a {@link IDisassembledInstruction} object, null if no valid
+        *         instruction at the beginning of the code_bytes.
+        * @throws CoreException
+        * @since 2.0
+        */
+       public IDisassembledInstruction disassembleOneInstruction(IAddress address, ByteBuffer code_bytes,
+                       Map<String, Object> options, IDisassemblyDMContext dmc) throws CoreException;
+
+       /**
+        * Disassemble a block of memory.
+        * 
+        * @param start_address
+        *            address of the first byte in the "code_bytes"
+        * @param end_address
+        *            address of the byte after the last byte that is disassembled.
+        * @param code_bytes
+        *            memory bytes
+        * @param options
+        *            disassembler options.
+        * @param dmc
+        *                        for context specific needs of the implementor (may be null)
+        * 
+        * @return a list of {@link IDisassembledInstruction} objects.
+        * @throws CoreException
+        * @since 2.0
+        */
+       public List<IDisassembledInstruction> disassembleInstructions(IAddress start_address, IAddress end_address,
+                       ByteBuffer code_bytes, Map<String, Object> options, IDisassemblyDMContext dmc) throws CoreException;
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/AbstractCompositeFormatProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/AbstractCompositeFormatProvider.java
new file mode 100644 (file)
index 0000000..607b555
--- /dev/null
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.cdt.debug.edc.services.IEDCExpression;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * An abstract class for formatting composite types.
+ */
+public abstract class AbstractCompositeFormatProvider extends AbstractVariableConverter implements ITypeContentProvider {
+
+       /**
+        * The Class NameToFieldPath.
+        */
+       protected static class NameToFieldPath {
+               
+               /** The name. */
+               private String name;
+               
+               /** The field path. */
+               private String fieldPath;
+               
+               /**
+                * Instantiates a new name to field path.
+                *
+                * @param name the name
+                * @param fieldPath the field path
+                */
+               public NameToFieldPath(String name, String fieldPath) {
+                       this.name = name;
+                       this.fieldPath = fieldPath;
+               }
+
+               /**
+                * Gets the name.
+                *
+                * @return the name
+                */
+               public String getName() {
+                       return name;
+               }
+
+               /**
+                * Gets the field path.
+                *
+                * @return the field path
+                */
+               public String getFieldPath() {
+                       return fieldPath;
+               }
+       }
+       
+       /** The name-to-field paths. */
+       private final NameToFieldPath[] nameToFieldPaths;
+       
+       /**
+        * Instantiates a new abstract composite format provider.
+        *
+        * @param type the type
+        * @param forDetails is this used for the details pane
+        * @param nameToFieldPaths the name to field paths
+        */
+       public AbstractCompositeFormatProvider(IType type, boolean forDetails, List<NameToFieldPath> nameToFieldPaths) {
+               super(type, forDetails);
+               this.nameToFieldPaths = nameToFieldPaths.toArray(new NameToFieldPath[nameToFieldPaths.size()]);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.formatter.ITypeContentProvider#getChildIterator(org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext)
+        */
+       public Iterator<IExpressionDMContext> getChildIterator(IExpressionDMContext variable) throws CoreException {
+               List<IExpressionDMContext> childExpressions = getChildren(variable);
+               return childExpressions.iterator();
+       }
+       
+       /**
+        * Gets the child count.
+        *
+        * @param variable the variable
+        * @return the child count
+        * @throws CoreException the core exception
+        * @since 2.0
+        */
+       public int getChildCount(IExpressionDMContext variable) throws CoreException {
+               List<IExpressionDMContext> childExpressions = getChildren(variable);
+               return childExpressions.size();
+       }
+
+       /**
+        * Gets the children.
+        *
+        * @param variable the variable
+        * @return the children
+        * @throws CoreException the core exception
+        */
+       protected List<IExpressionDMContext> getChildren(IExpressionDMContext variable) throws CoreException {
+               List<IExpressionDMContext> childExpressions = new ArrayList<IExpressionDMContext>();
+               for (NameToFieldPath nameToFieldPath : nameToFieldPaths) {
+                       IExpressionDMContext createSubExpression = 
+                               FormatUtils.createSubExpression(variable, nameToFieldPath.getName(), 
+                                               FormatUtils.getFieldAccessor(type) + nameToFieldPath.getFieldPath());
+                       if (createSubExpression != null) {
+                               childExpressions.add(createSubExpression);
+                       }
+               }
+               // now add all unmapped children
+               List<IExpressionDMContext> allChildren = FormatUtils.getAllChildExpressions(variable);
+               for (IExpressionDMContext child : allChildren) {
+                       String name = ((IEDCExpression) child).getName();
+                       if (!hasFieldPath(name))
+                               childExpressions.add(child);
+               }
+               return childExpressions;
+       }
+
+       /**
+        * Checks for field path.
+        *
+        * @param fieldPath the field path
+        * @return true, if successful
+        */
+       private boolean hasFieldPath(String fieldPath) {
+               for (NameToFieldPath nameToFieldPath : nameToFieldPaths) {
+                       if (nameToFieldPath.getFieldPath().equals(fieldPath))
+                               return true;
+               }
+               return false;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.formatter.AbstractVariableConverter#getDetailsValue(org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext)
+        */
+       protected String getDetailsValue(IExpressionDMContext variable) throws CoreException {
+               return getValueString(variable);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.formatter.AbstractVariableConverter#getSummaryValue(org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext)
+        */
+       protected String getSummaryValue(IExpressionDMContext variable) throws CoreException {
+               return getValueString(variable);
+       }
+
+       /**
+        * Gets the value string.
+        *
+        * @param variable the variable
+        * @return the value string
+        * @throws CoreException the core exception
+        */
+       protected String getValueString(IExpressionDMContext variable) throws CoreException {
+               IExpressions expressions = ((IEDCExpression) variable).getExpressionsService();
+               if (expressions == null)
+                       return ""; //$NON-NLS-1$
+               
+               StringBuilder sb = new StringBuilder();
+               List<IExpressionDMContext> children = getChildren(variable);
+               int i = 0;
+               for (IExpressionDMContext child : children) {
+                       IEDCExpression childExpression = (IEDCExpression) child;
+                       if (i < nameToFieldPaths.length)
+                               sb.append(nameToFieldPaths[i].getName());
+                       else
+                               sb.append(childExpression.getName());
+                       sb.append("="); //$NON-NLS-1$
+                       sb.append(FormatUtils.getVariableValue(childExpression));
+                       sb.append(" "); //$NON-NLS-1$
+                       i++;
+               }
+               return sb.toString();
+       }
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/AbstractStringFormatter.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/AbstractStringFormatter.java
new file mode 100644 (file)
index 0000000..5749848
--- /dev/null
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.services.IEDCExpression;
+import org.eclipse.cdt.debug.edc.symbols.IMemoryVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+
+/**
+ * Base class for string formatters.
+ */
+public abstract class AbstractStringFormatter implements IVariableFormatProvider {
+
+       /**
+        * Converter handles char* and wchar_t* strings terminated by a null character.
+        */
+       public class DefaultNullTerminatedStringConverter extends AbstractVariableConverter {
+               public DefaultNullTerminatedStringConverter(IType type, boolean forDetails) {
+                       super(type, forDetails);
+               }
+
+
+               @Override
+               protected String getDetailsValue(IExpressionDMContext variable) throws CoreException {
+                       return getValueString(variable);
+               }
+
+               @Override
+               protected String getSummaryValue(IExpressionDMContext variable) throws CoreException {
+                       return getValueString(variable);
+               }
+
+               private String getValueString(IExpressionDMContext variable) throws CoreException {
+                       IEDCExpression expressionDMC = (IEDCExpression) variable;
+                       expressionDMC.evaluateExpression();
+                       IType baseType = TypeUtils.getBaseType(expressionDMC.getEvaluatedType());
+                       int size = baseType.getByteSize();
+                       
+                       if (expressionDMC.getEvaluationError() != null)
+                               return expressionDMC.getEvaluationError().getMessage();
+                       
+                       // pointer living at null is not valid (e.g. inside a struct pointing to null)
+                       IVariableLocation exprLoc = expressionDMC.getEvaluatedLocation();
+                       if (exprLoc instanceof IMemoryVariableLocation && ((IMemoryVariableLocation) exprLoc).getAddress().isZero())
+                               return "0";
+
+                       int maximumLength = getMaximumLength();
+                       // limit to express char[] size if given
+                       if (expressionDMC.getEvaluatedType() instanceof IArrayType) {
+                               long boundLength = ((IArrayType)expressionDMC.getEvaluatedType()).getBound(0).getBoundCount();
+                               if (boundLength > 0) {
+                                       maximumLength = (int) Math.min(boundLength, maximumLength);
+                               }
+                       }
+                       
+                       Number value = expressionDMC.getEvaluatedValue();
+                       if (value == null) {
+                               if (expressionDMC.getEvaluatedValueString() != null) {
+                                       // already a string
+                                       // TODO: proper formatting
+                                       return '"' + expressionDMC.getEvaluatedValueString() + '"';
+                               }
+                               return null;
+                       }
+
+                       IAddress address = FormatUtils.getPointerValue(value);
+                       if (address == null) {
+                               return value.toString();                // dunno
+                       }
+                       
+                       // null pointer
+                       if (address.isZero())
+                               return "0";
+                       
+                       String formattedString = 
+                               FormatUtils.getFormattedNullTermString(variable, address, size, maximumLength);
+                       return quoteString(formattedString);
+               }
+
+               private String quoteString(String str) {
+                       StringBuilder sb = new StringBuilder("\"");
+                       sb.append(str);
+                       sb.append('\"');
+                       return sb.toString();
+               }
+       }
+
+       /**
+        * Override to change the maximum string length to format.
+        * @return size in characters
+        */
+       protected int getMaximumLength() {
+               IEclipsePreferences scope = InstanceScope.INSTANCE.getNode("org.eclipse.debug.ui");
+               return scope.getInt("org.eclipse.debug.ui.max_detail_length", 256);
+       }
+       
+       public ITypeContentProvider getTypeContentProvider(IType type) {
+               return null;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/AbstractVariableConverter.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/AbstractVariableConverter.java
new file mode 100644 (file)
index 0000000..12f86ba
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Abstract class implementing IVariableValueConverter with summary and detail variants
+ */
+public abstract class AbstractVariableConverter implements IVariableValueConverter {
+
+       protected IType type;
+       private boolean forDetails;
+       private int curValueLength;
+
+       public AbstractVariableConverter(IType type, boolean forDetails) {
+               this.forDetails = forDetails;
+               this.type = type;
+       }
+       
+       protected abstract String getDetailsValue(IExpressionDMContext variable) throws CoreException;
+
+       protected abstract String getSummaryValue(IExpressionDMContext variable) throws CoreException;
+       
+       public String getValue(IExpressionDMContext variable) throws CoreException {
+               if (forDetails)
+                       return getDetailsValue(variable);
+               return getSummaryValue(variable);
+       }
+       
+       /**
+        * @since 2.0
+        */
+       public void setCurValueLength(int curValueLength) {
+               this.curValueLength = curValueLength;
+       }
+       
+       /**
+        * @since 2.0
+        */
+       public int getCurValueLength() {
+               return curValueLength;
+       }
+
+       public boolean canEditValue() {
+               return false; // read-only implementation
+       }
+       
+       public String getEditableValue(IExpressionDMContext variable) throws CoreException {
+               return getValue(variable); // default - use same value
+       }
+       
+       public void setValue(IExpressionDMContext variable, String newValue) {
+               // read-only implementation
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/DefaultArrayFormatter.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/DefaultArrayFormatter.java
new file mode 100644 (file)
index 0000000..dad0dae
--- /dev/null
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import java.util.List;
+
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.IArrayDimensionType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.services.IEDCExpression;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+public class DefaultArrayFormatter implements IVariableFormatProvider {
+
+       public class DefaultArrayConverter extends AbstractVariableConverter {
+
+               private static final int STOP_LENGTH = 300; // stop adding items when string is this length
+
+               public DefaultArrayConverter(IType type, boolean forDetails) {
+                       super(type, forDetails);
+               }
+
+               @Override
+               protected String getSummaryValue(IExpressionDMContext variable) throws CoreException {
+                       IExpressions expressions = ((IEDCExpression) variable).getExpressionsService();
+                       if (expressions == null)
+                               return ""; //$NON-NLS-1$
+                       StringBuilder sb = new StringBuilder("[");
+                       List<IExpressionDMContext> children = FormatUtils.getAllChildExpressions(variable);
+                       boolean skip = true;
+                       for (IExpressionDMContext child : children) {
+                               if (skip)
+                                       skip = false;
+                               else
+                                       sb.append(", ");
+                               String customString = getCustomValueString(child, getCurValueLength() + sb.length());
+                               if (customString != null) {
+                                       sb.append('{');
+                                       sb.append(customString);
+                                       sb.append('}');
+                               }
+                               else {
+                                       IEDCExpression childExpression = (IEDCExpression) child;
+                                       sb.append(FormatUtils.getVariableValue(childExpression));
+                               }
+                               if (getCurValueLength() + sb.length() > STOP_LENGTH) {
+                                       if (!children.get(children.size() - 1).equals(child))
+                                               sb.append(", ...");
+                                       break;
+                               }
+                       }
+                       return sb.append(']').toString();
+               }
+
+               private String getCustomValueString(IExpressionDMContext variable, int curValueLength) throws CoreException {
+                       IVariableValueConverter converter = FormatUtils.getCustomValueConverter(variable);
+                       if (converter != null) {
+                               if (converter instanceof AbstractVariableConverter)
+                                       ((AbstractVariableConverter) converter).setCurValueLength(curValueLength);
+                               return converter.getValue(variable);
+                       }
+                       return null;
+               }
+
+               @Override
+               protected String getDetailsValue(IExpressionDMContext variable) throws CoreException {
+                       return getSummaryValue(variable);
+               }
+               
+       }
+
+       public static boolean handlesType(IType type) {
+               IType unqualifiedType = FormatUtils.getUnqualifiedTypeRemovePointers(type);
+               return unqualifiedType instanceof IArrayType
+                       || unqualifiedType instanceof IArrayDimensionType;
+       }
+
+       public ITypeContentProvider getTypeContentProvider(IType type) {
+               return null;
+       }
+       
+       public IVariableValueConverter getDetailValueConverter(IType type) {
+               if (handlesType(type))
+                       return new DefaultArrayConverter(type, true);
+               return null;
+       }
+
+       public IVariableValueConverter getVariableValueConverter(IType type) {
+               if (handlesType(type))
+                       return new DefaultArrayConverter(type, false);
+               return null;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/DefaultCStringFormatter.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/DefaultCStringFormatter.java
new file mode 100644 (file)
index 0000000..09bf72a
--- /dev/null
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.ConstType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IReferenceType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ITypedef;
+import org.eclipse.cdt.debug.edc.internal.symbols.VolatileType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+/**
+ * Handle char* and wchar_t* strings (ignoring const, volatile, and typedefs to char type).
+ */
+public class DefaultCStringFormatter extends AbstractStringFormatter {
+
+       public static boolean handlesType(IType type) {
+               if (type instanceof ICPPBasicType) {
+                       ICPPBasicType basicType = (ICPPBasicType) type;
+                       // NOTE: we may have neither signed nor unsigned set on a char*, and this is a "classic" string.
+                       // We would like to explicitly ignore "unsigned char*", since that's normally a byte buffer -- 
+                       // but RVCT incorrectly sets this flag for some instances of "char*" in source.
+                       boolean isCharString = /*!basicType.isUnsigned() &&*/ basicType.getBaseType() == ICPPBasicType.t_char;
+                       boolean isWcharTString = basicType.getBaseType() == ICPPBasicType.t_wchar_t || basicType.getName().equals("wchar_t");
+                       return isCharString || isWcharTString;
+               }
+               return false;
+       }
+
+       public ITypeContentProvider getTypeContentProvider(IType type) {
+               return null;
+       }
+       
+       public IVariableValueConverter getDetailValueConverter(IType type) {
+               IType basicType = getBasePointedType(type);
+               if (handlesType(basicType))
+                       return new DefaultNullTerminatedStringConverter(type, true);
+               
+               return null;
+       }
+
+       public IVariableValueConverter getVariableValueConverter(IType type) {
+               IType basicType = getBasePointedType(type);
+               if (handlesType(basicType))
+                       return new DefaultNullTerminatedStringConverter(type, false);
+               
+               return null;
+       }
+       
+
+       /**
+        * Get the basic unit type pointed to by a string (reducing, e.g.,
+        * "const char *const" to "char").  Also, handle typedefs (e.g. "gchar") and
+        * references (char &) to char.
+        * @param type
+        * @return basic unit type or <code>null</code> if not a pointer to basic type
+        */
+       protected IType getBasePointedType(IType type) {
+               // remove upper qualifiers
+               while (type instanceof ConstType || type instanceof VolatileType || type instanceof ITypedef || type instanceof IReferenceType)
+                       type = type.getType();
+               
+               // make sure it's a single pointer or a single-dimension array
+               if (type instanceof IPointerType)
+                       type = type.getType();
+               else if (type instanceof IArrayType && ((IArrayType) type).getBoundsCount() == 1)
+                       type = type.getType();
+               else
+                       return null;
+               
+               // remove inner qualifiers
+               while (type instanceof ConstType || type instanceof VolatileType || type instanceof ITypedef || type instanceof IReferenceType)
+                       type = type.getType();
+               if (!(type instanceof ICPPBasicType))
+                       return null;
+               return type;
+       }
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/DefaultCompositeFormatter.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/DefaultCompositeFormatter.java
new file mode 100644 (file)
index 0000000..8d3ef44
--- /dev/null
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import java.util.List;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.ICompositeType;
+import org.eclipse.cdt.debug.edc.services.IEDCExpression;
+import org.eclipse.cdt.debug.edc.symbols.IMemoryVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+public class DefaultCompositeFormatter implements IVariableFormatProvider {
+
+       public class DefaultCompositeConverter extends AbstractVariableConverter {
+               
+               private static final int MAX_DEPTH = 1; // stop recursing at this depth
+               private static final int STOP_LENGTH = 300; // stop adding items when string is this length
+
+               public DefaultCompositeConverter(IType type, boolean forDetails) {
+                       super(type, forDetails);
+               }
+
+               @Override
+               protected String getSummaryValue(IExpressionDMContext variable) throws CoreException {
+                       StringBuilder sb = new StringBuilder();
+                       addVariableFields(null, sb, variable, 0);
+                       if (sb.length() == 0) {
+                               // if debug information does not include child information,
+                               // return the already evaluated value
+                               if (variable instanceof IEDCExpression) {
+                                       IEDCExpression variableEDMC = (IEDCExpression)variable;
+                                       return variableEDMC.getEvaluatedValueString();
+                               }
+                       }
+                       return sb.toString();
+               }
+
+               private boolean hasNullLocation(IExpressionDMContext variable) throws CoreException {
+                       if (variable instanceof IEDCExpression) {
+                               FormatUtils.evaluateExpression((IEDCExpression) variable);
+                               IVariableLocation loc = ((IEDCExpression) variable).getEvaluatedLocation();
+                               if (loc instanceof IMemoryVariableLocation) {
+                                       if (((IMemoryVariableLocation) loc).getAddress().isZero()) {
+                                               return true;
+                                       }
+                               }
+                       }
+                       return false;
+               }
+
+               private void addVariableFields(String prefix, StringBuilder sb, IExpressionDMContext variable, int curDepth) throws CoreException {
+                       // if at null, don't try
+                       if (hasNullLocation(variable))
+                               return;
+                       
+                       if (prefix == null)
+                               prefix = ""; //$NON-NLS-1$
+                       List<IExpressionDMContext> childContexts = FormatUtils.getAllChildExpressions(variable);
+                       for (IExpressionDMContext child : childContexts) {
+                               IEDCExpression childExpression = (IEDCExpression) child;
+                               
+                               // if any child is at null, likely the struct is at null or crosses null, and is bad news
+                               if (hasNullLocation(childExpression)) {
+                                       continue;
+                               }
+                                       
+                               IVariableValueConverter customConverter = 
+                                       FormatUtils.getCustomValueConverter(child);
+                               if (customConverter != null &&
+                                               !(customConverter instanceof DefaultCompositeConverter)) {
+                                       sb.append(prefix);
+                                       sb.append(childExpression.getName());
+                                       sb.append("="); //$NON-NLS-1$
+                                       // for default array converter strings, don't surround in extra brackets
+                                       boolean isDefaultArrayConverter = 
+                                               customConverter instanceof DefaultArrayFormatter.DefaultArrayConverter;
+                                       if (!isDefaultArrayConverter)
+                                               sb.append("{");
+                                       if (customConverter instanceof AbstractVariableConverter)
+                                               ((AbstractVariableConverter) customConverter).setCurValueLength(getCurValueLength() + sb.length());
+                                       sb.append(customConverter.getValue(child));
+                                       if (!isDefaultArrayConverter)
+                                               sb.append("}");
+                                       sb.append(" ");
+                               }
+                               else {
+                                       IType evaluatedType = childExpression.getEvaluatedType();
+                                       IType unqualifiedType = FormatUtils.getUnqualifiedTypeRemovePointers(evaluatedType);
+                                       if (unqualifiedType instanceof ICompositeType) {
+                                               unqualifiedType = TypeUtils.getStrippedType(evaluatedType);
+                                               StringBuilder childPrefixSB = new StringBuilder(prefix);
+                                               String name = childExpression.getName();
+                                               if (name.startsWith("*")) {
+                                                       childPrefixSB.append('(');
+                                                       childPrefixSB.append(name);
+                                                       childPrefixSB.append(')');
+                                               } else
+                                                       childPrefixSB.append(name);
+                                               childPrefixSB.append(FormatUtils.getFieldAccessor(unqualifiedType));
+                                               if (curDepth < MAX_DEPTH)
+                                                       addVariableFields(childPrefixSB.toString(), sb, child, ++curDepth);
+                                               else {
+                                                       addSimpleChild(prefix, sb, childExpression);
+                                               }
+                                       }
+                                       else {
+                                               addSimpleChild(prefix, sb, childExpression);
+                                       }
+                               }
+                               
+                               if (getCurValueLength() + sb.length() > STOP_LENGTH) {
+                                       if (!childContexts.get(childContexts.size() - 1).equals(child))
+                                               sb.append("... ");
+                                       break;
+                               }
+                       }
+               }
+
+               private void addSimpleChild(String prefix, StringBuilder sb, IEDCExpression childExpression) {
+                       IExpressions expressions = childExpression.getExpressionsService();
+                       if (expressions == null)
+                               return;
+                       
+                       sb.append(prefix);
+                       sb.append(childExpression.getName());
+                       sb.append("="); //$NON-NLS-1$
+                       sb.append(FormatUtils.getVariableValue(childExpression));
+                       sb.append(" "); //$NON-NLS-1$
+               }
+
+               @Override
+               protected String getDetailsValue(IExpressionDMContext variable) throws CoreException {
+                       return getSummaryValue(variable);
+               }
+       }
+       
+       public static boolean handlesType(IType type) {
+               IType unqualifiedType = FormatUtils.getUnqualifiedTypeRemovePointers(type);
+               return unqualifiedType instanceof ICompositeType;
+       }
+
+       public ITypeContentProvider getTypeContentProvider(IType type) {
+               return null;
+       }
+       
+       public IVariableValueConverter getDetailValueConverter(IType type) {
+               if (handlesType(type))
+                       return new DefaultCompositeConverter(type, true);
+               
+               return null;
+       }
+
+       public IVariableValueConverter getVariableValueConverter(IType type) {
+               if (handlesType(type))
+                       return new DefaultCompositeConverter(type, false);
+               
+               return null;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/EDCFormatterMessages.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/EDCFormatterMessages.java
new file mode 100644 (file)
index 0000000..496c3ca
--- /dev/null
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import org.eclipse.osgi.util.NLS;
+
+public class EDCFormatterMessages extends NLS {
+       private static final String BUNDLE_NAME = "org.eclipse.cdt.debug.edc.formatter.EDCFormatterMessages"; //$NON-NLS-1$
+       public static String FormatUtils_CannotReadMemory;
+       static {
+               // initialize resource bundle
+               NLS.initializeMessages(BUNDLE_NAME, EDCFormatterMessages.class);
+       }
+
+       private EDCFormatterMessages() {
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/EDCFormatterMessages.properties b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/EDCFormatterMessages.properties
new file mode 100644 (file)
index 0000000..d5480c9
--- /dev/null
@@ -0,0 +1,11 @@
+###############################################################################
+# Copyright (c) 2010 Nokia and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Nokia - Initial API and implementation
+###############################################################################
+FormatUtils_CannotReadMemory=Cannot read memory at 0x{0}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/FormatUtils.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/FormatUtils.java
new file mode 100644 (file)
index 0000000..aeed5a6
--- /dev/null
@@ -0,0 +1,486 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.IArrayDimensionType;
+import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Expressions;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Memory;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICompositeType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IInheritance;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ITypedef;
+import org.eclipse.cdt.debug.edc.services.IEDCExpression;
+import org.eclipse.cdt.debug.edc.services.IEDCMemory;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.utils.Addr32;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.debug.core.model.MemoryByte;
+
+/**
+ * Utilities for generating formatters
+ * 
+ * Use of non-api IType in this class is provisional. IType will later move to a public package.
+ */
+public class FormatUtils {
+       
+       /** The Constant CLASS. */
+       private final static String CLASS = "class " ; //$NON-NLS-1$
+       
+       /** The Constant STRUCT. */
+       private final static String STRUCT = "struct "; //$NON-NLS-1$
+
+       /**
+        * Check type by name.
+        *
+        * @param type the type
+        * @param baseName the base name
+        * @return true, if successful
+        */
+       public static boolean checkTypeByName(IType type, String baseName) {
+               if (type == null)
+                       return false;
+               // we want to preserve typedefs to determine whether this is a type we support with a formatter
+               IType baseType = TypeUtils.getBaseTypePreservingTypedef(type);
+               
+               // check for someone making a typedef of what we're looking for
+               while (baseType != null && baseType instanceof ITypedef) {
+                       if (baseType.getName().equals(baseName))
+                               return true;
+                       baseType = TypeUtils.getBaseTypePreservingTypedef(baseType.getType());
+               }
+
+               if (baseType == null)
+                       return false;
+               
+               return checkName(baseType.getName(), baseName);
+       }
+       
+       /**
+        * Check name.
+        *
+        * @param typeName the type name
+        * @param baseName the base name
+        * @return true, if successful
+        */
+       public static boolean checkName(String typeName, String baseName) {
+               String checkName = typeName;
+               if (typeName.startsWith(CLASS))
+                       checkName = typeName.substring(CLASS.length()).trim();
+               else if (typeName.startsWith(STRUCT))
+                       checkName = typeName.substring(STRUCT.length()).trim();
+               return checkName.equals(baseName);
+       }
+       
+       
+       /**
+        * Check if the name of a class/struct, or one of the classes/structs it
+        * derives from, matches a given name.
+        * 
+        * @param type type of class/struct
+        * @param name type name to match against
+        * @return true if class/struct or inherited class/struct matches name,
+        * or null if no match
+        */
+       public static boolean checkClassOrInheritanceByName(IType type, String name) {
+               // strip off typedefs and type qualifiers, to look for classes and structs
+               type = TypeUtils.getBaseType(type);
+               
+               if (!(type instanceof ICompositeType))
+                       return false;
+               
+               ICompositeType composite = (ICompositeType)type;
+               
+               String baseName = composite.getBaseName();
+               
+               if (baseName.equals(name))
+                       return true;
+               
+               // if base name ends with a template size (e.g., "<15>"),
+               // match ignoring the value in the braces
+               if (baseName.indexOf('<') != -1) //$NON-NLS-1$
+                       if (baseName.matches(name + "<.*>$")) //$NON-NLS-1$
+                               return true;
+
+               // check classes and structs it derives from
+               for (IInheritance inheritance : composite.getInheritances()) {
+                       if (checkClassOrInheritanceByName(inheritance.getType(), name))
+                               return true;
+               }
+               
+               return false;
+       }
+
+       
+       /**
+        * Creates the sub expression.
+        *
+        * @param variable the variable
+        * @param name the name
+        * @param subExpressionStr the sub expression str
+        * @return the IExpressionDMContext for the sub expression.
+        */
+       public static IExpressionDMContext createSubExpression(IExpressionDMContext variable, String name, String subExpressionStr) {
+               IEDCExpression parentExpr = (IEDCExpression) variable;
+               IExpressions expressions = parentExpr.getExpressionsService();
+               if (expressions == null)
+                       return null;
+               String expressionStr = parentExpr.getExpression() + subExpressionStr;
+               IEDCExpression subExpression = (IEDCExpression) expressions.createExpression(parentExpr, expressionStr);
+               subExpression.setName(name);
+               return subExpression;
+       }
+       
+       /**
+        * Gets the formatted string.
+        *
+        * @param variable the variable
+        * @param address the address
+        * @param length the length
+        * @param charSize the char size
+        * @return the formatted string
+        * @throws CoreException the core exception
+        */
+       public static String getFormattedString(IExpressionDMContext variable, IAddress address, int length, int charSize)
+                       throws CoreException {
+               IEDCExpression expression = (IEDCExpression) variable;
+               StackFrameDMC frame = (StackFrameDMC) expression.getFrame();
+               IEDCMemory memory = frame.getEDCServicesTracker().getService(Memory.class);
+               
+               StringBuilder sb = new StringBuilder();
+               ArrayList<MemoryByte> buffer = new ArrayList<MemoryByte>();
+               IStatus status = memory.getMemory(frame.getExecutionDMC(), address, buffer, length * charSize, 1);
+               if (status.isOK()) {
+                       for (int i = 0; i < length * charSize; i++) {
+                               // make sure each byte is okay
+                               if (!buffer.get(i).isReadable())
+                                       throw EDCDebugger.newCoreException(
+                                                       MessageFormat.format(EDCFormatterMessages.FormatUtils_CannotReadMemory,
+                                                                               address.add(i).getValue().toString(16)));
+
+                               char c = (char) (buffer.get(i).getValue() & 0xff);
+                               if (charSize > 1) {
+                                       char c2 = (char) (buffer.get(++i).getValue() << 8);
+                                       c |= c2;
+                               }
+                               sb.append(c);
+                       }
+               }
+               return sb.toString();
+       }
+       
+       /**
+        * Gets the formatted null term string.
+        *
+        * @param variable the variable
+        * @param address the address
+        * @param charSize the char size
+        * @param maximumLength the maximum length
+        * @return the formatted null term string
+        * @throws CoreException the core exception
+        */
+       public static String getFormattedNullTermString(IExpressionDMContext variable, 
+                       IAddress address, int charSize,
+                       int maximumLength) throws CoreException {
+               IEDCExpression expression = (IEDCExpression) variable;
+               StackFrameDMC frame = (StackFrameDMC) expression.getFrame();
+               IEDCMemory memory = frame.getEDCServicesTracker().getService(Memory.class);
+               
+               StringBuilder sb = new StringBuilder();
+               ArrayList<MemoryByte> buffer = new ArrayList<MemoryByte>(64);// typical size of cache block
+               if (maximumLength == 0)
+                       maximumLength = 16384;  // somewhat arbitrary; if the user really wants more, the value can always be set higher
+               OUTER:while (maximumLength > 0) {
+                       int amount = Math.min(maximumLength, 64);// typical size of cache block
+                       IStatus status = memory.getMemory(frame.getExecutionDMC(), address, buffer, amount, charSize);
+                       if (status.isOK()) {
+                               // make sure each byte is okay
+                               for (int i = 0; i < buffer.size() && maximumLength > 0; ++i, --maximumLength) {
+                                       if (!buffer.get(i).isReadable())
+                                       {
+                                               if (i == 0)     // partial memory read success
+                                                       throw EDCDebugger.newCoreException(
+                                                                       MessageFormat.format(EDCFormatterMessages.FormatUtils_CannotReadMemory,
+                                                                                       address.add(i).getValue().toString(16)));
+                                               maximumLength = 0;
+                                               break OUTER;
+                                       }
+                                       char c = (char) buffer.get(i).getValue();
+                                       if (charSize > 1) {
+                                               char c2 = (char) (buffer.get(++i).getValue() << 8);
+                                               c |= c2;
+                                       }
+                                       if (c == '\0')
+                                               break OUTER;
+                                       sb.append(c);
+                                       address = address.add(charSize);
+                               }
+                       } else if (amount > 1) {
+                               maximumLength = Math.min(maximumLength, 64) / 2;
+                       } else {
+                               // Error in reading memory, bail out.  If we got more than one character,
+                               // use ellipsis, else fail.
+                               if (sb.length() == 0)
+                                       throw EDCDebugger.newCoreException(
+                                                       MessageFormat.format(EDCFormatterMessages.FormatUtils_CannotReadMemory,
+                                                                       address.getValue().toString(16)));
+                               maximumLength = 0;
+                               break;
+                       }
+                       buffer.clear();
+               }
+               if (maximumLength <= 0)
+                       sb.append("..."); //$NON-NLS-1$
+               
+               return sb.toString();
+       }
+
+       /**
+        * Find in collection by name.
+        *
+        * @param collection the collection
+        * @param name the name
+        * @return the i expression dm context
+        */
+       public static IExpressionDMContext findInCollectionByName(Collection<IExpressionDMContext> collection, String name) {
+               for (IExpressionDMContext context : collection) {
+                       if (((IEDCExpression) context).getName().equals(name))
+                               return context;
+               }
+               
+               return null;
+       }
+
+       /**
+        * Gets the all child expressions.
+        *
+        * @param variable the variable
+        * @return the all child expressions
+        */
+       public static List<IExpressionDMContext> getAllChildExpressions(IExpressionDMContext variable) {
+               
+               IEDCExpression variableDMC = (IEDCExpression) variable;
+               Expressions expressions = (Expressions) variableDMC.getExpressionsService();
+               if (expressions == null)
+                       return Collections.emptyList();
+               
+               List<IExpressionDMContext> kids = Arrays.<IExpressionDMContext>asList(
+                               expressions.getLogicalSubExpressions(variableDMC));
+               return kids;
+       }
+
+       /**
+        * Gets the field accessor.
+        *
+        * @param type the type
+        * @return the field accessor
+        */
+       public static String getFieldAccessor(IType type) {
+               if (type instanceof IPointerType)
+                       return "->"; //$NON-NLS-1$
+               return "."; //$NON-NLS-1$
+       }
+       
+       /**
+        * Gets the member value.
+        *
+        * @param variable the variable
+        * @param type the type
+        * @param memberName the member name
+        * @return the member value
+        */
+       public static String getMemberValue(IExpressionDMContext variable, IType type, String memberName) {
+               return getMemberValue(variable, type, memberName, IExpressions.NATURAL_FORMAT);
+       }
+
+       /**
+        * Gets the member value.
+        *
+        * @param variable the variable
+        * @param type the type
+        * @param memberName the member name
+        * @param format the format
+        * @return the member value
+        */
+       public static String getMemberValue(IExpressionDMContext variable, IType type, String memberName, String format) {
+               IExpressions expressions = ((IEDCExpression)variable).getExpressionsService();
+               if (expressions == null)
+                       return ""; //$NON-NLS-1$
+               IEDCExpression expression = 
+                       (IEDCExpression) expressions.createExpression(variable, variable.getExpression()
+                                       + FormatUtils.getFieldAccessor(type) + memberName);
+               FormattedValueDMContext fvc = expressions.getFormattedValueContext(expression, format);
+               return expression.getFormattedValue(fvc).getFormattedValue();
+       }
+
+       /**
+        * Gets the variable value.
+        *
+        * @param variable the variable
+        * @return the variable value
+        * @since 2.0
+        */
+       public static String getVariableValue(IExpressionDMContext variable) {
+               return getVariableValue(variable, IExpressions.NATURAL_FORMAT);
+       }
+
+       /**
+        * Gets the variable value.
+        *
+        * @param variable the variable
+        * @param format the format
+        * @return the variable value
+        * @since 2.0
+        */
+       public static String getVariableValue(IExpressionDMContext variable, String format) {
+               IExpressions expressions = ((IEDCExpression)variable).getExpressionsService();
+               FormattedValueDMContext fvc = 
+                       expressions.getFormattedValueContext(variable, format);
+               FormattedValueDMData formattedValue = ((IEDCExpression) variable).getFormattedValue(fvc);
+               return formattedValue.getFormattedValue();
+       }
+       
+       /**
+        * Gets the unqualified type remove pointers.
+        *
+        * @param type the type
+        * @return the unqualified type remove pointers
+        */
+       public static IType getUnqualifiedTypeRemovePointers(IType type) {
+               IType unqualifiedType = TypeUtils.getStrippedType(type);
+               while (unqualifiedType instanceof IPointerType)
+                       unqualifiedType = TypeUtils.getStrippedType(unqualifiedType.getType());
+               return unqualifiedType;
+       }
+
+       /**
+        * Gets the custom value converter.
+        *
+        * @param variable the variable
+        * @return the custom value converter
+        */
+       public static IVariableValueConverter getCustomValueConverter(IExpressionDMContext variable) {
+               IEDCExpression variableDMC = (IEDCExpression) variable;
+               variableDMC.evaluateExpression();
+               IType type = TypeUtils.getUnRefStrippedType(variableDMC.getEvaluatedType());
+               if (type instanceof IArrayDimensionType)
+                       type = ((IArrayDimensionType)type).getArrayType();
+               return FormatExtensionManager.instance().getVariableValueConverter(type);
+       }
+       
+       /**
+        * Get an address from an expression representing a pointer.
+        * @param value the evaluated value of an IEDCExpression
+        * @return the pointer address or <code>null</code>
+        */
+       public static IAddress getPointerValue(Number value) {
+               IAddress address = null;
+               
+               if (value instanceof BigInteger) {
+                       address = new Addr64((BigInteger) value);
+               } else {
+                       address = new Addr32(value.longValue());
+               }
+               return address;
+       }
+
+       /**
+        * Gets the template type name.
+        *
+        * @param typeName the type name
+        * @param type the type
+        * @return the template type name
+        * @since 2.0
+        */
+       public static String getTemplateTypeName(String typeName, IType type) {
+               // TODO Fix this when type gives template information Bug 11443
+               
+               ICompositeType composite = (ICompositeType) TypeUtils.getBaseType(type);
+               String baseName = composite.getBaseName();
+               
+               Matcher m = Pattern.compile(typeName + "<(.+)>").matcher(baseName);
+               if (m.matches())
+                       return m.group(1);
+
+               // check classes and structs it derives from
+               for (IInheritance inheritance : composite.getInheritances()) {
+                       String templateTypeName = getTemplateTypeName(typeName, inheritance.getType());
+                       if (templateTypeName != null)
+                               return templateTypeName;
+               }
+               
+               return null;
+       }
+       
+       /**
+        * Gets the formatted value.
+        *
+        * @param variable the variable
+        * @return the formatted value
+        * @throws CoreException the core exception
+        * @since 2.0
+        */
+       public static String getFormattedValue(IExpressionDMContext variable) throws CoreException {
+               IVariableValueConverter valueConverter = getCustomValueConverter(variable);
+               if (valueConverter != null) {
+                       return valueConverter.getValue(variable);
+               }
+               else
+                       return getVariableValue(variable);
+       }
+
+       /**
+        * Gets the max number of children.
+        *
+        * @return the max number of children
+        * @since 2.0
+        */
+       public static int getMaxNumberOfChildren() {
+               return 200; // this seems like a good default
+       }
+       
+       /**
+        * Evaluates the expression and throws a CoreException if there is an evaluation error.
+        *
+        * @param expression the expression
+        * @throws CoreException the core exception
+        * @since 2.0
+        */
+       public static void evaluateExpression(IEDCExpression expression) throws CoreException {
+               expression.evaluateExpression();
+               IStatus status = expression.getEvaluationError();
+               if ((status != null && !status.isOK()) || expression.getEvaluatedValue() == null) {
+                       Throwable t = status != null ? status.getException() : null;
+                       throw EDCDebugger.newDebugException("Error evaluating expression: " + expression.getExpression(), t);
+               }
+               
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/ITypeContentProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/ITypeContentProvider.java
new file mode 100644 (file)
index 0000000..7daaa46
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import java.util.Iterator;
+
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+
+
+/**
+ * An interface describing structure for a type
+ */
+public interface ITypeContentProvider {
+       
+       /**
+        * Return an iterator starting at a start index generating the
+        * list of IExpressionDMContext for each of the direct children 
+        * of the current object.
+        * @param variable IExpressionDMContext
+        * @return Iterator<IExpressionDMContext> 
+        * @throws CoreException on errors
+        */
+       Iterator<IExpressionDMContext> getChildIterator(IExpressionDMContext variable) throws CoreException;
+       
+       /**
+        * Return the number of children
+        * @param variable IExpressionDMContext
+        * @return int
+        * @throws CoreException on errors
+        * @since 2.0
+        */
+       int getChildCount(IExpressionDMContext variable) throws CoreException;
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/IVariableFormatProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/IVariableFormatProvider.java
new file mode 100644 (file)
index 0000000..367f318
--- /dev/null
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+/**
+ * Interface for an extension providing custom formatting for variables
+ */
+public interface IVariableFormatProvider {
+       /**
+        * An optional structure to use for this type
+        * @param type IType
+        * @return ITypeContentProvider
+        */
+       ITypeContentProvider getTypeContentProvider(IType type);
+       
+       /**
+        * An optional summary value to display in the value column for the current object.
+        * @param type IType
+        * @return IVariableValueConverter
+        */
+       IVariableValueConverter getVariableValueConverter(IType type);
+       
+       /**
+        * An optional string to display in the detail pane when the variable is selected
+        * @param type IType
+        * @return IVariableValueConverter
+        */
+       IVariableValueConverter getDetailValueConverter(IType type);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/IVariableValueConverter.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/formatter/IVariableValueConverter.java
new file mode 100644 (file)
index 0000000..7a8ece0
--- /dev/null
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.formatter;
+
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+
+/**
+ * Interface for converting displayed values and optionally editing converted value
+ */
+public interface IVariableValueConverter {
+       /**
+        * Return the formatted value.
+        * @param variable IExpressionDMContext
+        * @return String
+        * @throws CoreException any error on getting the value.
+        */
+       String getValue(IExpressionDMContext variable) throws CoreException;
+       
+       /**
+        * Whether the value is editable. 
+        * If false, {@link #setValue(String)} and {@link #getEditableValue(IExpressionDMContext)} may fail.
+        * @return boolean
+        */
+       boolean canEditValue();
+       
+       /**
+        * Return the formatted value for editing.
+        * @param variable IExpressionDMContext
+        * @return String
+        * @throws CoreException any error on getting the value.
+        */
+       String getEditableValue(IExpressionDMContext variable) throws CoreException;
+       
+       /**
+        * The value entered by the user to change the variable. 
+        * @param variable IExpressionDMContext
+        * @param newValue String
+        * @throws CoreException any error on setting the value.
+        */
+       void setValue(IExpressionDMContext variable, String newValue) throws CoreException;
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/ByteBufferStreamBuffer.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/ByteBufferStreamBuffer.java
new file mode 100644 (file)
index 0000000..2a4c29a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.io.IOException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+
+/**
+ * This implementation of IStreamBuffer works on an existing ByteBuffer.
+ */
+public class ByteBufferStreamBuffer extends StreamBufferBase {
+
+       private ByteBuffer buffer;
+       
+       
+       /**
+        * Wrap in-memory content.
+        * @param content
+        * @param order
+        */
+       public ByteBufferStreamBuffer(ByteBuffer buffer) throws IOException {
+               super(buffer.order(), 0, buffer.capacity());
+               this.buffer = buffer;
+       }
+       public ByteBufferStreamBuffer(ByteBuffer buffer, long position, long size) {
+               super(buffer.order(), position, size);
+               this.buffer = buffer;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.StreamBufferBase#fetchPage(byte[], int, int)
+        */
+       @Override
+       protected void fetchPage(byte[] buffer, long sourceOffset, int count) {
+               if (sourceOffset > Integer.MAX_VALUE)
+                       throw new BufferUnderflowException();
+               this.buffer.position((int) sourceOffset);
+               this.buffer.get(buffer, 0, count);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.StreamBufferBase#createSubBuffer(long, long)
+        */
+       @Override
+       protected IStreamBuffer createSubBuffer(long offset, long size) {
+               return new ByteBufferStreamBuffer(buffer, offset, size);
+       }
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCApplication.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCApplication.java
new file mode 100644 (file)
index 0000000..6920e72
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import org.eclipse.cdt.scripting.ScriptingPlugin;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+
+@SuppressWarnings("restriction")
+public class EDCApplication implements IApplication {
+
+       boolean running;
+       
+       public Object start(IApplicationContext context) throws Exception {
+               
+               running = true;
+       
+               IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(ScriptingPlugin.PLUGIN_ID);
+               prefs.putBoolean(ScriptingPlugin.SCRIPTING_ENABLED, true);
+
+               prefs = InstanceScope.INSTANCE.getNode(DebugPlugin.getUniqueIdentifier());
+               prefs.putBoolean(IInternalDebugCoreConstants.PREF_ENABLE_STATUS_HANDLERS, false);
+
+               ScriptingPlugin.getBundleContext();
+
+               while (running)
+               {
+                       Thread.sleep(1000);
+               }
+               
+               return null;
+       }
+
+       public void stop() {
+               running = false;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCDebugPreferenceInitializer.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCDebugPreferenceInitializer.java
new file mode 100644 (file)
index 0000000..5a78b25
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager;
+import org.eclipse.cdt.debug.edc.internal.snapshot.Album;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+
+public class EDCDebugPreferenceInitializer extends
+               AbstractPreferenceInitializer {
+
+       @Override
+       public void initializeDefaultPreferences() {
+               IEclipsePreferences node = DefaultScope.INSTANCE.getNode(EDCDebugger.PLUGIN_ID);
+               node.putInt(Album.PREF_VARIABLE_CAPTURE_DEPTH, 5);
+               node.put(Album.PREF_CREATION_CONTROL, Album.CREATE_MANUAL);
+               node.putBoolean(FormatExtensionManager.VARIABLE_FORMATS_ENABLED, FormatExtensionManager.VARIABLE_FORMATS_ENABLED_DEFAULT);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCDebugger.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCDebugger.java
new file mode 100644 (file)
index 0000000..5494bc0
--- /dev/null
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import org.eclipse.cdt.debug.edc.ITCFServiceManager;
+import org.eclipse.cdt.debug.edc.MessageLogger;
+import org.eclipse.cdt.debug.edc.tcf.extension.services.ILogging;
+import org.eclipse.cdt.debug.edc.tcf.extension.services.ISettings;
+import org.eclipse.cdt.debug.edc.tcf.extension.services.LoggingProxy;
+import org.eclipse.cdt.debug.edc.tcf.extension.services.SettingsProxy;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.osgi.service.debug.DebugOptions;
+import org.eclipse.osgi.service.debug.DebugTrace;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.protocol.Protocol.ChannelOpenListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+
+public class EDCDebugger extends Plugin {
+
+       // The plug-in ID
+       public static final String PLUGIN_ID = "org.eclipse.cdt.debug.edc"; //$NON-NLS-1$
+
+       // The shared instance
+       private static EDCDebugger plugin;
+
+       /** Platform facility used to trace. Lock {@link #traceLock} before accessing. */
+       private volatile DebugTrace trace;
+       
+       /** Serializes access to {@link #trace} */
+       private final String traceLock = new String("trace lock");
+
+    private ITCFServiceManager tcfServiceManager;
+    
+    private PersistentCache cache;
+
+    /** This plugin, once activated */
+       private BundleContext context;
+       
+       /**
+        * The constructor
+        */
+       public EDCDebugger() {
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.core.runtime.Plugin#start(org.osgi.framework.BundleContext)
+        */
+       @Override
+       public void start(BundleContext context) throws Exception {
+               super.start(context);
+               this.context = context;
+               plugin = this;
+
+               // Validate our plugin ID constant 
+               if (!getBundle().getSymbolicName().equals(PLUGIN_ID)) {
+                       throw new IllegalStateException("PLUGIN_ID constant is not correct"); //$NON-NLS-1$
+               }
+               
+               EDCTrace.init();
+               
+               installChannelListener();
+       }
+
+       private void installChannelListener() {
+
+               Protocol.invokeLater(new Runnable() {
+
+                       public void run() {
+                               Protocol.addChannelOpenListener(new ChannelOpenListener() {
+
+                                       public void onChannelOpen(IChannel channel) {
+                                               // logging service
+                                               if (channel.getRemoteService(ILogging.NAME) != null)
+                                                       channel.setServiceProxy(ILogging.class, new LoggingProxy(channel));
+                                               // settings service
+                                               if (channel.getRemoteService(ISettings.NAME) != null)
+                                                       channel.setServiceProxy(ISettings.class, new SettingsProxy(channel));
+                                               //
+                                       }
+                               });
+                       };
+               });
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
+        */
+       @Override
+       public void stop(BundleContext context) throws Exception {
+               if (cache != null)
+                       cache.flushAll();
+               plugin = null;
+               if (tcfServiceManager != null)
+                       ((TCFServiceManager) tcfServiceManager).shutdown();
+               super.stop(context);
+       }
+
+       /**
+        * Returns the shared instance
+        * 
+        * @return the shared instance
+        */
+       public static EDCDebugger getDefault() {
+               return plugin;
+       }
+
+       public static BundleContext getBundleContext() {
+               return getDefault().getBundle().getBundleContext();
+       }
+
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       public DebugTrace getTrace() {
+               synchronized (traceLock) {
+                       if (trace == null) {
+                               if (context == null) {
+                                       return null;    // Sorry, can't help. Bundle hasn't been activated yet
+                               }
+                               
+                               ServiceTracker tracker = new ServiceTracker(context, DebugOptions.class.getName(), null);
+                               tracker.open();
+                               DebugOptions debugOptions = (DebugOptions)tracker.getService();
+                               if (debugOptions != null) {
+                                       trace = debugOptions.newDebugTrace(getBundle().getSymbolicName());
+                               }
+                               tracker.close();
+                       }
+               }
+               return trace;
+       }
+
+       public ITCFServiceManager getServiceManager() {
+               if (tcfServiceManager == null) {
+                       tcfServiceManager = new TCFServiceManager();
+               }
+               return tcfServiceManager;
+       }
+
+       /**
+        * Utility method for creating a CoreException object with this EDC plugin
+        * ID.
+        * 
+        * @param msg
+        *            - error message.
+        * @param e
+        *            - cause exception, can be null.
+        * @return a {@link CoreException} object.
+        */
+       public static CoreException newCoreException(String msg, Throwable t) {
+               if ((msg == null || msg.length() == 0) && t instanceof CoreException)
+                       return new CoreException(((CoreException) t).getStatus());
+               else
+                       return new CoreException(new Status(IStatus.ERROR, PLUGIN_ID, msg, t));
+       }
+
+       /**
+        * Utility method for creating a CoreException object with this EDC plugin
+        * ID.
+        * 
+        * @param msg
+        *            - error message.
+        * @return a {@link CoreException} object.
+        */
+       public static CoreException newCoreException(String msg) {
+               return new CoreException(new Status(IStatus.ERROR, PLUGIN_ID, msg));
+       }
+
+       /**
+        * Utility method for creating a DebugException object with this EDC plugin
+        * ID.
+        * 
+        * @param msg
+        *            - error message.
+        * @param e
+        *            - cause exception, can be null.
+        * @return a {@link DebugException} object.
+        */
+       public static DebugException newDebugException(String msg, Throwable t) {
+               if ((msg == null || msg.length() == 0) && t instanceof CoreException)
+                       return new DebugException(((CoreException) t).getStatus());
+               else
+                       return new DebugException(new Status(IStatus.ERROR, PLUGIN_ID, msg, t));
+       }
+
+       /**
+        * Utility method for creating a DebugException object with this EDC plugin
+        * ID.
+        * 
+        * @param msg
+        *            - error message.
+        * @return a {@link DebugException} object.
+        */
+       public static DebugException newDebugException(String msg) {
+               return new DebugException(new Status(IStatus.ERROR, PLUGIN_ID, msg));
+       }
+
+       public static MessageLogger getMessageLogger() {
+               return new MessageLogger() {
+                       @Override
+                       public String getPluginID() {
+                               return PLUGIN_ID;
+                       }
+
+                       @Override
+                       public Plugin getPlugin() {
+                               return plugin;
+                       }
+               };
+       }
+
+       /**
+        * Returns the unique identifier of this plugin.
+        */
+       public static String getUniqueIdentifier() {
+               return PLUGIN_ID;
+       }
+
+       public static IStatus dsfRequestFailedStatus(String message, Throwable exception) {
+               return new Status(IStatus.ERROR, PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, message, exception);
+       }
+
+       public PersistentCache getCache() {
+               if (cache == null) {
+                       cache = new PersistentCache(getStateLocation().append("cached_data"));
+               }
+               return cache;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCTrace.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/EDCTrace.java
new file mode 100644 (file)
index 0000000..3bb5586
--- /dev/null
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ * Freescale Semiconductor - Refactoring and improvements
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.service.debug.DebugTrace;
+
+/**
+ * Tracing of EDC code based on standard tracing mechanism in eclipse;
+ * <br>see
+ * <a href=http://wiki.eclipse.org/FAQ_How_do_I_use_the_platform_debug_tracing_facility%3F>
+ * How do I use the Platform debug tracing facility?</a>
+ */
+public class EDCTrace {
+
+       // The various tracing options. DEBUG_TRACE is a master shut-on/off valve
+       public static final String DEBUG_TRACE = "/debug";
+       public static final String RUN_CONTROL_TRACE = "/debug/runControl";
+       public static final String STACK_TRACE = "/debug/stack";
+       public static final String EXPRESSION_PARSE_TRACE = "/debug/expressionParse";
+       public static final String SYMBOL_READER_TRACE = "/debug/symbolReader";
+       public static final String SYMBOL_READER_VERBOSE_TRACE = "/debug/symbolReader/verbose";
+       public static final String VARIABLE_VALUE_TRACE = "/debug/variableValue";
+       public static final String BREAKPOINTS_TRACE = "/debug/breakpoints";
+       public static final String MEMORY_TRACE = "/debug/memory";
+       public static final String ACPM_TRACE = "/debug/acpm";
+       public static final String PERSISTENT_CACHE_TRACE = "/debug/persistentCache";
+
+       // In order to minimize trace overhead when tracing is off, we check these
+       // "globals". They are set at plugin initialization time. Note that they do
+       // not preclude dynamic toggling of the trace options. Toggling would
+       // require dedicated GUI in any case. We would just have to have a pref
+       // change listener that toggles the values of these fields (note that they
+       // are not 'final').
+       public static boolean DEBUG_TRACE_ON;
+       public static boolean RUN_CONTROL_TRACE_ON;
+       public static boolean STACK_TRACE_ON;
+       public static boolean EXPRESSION_PARSE_TRACE_ON;
+       public static boolean SYMBOL_READER_TRACE_ON;
+       public static boolean SYMBOL_READER_VERBOSE_TRACE_ON;
+       public static boolean VARIABLE_VALUE_TRACE_ON;
+       public static boolean BREAKPOINTS_TRACE_ON;
+       public static boolean MEMORY_TRACE_ON;
+       public static boolean ACPM_TRACE_ON;
+       public static boolean PERSISTENT_CACHE_TRACE_ON;
+
+       /**
+        * Returns whether the specific tracing option is on. The answer is based on
+        * the real-time state of options as managed by the platform, whereas our
+        * XXXXX_ON static fields provide the answer based on the state of the
+        * options at plugin initialization time. Since we currently provide the
+        * user no way to toggle the options after launching Eclipse, use of this
+        * method is a heavy and unnecessary alternative to just checking the static
+        * field--thus the private visibility.
+        */
+       private static boolean isOn(String option) {
+               return "true".equals(Platform.getDebugOption(EDCDebugger.PLUGIN_ID + option)); 
+       }
+       
+       /**
+        * Sets up static booleans at plugin startup time for efficient trace checks.
+        */
+       public static void init() {
+               if ("true".equals(Platform.getDebugOption(EDCDebugger.PLUGIN_ID + "/debug"))) {  //$NON-NLS-1$//$NON-NLS-2$
+                       DEBUG_TRACE_ON = true;
+                       RUN_CONTROL_TRACE_ON = isOn(EDCTrace.RUN_CONTROL_TRACE);
+                       STACK_TRACE_ON = isOn(EDCTrace.STACK_TRACE);
+                       EXPRESSION_PARSE_TRACE_ON = isOn(EDCTrace.EXPRESSION_PARSE_TRACE);
+                       SYMBOL_READER_TRACE_ON = isOn(EDCTrace.SYMBOL_READER_TRACE);
+                       SYMBOL_READER_VERBOSE_TRACE_ON = SYMBOL_READER_TRACE_ON && isOn(EDCTrace.SYMBOL_READER_VERBOSE_TRACE);
+                       VARIABLE_VALUE_TRACE_ON = isOn(EDCTrace.VARIABLE_VALUE_TRACE);
+                       BREAKPOINTS_TRACE_ON = isOn(EDCTrace.BREAKPOINTS_TRACE);
+                       MEMORY_TRACE_ON = isOn(EDCTrace.MEMORY_TRACE);
+                       ACPM_TRACE_ON = isOn(EDCTrace.ACPM_TRACE);
+                       PERSISTENT_CACHE_TRACE_ON = isOn(EDCTrace.PERSISTENT_CACHE_TRACE);
+               }
+       }
+
+       static class NullDebugTrace implements DebugTrace {
+               public void trace(String option, String message) {}
+               public void trace(String option, String message, Throwable error) {}
+               public void traceDumpStack(String option) {}
+               public void traceEntry(String option) {}
+               public void traceEntry(String option, Object methodArgument) {}
+               public void traceEntry(String option, Object[] methodArguments) {}
+               public void traceExit(String option) {}
+               public void traceExit(String option, Object result) {}
+       };
+
+       private static DebugTrace sTrace;
+
+       public static String fixArg(Object argument) {
+               if (argument == null || sTrace instanceof NullDebugTrace)
+                       return null;
+               return argument.toString().replaceAll("\\{", "[").replaceAll("\\}", "]");
+       }
+
+       public static String[] fixArgs(Object[] arguments) {
+               if (arguments == null || sTrace instanceof NullDebugTrace)
+                       return null;
+               String[] args = new String[arguments.length];
+               for (int i = 0; i < arguments.length; i++) {
+                       args[i] = fixArg(arguments[i]);
+               }
+               return args;
+       }
+
+       public static DebugTrace getTrace() {
+               if (sTrace == null) {
+                       EDCDebugger activator = EDCDebugger.getDefault();
+                       if (activator != null) {
+                               sTrace = activator.getTrace();
+                       }
+                       else
+                               sTrace = new NullDebugTrace();
+               }
+               return sTrace;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/ExecutablesSourceContainer.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/ExecutablesSourceContainer.java
new file mode 100644 (file)
index 0000000..627df24
--- /dev/null
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - Initial implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.io.File;
+import java.util.Collection;
+
+import org.eclipse.cdt.debug.core.executables.Executable;
+import org.eclipse.cdt.debug.core.executables.ExecutablesManager;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.debug.core.sourcelookup.ISourceContainerType;
+import org.eclipse.debug.core.sourcelookup.containers.AbstractSourceContainer;
+import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
+
+public class ExecutablesSourceContainer extends AbstractSourceContainer {
+
+       public static final String TYPE_ID = EDCDebugger.getUniqueIdentifier() + ".containerType.executables";   //$NON-NLS-1$
+
+       public Object[] findSourceElements(String name) throws CoreException {
+               IPath path = PathUtils.findExistingPathIfCaseSensitive(PathUtils.createPath(name));
+               // Now looking for the file in executable view.
+               //
+               // Between the SDK and target, the exact directory and file capitalization may differ.
+               //
+               // Inject required initial slash so we can confidently use String#endsWith() without
+               // matching, e.g. "/path/to/program.exe" with "ram.exe".
+               //
+               String slashAndLowerFileName = File.separator + path.lastSegment().toLowerCase();
+               String absoluteLowerPath = path.makeAbsolute().toOSString().toLowerCase();
+               
+               // Note the 'wait=true' argument.  We can wait now that this job does not lock the UI.  
+               Collection<Executable> executables = ExecutablesManager.getExecutablesManager().getExecutables(true);
+               for (Executable e : executables) {
+                       String p = e.getPath().makeAbsolute().toOSString().toLowerCase();
+                       if (p.endsWith(absoluteLowerPath) || // stricter match first
+                               p.endsWith(slashAndLowerFileName)) // then only check by name
+                       {
+                               return new LocalFileStorage[] { new LocalFileStorage(e.getPath().toFile()) };
+                       }
+               }
+               return new Object[]{};
+       }
+
+       public String getName() {
+               return "Executables";
+       }
+
+       public ISourceContainerType getType() {
+               return getSourceContainerType( TYPE_ID );
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/FileStreamBuffer.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/FileStreamBuffer.java
new file mode 100644 (file)
index 0000000..9c76fd5
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteOrder;
+
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+
+/**
+ * This implementation of IStreamBuffer works on file content.
+ */
+public class FileStreamBuffer extends StreamBufferBase {
+       private final boolean DEBUG = false;
+       private RandomAccessFile file;
+       
+       
+       /**
+        * Wrap in-memory content.
+        * @param content
+        * @param order
+        */
+       public FileStreamBuffer(RandomAccessFile file, ByteOrder order) throws IOException {
+               super(order, 0, file.length());
+               this.file = file;
+       }
+       public FileStreamBuffer(RandomAccessFile file, ByteOrder order, long position, long size) {
+               super(order, position, size);
+               this.file = file;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.StreamBufferBase#fetchPage(byte[], int, int)
+        */
+       @Override
+       protected void fetchPage(byte[] buffer, long sourceOffset, int count) {
+               try {
+                       if (DEBUG) System.out.print("Reading "+ sourceOffset + " x "+ count + "... ");
+                       file.seek(sourceOffset);
+                       file.read(buffer, 0, count);
+                       if (DEBUG) System.out.println("done");
+               } catch (IOException e) {
+                       BufferUnderflowException be = new BufferUnderflowException();
+                       be.initCause(e);
+                       throw be;
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.StreamBufferBase#createSubBuffer(long, long)
+        */
+       @Override
+       protected IStreamBuffer createSubBuffer(long offset, long size) {
+               return new FileStreamBuffer(file, order, offset, size);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/HostOS.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/HostOS.java
new file mode 100644 (file)
index 0000000..3d3d4f9
--- /dev/null
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.io.File;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+
+/**
+ * Utilities used for portability between hosts.
+ */
+public class HostOS {
+       /** Is the host Windows? */
+       public static boolean IS_WIN32 = File.separatorChar == '\\';
+       /** Is the host some Unix variant? */
+       public static boolean IS_UNIX = File.separatorChar == '/';
+       /** Executable file extension */
+       public static final String EXE_EXT = IS_WIN32 ? ".exe" : "";
+       
+       /**
+        * Ensure that the executable name mentioned is canonical for the machine.
+        * This only affects Windows, currently, ensuring that an ".exe" is attached.
+        * @param executablePath
+        * @return updated path
+        */
+       public static String canonicalizeExecutableName(String executable) {
+               if (IS_WIN32) {
+                       IPath executablePath = new Path(executable);
+                       String ext = executablePath.getFileExtension();
+                       if (ext == null) {
+                               executable += EXE_EXT;
+                       }
+               }
+               return executable;
+       }
+
+       /**
+        * Scan the PATH variable and see if the given binary is visible on
+        * the PATH that will be used at runtime (with the default environment and overrides).
+        * @param pathValue the expected Path 
+        * @param program
+        * @return IPath if program is on PATH, else <code>null</code>
+        */
+       public static IPath findProgramOnPath(String program, String pathValue) {
+               
+               // be sure proper path/extension are present
+               program = HostOS.canonicalizeExecutableName(program);
+               
+               IPath path = null;
+               
+               IPath[] pathEntries = PathUtils.getPathEntries(pathValue);
+               for (IPath pathEntry : pathEntries) {
+                       IPath testPath = pathEntry.append(program);
+                       if (testPath.toFile().exists()) {
+                               path = testPath;
+                               break;
+                       }
+               }
+               
+               return path;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/IMemoryAccess.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/IMemoryAccess.java
new file mode 100644 (file)
index 0000000..658ca69
--- /dev/null
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal;
+
+import org.eclipse.cdt.debug.edc.services.IEDCExecutionDMC;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.debug.core.model.MemoryByte;
+
+/**
+ * @author Administrator
+ * @since 2.0
+ *
+ */
+public interface IMemoryAccess {
+
+       /**
+        * Retrieves the memory address values as shown at the Hex Pane Memory
+        * View. Every cell has 4 bytes.
+        * @param contextId string representing the context of for the memory
+        * @param memoryAddress The memory address to get its values.
+        * @param length the amount of memory to retrieve
+        * @return An array of memory bytes starting from the memory address given.
+        * @throws Exception Any exception is propagated to the caller.
+        */
+       public MemoryByte[] getMemoryValues(final DsfSession session,
+                       final IEDCExecutionDMC exe_dmc, final String memoryAddress,
+                       final int length)
+               throws Exception;
+
+       /**
+        * Changes the memory value for the given memory address for the length of the array
+        * @param contextId string representing the context of for the memory
+        * @param memoryAddress The memory address which content will be changed.
+        * @param newMemoryValue The new value of the memory address content.
+        * @return True if the change was successful. False if the value couldn't be changed.
+        * @throws Exception Any exception will be propagated to the caller.
+        */
+       public boolean changeMemoryValue(final DsfSession session,
+                       final IEDCExecutionDMC exe_dmc, final String memoryAddress,
+                       final byte[] newMemoryValue)
+               throws Exception;
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/MemoryStreamBuffer.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/MemoryStreamBuffer.java
new file mode 100644 (file)
index 0000000..9c581ec
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.nio.ByteOrder;
+
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+
+/**
+ * This implementation of IStreamBuffer works on memory content.
+ */
+public class MemoryStreamBuffer extends StreamBufferBase {
+
+       private byte[] content;
+
+       
+       /**
+        * Wrap in-memory content.
+        * @param content
+        * @param order
+        */
+       public MemoryStreamBuffer(byte[] content, ByteOrder order) {
+               super(order, 0, content.length);
+               this.content = content;
+       }
+       public MemoryStreamBuffer(byte[] content, ByteOrder order, long position, long size) {
+               super(order, position, size);
+               this.content = content;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.StreamBufferBase#fetchPage(byte[], int, int)
+        */
+       @Override
+       protected void fetchPage(byte[] buffer, long sourceOffset, int count) {
+               System.arraycopy(content, (int) sourceOffset, buffer, 0, count);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.StreamBufferBase#createSubBuffer(long, long)
+        */
+       @Override
+       protected IStreamBuffer createSubBuffer(long offset, long size) {
+               return new MemoryStreamBuffer(content, order, offset, size);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/NumberFormatUtils.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/NumberFormatUtils.java
new file mode 100644 (file)
index 0000000..17ff813
--- /dev/null
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+
+public class NumberFormatUtils {
+
+       private static final String HEX_PREFIX = "0x"; //$NON-NLS-1$
+
+       private static final String OCTAL_PREFIX = "0"; //$NON-NLS-1$
+
+       private static final String BINARY_PREFIX = "0b"; //$NON-NLS-1$
+
+       private static final String SINGLE_QUOTE = "'"; //$NON-NLS-1$
+
+       private static final String DECIMAL_SUFFIX = " (Decimal)"; //$NON-NLS-1$
+
+       static public String toHexString(Number number) {
+               String str = null;
+               if (number instanceof Integer)
+                       str = Integer.toHexString((Integer) number);
+               else if (number instanceof Long)
+                       str = Long.toHexString((Long) number);
+               else if (number instanceof BigInteger)
+                       str = ((BigInteger) number).toString(16);
+               else if (number instanceof Float)
+                       str = Float.toHexString((Float) number);
+               else if (number instanceof Double)
+                       str = Double.toHexString((Double) number);
+               if (str != null && !str.startsWith(HEX_PREFIX))
+                       return HEX_PREFIX + str;
+               return str;
+       }
+
+       static public String toOctalString(Number number) {
+               String str = null;
+               if (number instanceof Integer)
+                       str = Integer.toOctalString((Integer) number);
+               else if (number instanceof Long)
+                       str = Long.toOctalString((Long) number);
+               else if (number instanceof BigInteger)
+                       str = ((BigInteger) number).toString(8);
+               if (str != null && !str.startsWith(OCTAL_PREFIX))
+                       str = OCTAL_PREFIX + str;
+               if (str == null && (number instanceof Float || number instanceof Double))
+                       str = number.toString() + DECIMAL_SUFFIX;
+               return str;
+       }
+
+       static public String asBinary(Number number) {
+               String str = null;
+               if (number instanceof Integer)
+                       str = Integer.toBinaryString((Integer) number);
+               else if (number instanceof Long)
+                       str = Long.toBinaryString((Long) number);
+               else if (number instanceof BigInteger)
+                       str = ((BigInteger) number).toString(2);
+               if (str != null && !str.startsWith(BINARY_PREFIX))
+                       str = BINARY_PREFIX + str;
+               if (str == null && (number instanceof Float || number instanceof Double))
+                       str = number.toString() + DECIMAL_SUFFIX;
+               return str;
+       }
+
+       static public String toCharString(Number number, IType valueType) {
+               int intValue = number.intValue();
+               String charVal = null;
+               if (intValue < 128) {
+                       switch ((char) intValue) {
+                               case 0:
+                                       charVal = ("\\0"); //$NON-NLS-1$
+                                       break;
+                               case '\b':
+                                       charVal = ("\\b"); //$NON-NLS-1$
+                                       break;
+                               case '\f':
+                                       charVal = ("\\f"); //$NON-NLS-1$
+                                       break;
+                               case '\n':
+                                       charVal = ("\\n"); //$NON-NLS-1$
+                                       break;
+                               case '\r':
+                                       charVal = ("\\r"); //$NON-NLS-1$
+                                       break;
+                               case '\t':
+                                       charVal = ("\\t"); //$NON-NLS-1$
+                                       break;
+                               case '\'':
+                                       charVal = ("\\'"); //$NON-NLS-1$
+                                       break;
+                               case '\"':
+                                       charVal = ("\\\""); //$NON-NLS-1$
+                                       break;
+                               case '\\':
+                                       charVal = ("\\\\"); //$NON-NLS-1$
+                                       break;
+                               case 0xb:
+                                       charVal = ("\\v"); //$NON-NLS-1$
+                                       break;
+                       }
+               }
+       
+               // Show the numeric value (decimal for char, since it's short, and hex for wchar_t)
+               // then the character value.  Note that at the system font may not be able to show
+               // all characters in the variables/expressions view, which is why we show the 
+               // more meaningful numeric value before the possibly "boxy" character representation.
+               //
+               // Also, we assume wchar_t == Unicode.
+               boolean isWchart = (valueType instanceof ICPPBasicType 
+                       && ((ICPPBasicType) valueType).getBaseType() == ICPPBasicType.t_wchar_t)
+                        || valueType.getName().equals("wchar_t"); //$NON-NLS-1$
+               
+               StringBuilder info = new StringBuilder();
+       
+               if (isWchart) {
+                       info.append(HEX_PREFIX);
+                       if (valueType.getByteSize() == 2)
+                               info.append(String.format("%04X", intValue)); //$NON-NLS-1$
+                       else
+                               info.append(String.format("%08X", intValue)); //$NON-NLS-1$
+                       info.append(" (L"); //$NON-NLS-1$
+               } else {
+                       info.append("" + intValue); //$NON-NLS-1$
+                       info.append(" ("); //$NON-NLS-1$
+               }
+       
+               if (charVal == null) {
+                       // treat chars as unsigned for getting the char representation
+                       String fmt = "\\U%08X"; //$NON-NLS-1$
+                       switch (valueType.getByteSize()) {
+                       case 1:
+                               fmt = "\\%03o"; //$NON-NLS-1$
+                               intValue &= 0xff; break;
+                       case 2:
+                               fmt = "\\u%04X"; //$NON-NLS-1$
+                               intValue &= 0xffff; break;
+                       case 4:
+                               // note: may still be too large to be legal
+                               fmt = "\\U%08X"; //$NON-NLS-1$
+                               intValue &= 0xffffffff; break;
+                       }
+                       
+                       boolean gotRepr = false;
+                       try {
+                               if (!Character.isISOControl(intValue)) {
+                                       char[] chars = Character.toChars(intValue);
+                                       info.append(asStringQuoted(new String(chars)));
+                                       gotRepr = true;
+                               }
+                       } catch (IllegalArgumentException e) {
+                               // some character values are negative or outside the UCS range;
+                               // these throw exceptions
+                       }
+                       if (!gotRepr) {
+                               info.append(asStringQuoted(String.format(fmt, intValue)));
+                       }
+               } else {
+                       info.append(asStringQuoted(charVal));
+               }
+               info.append(')');
+               
+               return info.toString();
+       }
+
+       static public String asStringQuoted(String val) {
+               StringBuilder sb = new StringBuilder(SINGLE_QUOTE);
+               sb.append(val);
+               sb.append(SINGLE_QUOTE);
+               return sb.toString();
+       }
+
+       static public BigInteger parseIntegerByFormat(String expressionValue, String formatId) {
+               int radix = 10;
+               if (IFormattedValues.HEX_FORMAT.equals(formatId)) {
+                       if (expressionValue.startsWith(HEX_PREFIX)) 
+                               expressionValue = expressionValue.substring(HEX_PREFIX.length());
+                       radix = 16;
+               } else if (IFormattedValues.OCTAL_FORMAT.equals(formatId)) {
+                       if (expressionValue.startsWith(OCTAL_PREFIX)) 
+                               expressionValue = expressionValue.substring(OCTAL_PREFIX.length()); 
+                       radix = 8;
+               } else if (IFormattedValues.BINARY_FORMAT.equals(formatId)) {
+                       if (expressionValue.startsWith(BINARY_PREFIX)) 
+                               expressionValue = expressionValue.substring(BINARY_PREFIX.length()); 
+                       radix = 2;
+               } else if (IFormattedValues.NATURAL_FORMAT.equals(formatId)) {
+                       if (expressionValue.startsWith(BINARY_PREFIX)) {
+                               expressionValue = expressionValue.substring(BINARY_PREFIX.length());
+                               radix = 2;
+                       } else if (expressionValue.startsWith(OCTAL_PREFIX)) { 
+                               expressionValue = expressionValue.substring(OCTAL_PREFIX.length());
+                               radix = 8;
+                       } else if (expressionValue.startsWith(HEX_PREFIX)) { 
+                               expressionValue = expressionValue.substring(HEX_PREFIX.length());
+                               radix = 16;
+                       } 
+                       // else, decimal
+               }
+        try {
+               return new BigInteger(expressionValue, radix);
+        } catch (NumberFormatException e) {
+               // just return null
+        }
+        
+        return null;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/PathUtils.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/PathUtils.java
new file mode 100644 (file)
index 0000000..31ec0f1
--- /dev/null
@@ -0,0 +1,273 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+/**
+ * These utilities handle some common portability issues when dealing with
+ * (absolute) paths which may be in a format intended for another operating system.  
+ * It also handles shortcomings in the org.eclipse.core.runtime.Path
+ * implementation, which is not able to construct a meaningful path from
+ * a Win32 path outside of Windows.
+ */
+public class PathUtils {
+
+       /**
+        * Convert a variable constructed blindly for a Win32 environment into
+        * Unix-like syntax.  This is typically used for PATH or lists
+        * of paths where ';' is the entry separator and '\' is the 
+        * path component separator.
+        * <p>
+        * NOTE: we assume that the entries in the
+        * path list are already legal Unix paths, but just with the
+        * wrong slash.
+        * @param env
+        * @return converted string
+        */
+       public static String convertPathListToUnix(String env) {
+               if (env == null) return null;
+               env = env.replaceAll(";", ":");  // entry separators
+               env = env.replaceAll("\\\\", "/");  // path separators
+               return env;
+       }
+
+       /**
+        * Convert a path constructed blindly for a Win32 environment into
+        * Unix-like syntax.  <p>
+        * NOTE: we assume that the path is already a legal Unix path, 
+        * but just with the wrong slash.
+        * @param file
+        * @return converted string
+        */
+       public static String convertPathToUnix(String file) {
+               if (file == null) return null;
+               // handle Windows slashes and canonicalize
+               file = file.replaceAll("\\\\", "/");
+               return file;
+       }
+
+       /**
+        * Convert a path which may be in Windows or Unix format to Windows format.
+        * NOTE: we assume that the path is already a legal path, 
+        * but just with the wrong slash.
+        * @param file
+        * @return converted string
+        */
+       public static String convertPathToWindows(String file) {
+               if (file == null) return null;
+               file = file.replaceAll("/", "\\\\");
+               return file;
+       }
+
+       /**
+        * Convert a path which may be in Windows or Unix format to Windows format.
+        * NOTE: we assume that the path is already a legal path, 
+        * but just with the wrong slash.
+        * @param file
+        * @return converted string
+        */
+       public static String convertPathToWindows(IPath path) {
+               return convertPathToWindows(path.toPortableString());
+       }
+
+       /**
+        * Convert a path which may be in the opposite slash format to the local slash format.
+        * NOTE: we assume that the path is already a legal path, 
+        * but just with the wrong slash.
+        * @param file
+        * @return converted string
+        */
+       public static String convertPathToNative(String path) {
+               if (path == null) return null;
+               if (HostOS.IS_UNIX)
+                       return path.replaceAll("\\\\", "/");
+               else
+                       return path.replaceAll("/", "\\\\");
+       }
+
+       /**
+        * Create an IPath from a string which may be a Win32 path. <p>
+        * <p>
+        * ("new Path(...)" won't work in Unix when using a Win32 path: the backslash
+        * separator and the device notation are completely munged.)
+        * @param path
+        * @return converted string
+        */
+       public static IPath createPath(String path) {
+               if (path == null) return null;
+               boolean hasWindowsSlashes = path.contains("\\");
+               if (hasWindowsSlashes) {
+                       // handle Windows slashes and canonicalize
+                       path = path.replaceAll("\\\\", "/");
+               }
+               
+               // also check for device or UNC
+               int idx = path.indexOf(":");
+               if (idx > 0) {
+                       String device = path.substring(0, idx + 1);
+                       path = path.substring(idx + 1);
+                       return new Path(path).setDevice(device);
+               } 
+               else {
+                       // Cygwin or UNC path
+                       if (path.startsWith("//") && !hasWindowsSlashes) {
+                               String network;
+                               idx = path.indexOf("/", 2);
+                               if (idx > 0) {
+                                       network = path.substring(0, idx);
+                                       path = path.substring(idx);
+                               } else {
+                                       network = path;
+                                       path = "";
+                               }
+                               return new Path(network, path).makeUNC(true);
+                       }
+               }               
+               
+               // fallthrough
+               return new Path(path);
+       }
+
+       /**
+        * Get the PATH entries from the given path environment value or the
+        * system environment.
+        * @param pathValue the expected PATH/Path value, or <code>null</code> for the system value
+        * @return array of IPath, never <code>null</code>
+        */
+       public static IPath[] getPathEntries(String pathValue) {
+               String pathVar = null;
+               if (pathValue != null) {
+                       pathVar = pathValue;
+               } else {
+                       if (HostOS.IS_WIN32) {
+                               // canonical name, plus fallback below
+                               pathVar = System.getenv("Path"); //$NON-NLS-1$
+                       }
+                       if (pathVar == null) {
+                               pathVar = System.getenv("PATH"); //$NON-NLS-1$
+                       }
+               }
+               
+               if (pathVar == null)
+                       pathVar = "";
+               
+               String pathSeparator = System.getProperty("path.separator");
+               String[] pathEntries = pathVar.split(pathSeparator);
+               IPath[] paths = new IPath[pathEntries.length];
+               for (int i = 0; i < pathEntries.length; i++) {
+                       paths[i] = new Path(pathEntries[i]);
+               }
+               return paths;
+       }
+
+       /**
+        * If the filesystem is case sensitive, locate the file on the filesystem 
+        * on the given path, by ignoring case sensitivity differences.  
+        * This is needed on case-preserving but not case-insensitive filesystems.
+        * @param path 
+        * @return path pointing to existing file (possibly with different case in components) or
+        * original path if there is no match
+        */
+       public static IPath findExistingPathIfCaseSensitive(IPath path) {
+               // case is insensitive already
+               if (HostOS.IS_WIN32)
+                       return path;
+               
+               if (path == null || !path.isAbsolute())
+                       return path;
+               
+               File pathFile = path.toFile();
+               if (pathFile.exists()) {
+                       try {
+                               return new Path(pathFile.getCanonicalPath());
+                       } catch (IOException e) {
+                               // should not happen
+                               return path;
+                       }
+               }
+                       
+
+               // start with the assumption that the path is mostly correct except for the
+               // last N segments.
+               IPath goodPath = Path.ROOT;
+               if (path.getDevice() != null)
+                       goodPath = goodPath.setDevice(path.getDevice());
+               
+               // if bad drive or no root (?!), just skip
+               if (!goodPath.toFile().exists())
+                       return path;
+               
+               for (int seg = path.segmentCount(); seg > 0; seg--) {   
+                       final IPath prefix = path.uptoSegment(seg - 1);
+
+                       if (prefix.toFile().exists()) {
+                               goodPath = prefix;
+                               break;
+                       }
+               }
+               
+               StringBuilder builder = new StringBuilder();
+               
+               builder.append(goodPath.addTrailingSeparator().toOSString());
+               
+               boolean failedLookup = false;
+               
+               for (int seg = goodPath.segmentCount(); seg < path.segmentCount(); seg++) {
+                       final String segment = path.segment(seg);
+                       
+                       final String[] matches = { segment };
+                       
+                       if (!failedLookup) {
+                               File dir = new File(builder.toString());
+                               if (!new File(dir, matches[0]).exists()) {
+                                       // component has wrong case; find the first one matching case-insensitively
+                                       String[] names = dir.list(new FilenameFilter() {
+                                               
+                                               public boolean accept(File dir, String name) {
+                                                       if (name.equalsIgnoreCase(segment)) {
+                                                               matches[0] = name;
+                                                               return true;
+                                                       }
+                                                       return false;
+                                               }
+                                       });
+                                       
+                                       if (names.length == 0) {
+                                               // no matches!  the rest of the path won't match either
+                                               failedLookup = true;
+                                       }
+                               }
+                       }
+                       builder.append(matches[0]);
+                       builder.append('/');
+               }
+               
+               if (!path.hasTrailingSeparator() && builder.length() > 0 && builder.charAt(builder.length() - 1) == '/') {
+                       builder.setLength(builder.length() - 1);
+               }
+               return new Path(builder.toString());
+       }
+
+       public static boolean isCaseSensitive() {
+               // Is the underlying file system case sensitive?
+               // This can actually be complex to determine and can even vary by volume
+               // but this is an OK general test for now.
+               if (HostOS.IS_UNIX)
+                       return true;
+               return false;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/PersistentCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/PersistentCache.java
new file mode 100644 (file)
index 0000000..4092cb6
--- /dev/null
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IPath;
+
+public class PersistentCache {
+
+       private class CacheEntry {
+
+               private String identifier;
+               private long freshness;
+               private Serializable data;
+               private IPath location;
+
+               public CacheEntry(String identifier, Serializable data, long freshness) {
+                       this.identifier = identifier;
+                       this.freshness = freshness;
+                       this.data = data;
+                       this.location = getDefaultLocation().append(Integer.toString(identifier.hashCode())).addFileExtension("txt");;
+               }
+
+               public CacheEntry(ObjectInputStream ois) throws Exception {             
+                       this.identifier = (String) ois.readObject();
+                       this.freshness = (Long) ois.readObject();
+                       this.data = (Serializable) ois.readObject();            
+                       this.location = getDefaultLocation().append(Integer.toString(identifier.hashCode())).addFileExtension("txt");;
+               }
+               
+               public IPath getLocation() {
+                       return location;
+               }
+
+               @SuppressWarnings("unchecked")
+               private <T> T getData(Class<T> expectedClass) {
+                       if (expectedClass.isInstance(data))
+                               return (T) data;
+                       else
+                               return null;
+               }
+
+               private long getFreshness() {
+                       return freshness;
+               }
+
+               private void flush() throws Exception {
+                       File cacheFile = getLocation().toFile();
+                       if (!cacheFile.exists())
+                       {
+                               cacheFile.getParentFile().mkdirs();
+                               cacheFile.createNewFile();
+                       }
+                       FileOutputStream fos = new FileOutputStream(cacheFile);
+                       ObjectOutputStream oos = new ObjectOutputStream(fos);
+                       oos.writeObject(identifier);
+                       oos.writeObject(freshness);
+                       oos.writeObject(data);
+                       fos.close();
+                       if (EDCTrace.PERSISTENT_CACHE_TRACE_ON) {
+                               EDCTrace.getTrace().trace(null, "Cache flush: " + identifier + " data: " + data);
+                       }
+               }
+
+               public void delete() {
+                       File cacheFile = getLocation().toFile();
+                       if (cacheFile.exists())
+                       {
+                               cacheFile.delete();
+                       }
+               }
+               
+       }
+       
+       private Map<String, CacheEntry> caches = Collections.synchronizedMap(new HashMap<String, CacheEntry>());
+       private IPath defaultLocation;
+
+       public PersistentCache(IPath defaultLocation) {
+               this.defaultLocation = defaultLocation;
+       }
+
+       public CacheEntry getCache(String identifier){
+               CacheEntry result = caches.get(identifier);
+               return result;          
+       }
+
+       public boolean hasCachedData(String cacheIdentifier) {
+               return caches.containsKey(cacheIdentifier);
+       }
+       
+       synchronized public <T> T getCachedData(String cacheIdentifier, T expectedClass, long freshness) {
+               @SuppressWarnings("unchecked")
+               T result = (T) getCachedData(cacheIdentifier, expectedClass.getClass(), freshness);
+               if (result == null)
+               {
+                       putCachedData(cacheIdentifier, (Serializable) expectedClass, freshness);
+                       result = expectedClass;
+               }
+               return result;
+       }
+
+       synchronized public <T> T getCachedData(String cacheIdentifier, Class<T> expectedClass, long freshness) {
+       //      freshness  = 0;
+               CacheEntry cache = caches.get(cacheIdentifier);
+               
+               if (cache == null)
+               {
+                       cache = loadCachedData(getDefaultLocation(), cacheIdentifier);
+                       if (cache != null)
+                               caches.put(cacheIdentifier, cache);
+               }
+               
+               if (cache != null)
+               {
+                       long cachedFreshness = cache.getFreshness();
+                       T result = cache.getData(expectedClass);
+                       if (cachedFreshness == freshness && result != null)
+                       {
+                               if (EDCTrace.PERSISTENT_CACHE_TRACE_ON) {
+                                       EDCTrace.getTrace().trace(null, "Cache get data: " + cacheIdentifier + " data: " + result);
+                               }
+                               return result;
+                       }
+                       else
+                       {
+                               if (EDCTrace.PERSISTENT_CACHE_TRACE_ON) {
+                                       EDCTrace.getTrace().trace(null, "Stale data. cachedFreshness: " + cachedFreshness + " freshness: " + result + " cache: " + cache);
+                               }
+                               caches.remove(cache);
+                               cache.delete();
+                       }
+               }
+               
+               return null;
+       }
+
+       private CacheEntry loadCachedData(IPath location, String cacheIdentifier) {
+               IPath flushPath = location.append(Integer.toString(cacheIdentifier.hashCode())).addFileExtension("txt");
+
+               if (flushPath.toFile().exists())
+               {
+                       try {
+                               final ClassLoader classLoader = EDCDebugger.getDefault().getClass().getClassLoader();
+                               FileInputStream fis = new FileInputStream(flushPath.toFile());
+                               ObjectInputStream ois = new ObjectInputStream(fis) {
+
+                                       @Override
+                                       protected Class<?> resolveClass(ObjectStreamClass desc)
+                                       throws IOException, ClassNotFoundException {
+                                               String name = desc.getName();
+                                               try {
+                                                       return classLoader.loadClass(name);
+                                               } catch (ClassNotFoundException e) {
+                                                       return super.resolveClass(desc);
+                                               }
+                                       }};
+                                       return new CacheEntry(ois);
+                       } catch (Exception e) {}
+               }
+
+               return null;
+       }
+
+       public void putCachedData(String cacheIdentifier, Serializable data, long freshness)
+       {
+               CacheEntry cache = new CacheEntry(cacheIdentifier, data, freshness);
+               caches.put(cacheIdentifier, cache);
+               if (EDCTrace.PERSISTENT_CACHE_TRACE_ON) {
+                       EDCTrace.getTrace().trace(null, "Cache put data: " + cacheIdentifier + " data: " + data);
+               }
+       }
+
+       public void flushAll() {
+               Collection<CacheEntry> allCaches = caches.values();
+               for (CacheEntry entry : allCaches) {
+                       try {
+                               entry.flush();
+                       } catch (Exception e) {
+                               EDCDebugger.getMessageLogger().logException(e);
+                       }
+               }
+               caches.clear();
+       }
+
+       public IPath getDefaultLocation() {
+               return defaultLocation;
+       }
+
+       public void setDefaultLocation(IPath defaultLocation) {
+               this.defaultLocation = defaultLocation;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/StreamBufferBase.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/StreamBufferBase.java
new file mode 100644 (file)
index 0000000..e12852d
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.nio.BufferUnderflowException;
+import java.nio.ByteOrder;
+
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+
+/**
+ * 
+ */
+public abstract class StreamBufferBase implements IStreamBuffer {
+       /* must be a power of 2 */
+       public static final int BUFFER_SIZE = 4096;
+       
+       protected ByteOrder order;
+       
+       // absolute
+       private long position;
+       // absolute
+       private long sourceCapacity;
+
+       private byte[] buffer;
+       // absolute source position in buffer[0]
+       private long sourceOffset;
+       // absolute source position in buffer[buffer.length]
+       private long sourceLimit;
+       
+       // offset from source to position
+       private final long baseOffset;
+       
+       /**
+        * Create a buffer over some source content
+        * @param order native byte order of content
+        * @param baseOffset base offset from source to this buffer
+        * @param capacity total size of the source (from baseOffset)
+        */
+       public StreamBufferBase(ByteOrder order, long baseOffset, long capacity) {
+               this.order = order;
+               this.baseOffset = baseOffset;
+               this.position = 0;
+               this.sourceCapacity = capacity;
+               
+               this.buffer = new byte[BUFFER_SIZE];
+               this.sourceOffset = 0;
+               this.sourceLimit = 0;
+       }
+
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return getClass().getSimpleName() +  " pos="+position() + " of "+ capacity() + " base="+ baseOffset; //$NON-NLS-N$ //$NON-NLS-2$ //$NON-NLS-3$
+       }
+       
+       /**
+        * Fetch a page of content from the buffer.
+        * @param buffer the buffer
+        * @param sourceOffset absolute offset in original content
+        * @throws BufferUnderflowException
+        */
+       protected abstract void fetchPage(byte[] buffer, long sourceOffset, int count);
+       
+       protected abstract IStreamBuffer createSubBuffer(long offset, long size);
+       
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#wrapSubsection(int)
+        */
+       public IStreamBuffer wrapSubsection(long size) {
+               long availableSize = capacity() - position();
+               if (availableSize < size)
+                       size = availableSize;
+               return createSubBuffer(position() + baseOffset, size);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#capacity()
+        */
+       public long capacity() {
+               return sourceCapacity;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#hasRemaining()
+        */
+       public boolean hasRemaining() {
+               return position < sourceCapacity;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#remaining()
+        */
+       public long remaining() {
+               return sourceCapacity - position;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#position()
+        */
+       public long position() {
+               return position;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#position(int)
+        */
+       public IStreamBuffer position(long newPosition) {
+               if (newPosition < 0 || newPosition > sourceCapacity)
+                       throw new IllegalArgumentException(newPosition + " not in 0.."+ sourceCapacity);
+               
+               this.position = newPosition;
+               return this;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#get(byte[], int, int)
+        */
+       public IStreamBuffer get(byte[] dst, int offset, int length) {
+               // read page-by-page if possible
+               while (length > 0) {
+                       if (needFetch())
+                               refetch();
+                       
+                       int left = (int) Math.min(sourceLimit - position, length);
+                       if (left > 0) {
+                               System.arraycopy(buffer, (int) (position - sourceOffset), dst, offset, left);
+                               offset += left;
+                               position += left;
+                               length -= left;
+                       } else {
+                               break;
+                       }
+               }
+               return this;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#get(byte[])
+        */
+       public IStreamBuffer get(byte[] dst) {
+               return get(dst, 0, dst.length);
+       }
+
+       /**
+        * Fill memory buffer from source
+        */
+       protected void refetch() {
+               long newSourceOffset = position - (position & buffer.length - 1);
+               if (newSourceOffset < 0)
+                       throw new BufferUnderflowException();
+               if (newSourceOffset >= sourceCapacity)
+                       throw new BufferUnderflowException();
+               
+               int toFetch = (int) Math.min(sourceCapacity - newSourceOffset, buffer.length);
+               fetchPage(buffer, newSourceOffset + baseOffset, toFetch);
+               sourceOffset = newSourceOffset;
+               sourceLimit = sourceOffset + toFetch;
+       }
+       
+       protected final boolean needFetch() {
+               return (position < sourceOffset || position >= sourceLimit);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#get()
+        */
+       public byte get() {
+               if (needFetch()) 
+                       refetch();
+               
+               if (position < sourceCapacity)
+                       return buffer[(int)((position++) - sourceOffset)];
+               else
+                       throw new BufferUnderflowException();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#getChar()
+        */
+       public char getChar() {
+               return (char) getShort();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#getShort()
+        */
+       public short getShort() {
+               int a = get() & 0xff;
+               int b = get() & 0xff;
+               if (order == ByteOrder.LITTLE_ENDIAN)
+                       return (short) (a | (b << 8));
+               else
+                       return (short) (b | (a << 8));
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#getInt()
+        */
+       public int getInt() {
+               int a = getShort() & 0xffff;
+               int b = getShort() & 0xffff;
+               if (order == ByteOrder.LITTLE_ENDIAN)
+                       return a | (b << 16);
+               else
+                       return b | (a << 16);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.IStreamBuffer#getLong()
+        */
+       public long getLong() {
+               long a = getInt();
+               long b = getInt();
+               if (order == ByteOrder.LITTLE_ENDIAN)
+                       return a | (b << 32);
+               else
+                       return b | (a << 32);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.IStreamBuffer#skip(long)
+        */
+       public IStreamBuffer skip(long amount) {
+               return position(position() + amount);
+       }
+       
+       public ByteOrder getOrder() {
+               return order;
+       }
+       public void setOrder(ByteOrder order) {
+               this.order = order;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/TCFServiceManager.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/TCFServiceManager.java
new file mode 100644 (file)
index 0000000..d29e774
--- /dev/null
@@ -0,0 +1,618 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.cdt.debug.edc.ITCFAgentLauncher;
+import org.eclipse.cdt.debug.edc.ITCFConnectionListener;
+import org.eclipse.cdt.debug.edc.ITCFServiceManager;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.tm.tcf.core.AbstractPeer;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener;
+import org.eclipse.tm.tcf.protocol.IPeer;
+import org.eclipse.tm.tcf.protocol.IService;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.ILocator;
+import org.eclipse.tm.tcf.util.TCFTask;
+
+/**
+ * Utility class that provides access to TCF agents and services. It abstracts
+ * out the details of which agent provides the services, launching the agent if
+ * necessary, etc.
+ */
+public class TCFServiceManager implements ITCFServiceManager  {
+
+       /**
+        * The IP addresses of the local machine. Typically, there's at least two
+        * (the loopback address is one of them), but there can be more if there are
+        * multiple network adapters (physical or virtual).
+        * 
+        * <p>
+        * TODO: if you look at the TCF Java reference implementation, it updates
+        * its list every so often, as a system's network configuration can change
+        * during the life of a process. We should probably do that, too, though
+        * it's clearly an edge case.
+        */
+       private static List<String> localIPAddresses;
+       
+       private List<ITCFAgentLauncher> tcfAgentLaunchers;
+
+       private static final String EXTENSION_POINT_NAME = "tcfAgentLauncher";
+
+       private List<ITCFAgentLauncher> launchedtcfAgentLaunchers;
+       
+       private ListenerList peerChannelListeners = new ListenerList();
+
+       static {
+               // Record local host IP addresses--not only numeric IP addresses but
+               // also hostnames if available.
+               try {
+                       localIPAddresses = getLocalIPAddresses();
+               } catch (CoreException e) {
+                       EDCDebugger.getMessageLogger().logError("Problem getting local IP addresses", e); //$NON-NLS-1$
+               }
+       }
+
+       public TCFServiceManager() {
+               // load TCFAgentLauncher extensions
+               tcfAgentLaunchers = new ArrayList<ITCFAgentLauncher>();
+               launchedtcfAgentLaunchers = new ArrayList<ITCFAgentLauncher>();
+
+               IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+               IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(EDCDebugger.PLUGIN_ID, EXTENSION_POINT_NAME);
+               IExtension[] extensions = extensionPoint.getExtensions();
+
+               for (IExtension extension : extensions) {
+                       IConfigurationElement[] elements = extension.getConfigurationElements();
+                       IConfigurationElement element = elements[0];
+
+                       boolean failed = false;
+                       CoreException exc = null;
+                       try {
+                               Object extObject = element.createExecutableExtension("class"); //$NON-NLS-1$
+                               if (extObject instanceof ITCFAgentLauncher) {
+                                       tcfAgentLaunchers.add((ITCFAgentLauncher) extObject);
+                               } else {
+                                       failed = true;
+                               }
+                       } catch (CoreException e) {
+                               failed = true;
+                               exc = e;
+                       }
+
+                       if (failed) {
+                               EDCDebugger.getMessageLogger().logError(
+                                               "Unable to load " + EXTENSION_POINT_NAME + " extension from " + extension.getContributor().getName(), exc);
+                       }
+               }
+
+       }
+
+       /**
+        * Returns true if <i>all</i> the attributes in [attributesToMatch] appear
+        * identically in [attributes] (keys and respective values). Basically, is
+        * [attributesToMatch] a subset of [attributes]?
+        */
+       public static boolean matchesAllAttributes(Map<String, String> attributes, Map<String, String> attributesToMatch) {
+               if (attributesToMatch.isEmpty())
+                       return false;
+               
+               for (String key : attributesToMatch.keySet()) {
+                       if (!attributes.containsKey(key)) {
+                               return false;
+                       }
+                       if (!attributesToMatch.get(key).equals(attributes.get(key))) {
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+
+       /**
+        * Check if the given TCF peer is the LocalPeer defined in TCF. As that
+        * LocalPeer is not public, we check by its internal ID. It may not be
+        * forward compatible, but is there a better way ?
+        * 
+        * @param p
+        * @return
+        */
+       public static boolean isInternalLocalPeer(IPeer p) {
+               assert Protocol.isDispatchThread();
+               return p.getID().equals("TCFLocal");
+       }
+
+       /**
+        * Find any registered TCF agent-launchers that will (should) produce a peer
+        * with the given attributes and that exposes the given service. The
+        * agent-launchers are registered through an EDC extension point.
+        * 
+        * @param serviceName
+        *            the required service
+        * @param attributesToMatch
+        *            the required peer attributes
+        * @return zero or more agent-launchers that fit the bill
+        */
+       public ITCFAgentLauncher[] findSuitableAgentLaunchers(final String serviceName, final Map<String, String> attributesToMatch, boolean localAgentsOnly) {
+               List<String> registeredPeerLabels = new ArrayList<String>();
+               List<ITCFAgentLauncher> registeredAgents = new ArrayList<ITCFAgentLauncher>();
+
+               // Find registered agents that meets our need and which can be launched.
+
+               for (ITCFAgentLauncher descriptor : tcfAgentLaunchers) {
+                       if (descriptor.getServiceNames().contains(serviceName)
+                                       && matchesAllAttributes(descriptor.getPeerAttributes(), attributesToMatch)
+                                       && descriptor.isLaunchable()) {
+                               registeredPeerLabels.add(descriptor.getPeerName() + " (local registered non-started)");
+                               registeredAgents.add(descriptor);
+                       }
+               }
+               return registeredAgents.toArray(new ITCFAgentLauncher[registeredAgents.size()]);
+       }
+       
+       public IPeer[] getRunningPeers(final String serviceName, final Map<String, String> attributesToMatch, final boolean localAgentsOnly) throws CoreException {
+               // first find running peers with matching attributes
+               final List<IPeer> runningCandidates1 = new ArrayList<IPeer>();
+
+               Protocol.invokeAndWait(new Runnable() {
+                       public void run() {
+                               // This collection is only changed in TCF dispatcher thread.
+                               // So don't worry about race condition.
+                               Collection<IPeer> peers = Protocol.getLocator().getPeers().values();
+
+                               for (IPeer p : peers) {
+                                       // Don't bother with internal local peer.
+                                       if (isInternalLocalPeer(p))
+                                               continue;
+
+                                       if (matchesAllAttributes(p.getAttributes(), attributesToMatch)) {
+                                               runningCandidates1.add(p);
+                                       }
+                               }
+                       }
+               });
+               
+               // Now search the running candidates for the one that offers the
+               // required service.
+
+               final List<IPeer> runningCandidates2 = new ArrayList<IPeer>();
+               final List<String> runningLocalAgentPorts = new ArrayList<String>();
+
+               for (final IPeer peer : runningCandidates1) {
+
+                       // wait up to 3 seconds for the asynchronous task.
+                       TCFTask<Object> task = new TCFTask<Object>(3000) {
+                               public void run() {
+                                       final boolean isLocalAgent = isInLocalAgent(peer);
+
+                                       /*
+                                        * If host has multiple IP addresses (e.g. 127.0.0.1 &
+                                        * 192.168.0.5), a local agent instance may be running on
+                                        * each of the addresses (see AgentServerTCP for more) but
+                                        * listening on the same port. In such case, we don't want
+                                        * to ask user to choose between those for local debug (it's
+                                        * annoying). So we'll just use first of them for local
+                                        * debug. Also note that different types of agents should
+                                        * not listen to the same port.
+                                        */
+                                       if (isLocalAgent) {
+                                               String port = peer.getAttributes().get(IPeer.ATTR_IP_PORT);
+                                               if (port != null) { // TCP/IP peer
+                                                       if (runningLocalAgentPorts.contains(port)) {
+                                                               // a local agent on the same port already exists (it 
+                                                               // must be of the same agent type), skip this one.
+                                                               done(this);
+                                                               return;
+                                                       }
+                                                       else
+                                                               runningLocalAgentPorts.add(port);
+                                               }
+                                       }
+
+                                       IChannel ch = getChannelForPeer(peer);
+                                       if (ch != null) {
+                                               assert (ch.getState() == IChannel.STATE_OPEN);
+                                               if (null != ch.getRemoteService(serviceName)) {
+                                                       // If the peer is on a local host, add it. If the
+                                                       // peer is on another host, then whether we add
+                                                       // it or not depends on the caller's wishes.
+                                                       if (isLocalAgent || !localAgentsOnly)
+                                                               runningCandidates2.add(peer);
+                                               }
+                                               done(this);
+                                       } else {
+                                               final IChannel channel = peer.openChannel();
+
+                                               IChannel.IChannelListener listener = new IChannel.IChannelListener() {
+                                                       public void onChannelOpened() {
+                                                               if (null != channel.getRemoteService(serviceName)) {
+                                                                       // If the peer is on this machine, add it. If the
+                                                                       // peer is on another machine, then whether we add
+                                                                       // it or not depends on the caller's wishes.
+                                                                       if (isLocalAgent || !localAgentsOnly)
+                                                                               runningCandidates2.add(peer);
+                                                               }
+                                                               
+                                                               fireConnectionOpened(peer, channel);
+                                                               
+                                                               done(this); // argument is do-not-care
+                                                       }
+
+                                                       public void onChannelClosed(Throwable error) {
+                                                               fireConnectionClosed(peer, channel, error);
+                                                               channel.removeChannelListener(this);
+                                                       }
+
+                                                       public void congestionLevel(int level) {
+                                                       }
+                                               };
+
+                                               channel.addChannelListener(listener);
+                                       }
+                               }
+                       };
+
+                       try {
+                               task.get();
+                       } catch (Exception e) {
+                               // Failed to find nor open channel to the peer, it must be a
+                               // stale peer (a peer that dies but not removed from the TCF
+                               // framework. See
+                               // rg.eclipse.tm.internal.tcf.services.local.LocatorService.refresh_timer()).
+                               // Dispose it so that it won't get in the way
+                               // when we try to auto-launch the agent again.
+                               Protocol.invokeAndWait(new Runnable() {
+                                       public void run() {
+                                               try {
+                                                       ((AbstractPeer) peer).dispose();
+                                               } catch (AssertionError e) {
+                                                       // we were wrong; it is disposed
+                                               }
+                                       }
+                               });
+                       }
+               }
+               
+               return runningCandidates2.toArray(new IPeer[runningCandidates2.size()]);
+       }
+
+       /**
+        * Determines whether the given peer is running in a local agent. We compare
+        * the IP address of the peer against the list of IP addresses for this
+        * machine (typically, there are at least two: the loopback address and the
+        * physical NIC).
+        */
+       public static boolean isInLocalAgent(IPeer peer) {
+               assert Protocol.isDispatchThread();
+               String ipHost = peer.getAttributes().get(IPeer.ATTR_IP_HOST);
+               return localIPAddresses.contains(ipHost);
+       }
+
+       public IChannel findOrCreateChannelForPeer(final IPeer peer) throws CoreException {
+               IChannel channel = null;
+
+               // First check if there is existing open channel to the peer.
+               //
+               channel = getChannelForPeer(peer);
+               if (channel != null)
+                       return channel;
+
+               // Then try to open a channel to the peer.
+               //
+               /*
+                * Following will cause deadlock if called in TCF dispatcher thread as
+                * it will wait for an TCF even to finish in the dispatcher thread.
+                */
+               assert (!Protocol.isDispatchThread());
+
+               final WaitForResult<IChannel> waitForChannel = new WaitForResult<IChannel>();
+
+               Protocol.invokeAndWait(new Runnable() {
+                       public void run() {
+                               try {
+                                       final IChannel newChannel = peer.openChannel();
+                                       newChannel.addChannelListener(new IChannelListener() {
+       
+                                               public void onChannelOpened() {
+                                                       waitForChannel.setData(newChannel);
+                                                       
+                                                       fireConnectionOpened(peer, newChannel);
+                                               }
+       
+                                               public void onChannelClosed(Throwable error) {
+                                                   waitForChannel.handleException(error);
+                                                   fireConnectionClosed(peer, newChannel, error);
+                                                   newChannel.removeChannelListener(this);
+                                               }
+       
+                                               public void congestionLevel(int level) {
+                                               }
+                                       });
+                               }
+                               catch (Throwable exc) {
+                                       waitForChannel.handleException(exc);
+                               }
+                       }
+               });
+
+               try {
+                       channel = waitForChannel.get(15, TimeUnit.SECONDS);
+               } catch (ExecutionException e) {
+                       throw EDCDebugger.newCoreException("Failed to open channel for " + peer.getID(), e);
+                   
+               } catch (Exception e) {
+                       throw EDCDebugger.newCoreException("Time out getting open channel for peer.", e);
+               }
+
+               return channel;
+       }
+
+       /**
+        * Find existing open channel for the given peer.
+        * 
+        * @param peer
+        * @return null if not found.
+        */
+       public IChannel getChannelForPeer(final IPeer peer) {
+
+               final IChannel[] ret = { null };
+
+               Protocol.invokeAndWait(new Runnable() {
+                       public void run() {
+                               String peerName = peer.getName();
+                               String peerID = peer.getID();
+
+                               IChannel[] channels = Protocol.getOpenChannels();
+                               for (IChannel channel : channels) {
+                                       IPeer remotePeer = channel.getRemotePeer();
+                                       if (remotePeer.getName().equals(peerName) && remotePeer.getID().equals(peerID)) {
+                                               ret[0] = channel;
+                                               return;
+                                       }
+                               }
+                       }
+               });
+
+               return ret[0];
+       }
+
+       /**
+        * Gets the service from the given TCF peer.
+        * 
+        * @param peer
+        *            TCF peer.
+        * @param serviceName
+        *            the name of the service
+        * @return IService if the peer offers that service, null otherwise.
+        * @throws CoreException on error
+        */
+       public IService getPeerService(final IPeer peer, final String serviceName) throws CoreException {
+               final WaitForResult<IService> waitForService = new WaitForResult<IService>();
+
+               final IChannel channel = findOrCreateChannelForPeer(peer);
+
+               Protocol.invokeAndWait(new Runnable() {
+                       public void run() {
+                               try {
+                                       IService service = channel.getRemoteService(serviceName);
+                                       if (service == null) {
+                                               // If the service is unavailable, set a dummy service
+                                               // object so the delegating thread doesn't end up
+                                               // pointlessly waiting
+                                               service = new IService() {
+                                                       public String getName() {
+                                                               return null;
+                                                       }
+                                               };
+                                       }
+                                       waitForService.setData(service);
+                               } catch (Exception e) {
+                                       waitForService.handleException(e);
+                               }
+                       }
+               });
+
+               try {
+                       IService service = waitForService.get();
+                       // check for the dummy service object
+                       return (service.getName() == null) ? null : service;
+                       
+               } catch (Exception e) {
+                       throw EDCDebugger.newCoreException("Fail to get TCF service [" + serviceName + "] from peer.", e);
+               }
+       }
+
+       /**
+        * Invokes an agent-launcher and waits (a while) for an agent to be
+        * discovered that meets the given peer attributes
+        * 
+        * @param descriptor
+        * @return
+        * @throws CoreException
+        */
+       public IPeer launchAgent(final ITCFAgentLauncher descriptor, final Map<String, String> peerAttrs) throws CoreException {
+               final WaitForResult<IPeer> waitForPeer = new WaitForResult<IPeer>() {
+               };
+
+               final ILocator.LocatorListener listener = new ILocator.LocatorListener() {
+
+                       public void peerRemoved(String id) {
+                       }
+
+                       public void peerHeartBeat(String id) {
+                       }
+
+                       public void peerChanged(IPeer peer) {
+                       }
+
+                       public void peerAdded(IPeer peer) {
+                               if (matchesAllAttributes(peer.getAttributes(), peerAttrs)) {
+                                       waitForPeer.setData(peer);
+                               }
+                       }
+               };
+
+               Protocol.invokeAndWait(new Runnable() {
+                       public void run() {
+                               // register ourselves as a listener
+                               Protocol.getLocator().addListener(listener);
+                       }
+               });
+
+               // launch the agent
+
+               IPeer launchedPeer = null;
+               try {
+                       // Launch the agent (if it's not already running)
+                       try {
+                               descriptor.launch();
+                       } catch (Exception e) {
+                               throw EDCDebugger.newCoreException(MessageFormat.format("Failed to launch the TCF agent that hosts peer \"{0}\". Cause: {1}", 
+                                               descriptor.getPeerName(), e.getLocalizedMessage()), e);
+                       }
+                       
+                       // Wait for the Locator listener we registered above to be notified
+                       // of the existence of the peer we're interested in
+                       try {
+                               launchedPeer = waitForPeer.get();
+                       } catch (Exception e) {
+                               if (e.getCause() instanceof TimeoutException) {
+                                       throw EDCDebugger.newCoreException(MessageFormat.format("Timed out waiting for the launched TCF agent to make peer \"{0}\" available.", 
+                                                       descriptor.getPeerName()), null);
+                               }
+                               else {
+                                       throw EDCDebugger.newCoreException(MessageFormat.format("Error waiting for the launched TCF agent to make peer \"{0}\" available. Cause: {1}", 
+                                                       descriptor.getPeerName(), e.getLocalizedMessage()), e);
+                               }
+                       }
+                       launchedtcfAgentLaunchers.add(descriptor);
+               }
+               finally {
+                       Protocol.invokeAndWait(new Runnable() {
+                               public void run() {
+                                       // unregister our listener
+                                       Protocol.getLocator().removeListener(listener);
+                               }
+                       });
+               }
+               
+
+               return launchedPeer;
+       }
+
+       private static List<String> getLocalIPAddresses() throws CoreException {
+               List<String> ret = new ArrayList<String>();
+
+               Enumeration<NetworkInterface> e;
+               try {
+                       e = NetworkInterface.getNetworkInterfaces();
+               } catch (SocketException e1) {
+                       throw EDCDebugger.newCoreException("Host is required to connect to a network but it isn't.");
+               }
+
+               while (e.hasMoreElements()) {
+                       NetworkInterface f = e.nextElement();
+                       Enumeration<InetAddress> n = f.getInetAddresses();
+                       while (n.hasMoreElements()) {
+                               InetAddress addr = n.nextElement();
+                               ret.add(addr.getHostAddress());
+                       }
+               }
+               
+               // Support agents who use hostnames instead of numeric IP addresses
+               try {
+                       InetAddress localHost = InetAddress.getLocalHost();
+                       if (localHost != null) {
+                               ret.add(localHost.getHostName());
+                               ret.add(localHost.getCanonicalHostName());
+                       }
+               } catch (UnknownHostException exc) {
+                       EDCDebugger.getMessageLogger().logError("", exc);
+               }
+               
+               return ret;
+       }
+
+       /**
+        * Shutdown.
+        */
+       public void shutdown() {
+               // shutdown all agents that were launched by this manager
+               for (ITCFAgentLauncher desc : launchedtcfAgentLaunchers) {
+                       try {
+                               desc.shutdown();
+                       } catch (Exception e) {
+                       }
+               }
+               launchedtcfAgentLaunchers.clear();
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.ITCFServiceManager#addChannelPeerListener(org.eclipse.cdt.debug.edc.ITCFConnectionListener)
+        */
+       public void addConnectionListener(ITCFConnectionListener listener) {
+               peerChannelListeners.add(listener);
+       }
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.ITCFServiceManager#removeChannelPeerListener(org.eclipse.cdt.debug.edc.ITCFConnectionListener)
+        */
+       public void removeConnectionListener(ITCFConnectionListener listener) {
+               peerChannelListeners.remove(listener);
+       }
+       
+       protected void fireConnectionOpened(final IPeer peer, final IChannel channel) {
+               Protocol.invokeAndWait(new Runnable() {
+                       public void run() {
+                               for (Object o : peerChannelListeners.getListeners()) {
+                                       try {
+                                               ((ITCFConnectionListener) o).peerChannelOpened(peer, channel);
+                                       } catch (Throwable t) {
+                                               EDCDebugger.getMessageLogger().logError("Exception thrown from connection listener", t);
+                                       }
+                               }
+                       }
+               });
+       }
+       
+       protected void fireConnectionClosed(final IPeer peer, final IChannel channel, final Throwable exception) {
+               Protocol.invokeAndWait(new Runnable() {
+                       public void run() {
+                               for (Object o : peerChannelListeners.getListeners()) {
+                                       try {
+                                               ((ITCFConnectionListener) o).peerChannelClosed(peer, channel, exception);
+                                       } catch (Throwable t) {
+                                               EDCDebugger.getMessageLogger().logError("Exception thrown from connection listener", t);
+                                       }
+                               }
+                       }
+               });
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/WaitForResult.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/WaitForResult.java
new file mode 100644 (file)
index 0000000..6b1dc41
--- /dev/null
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class WaitForResult<V> implements Future<V> {
+
+       public static final long DEFAULT_WAIT_TIMEOUT_SECONDS = 10;
+       public static final long WAIT_INTERVAL_MILLIS = 50;
+       private boolean running;
+       private boolean canceled;
+       private boolean done;
+       private V data;
+       private volatile Throwable exception;
+
+       /* (non-Javadoc)
+        * @see java.util.concurrent.Future#cancel(boolean)
+        */
+       public boolean cancel(boolean mayInterruptIfRunning) {
+               if (!running)
+                       return false;
+               else {
+                       canceled = true;
+                       return true;
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.util.concurrent.Future#get()
+        */
+       public V get() throws InterruptedException, ExecutionException {
+               try {
+                       return get(DEFAULT_WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+               } catch (TimeoutException e) {
+                       throw new ExecutionException(e);
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.util.concurrent.Future#get(long, java.util.concurrent.TimeUnit)
+        */
+       public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+
+               long limitMillis = System.currentTimeMillis() + unit.toMillis(timeout);
+               running = true;
+               while (!canceled && (exception == null) && !hasResult()) {
+                       Thread.sleep(WAIT_INTERVAL_MILLIS);
+                       if (System.currentTimeMillis() > limitMillis)
+                               throw new TimeoutException();
+               }
+               done = true;
+               running = false;
+
+               if (exception != null)
+                       throw new ExecutionException(exception);
+
+               return data;
+       }
+
+       public void setData(V data) {
+               this.data = data;
+       }
+
+       public V getData() {
+               return data;
+       }
+
+       public boolean hasResult() {
+               return getData() != null;
+       }
+
+       /* (non-Javadoc)
+        * @see java.util.concurrent.Future#isCancelled()
+        */
+       public boolean isCancelled() {
+               return canceled;
+       }
+
+       /* (non-Javadoc)
+        * @see java.util.concurrent.Future#isDone()
+        */
+       public boolean isDone() {
+               return done;
+       }
+
+       public void handleException(Throwable e) {
+               this.exception = e;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/ZipFileUtils.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/ZipFileUtils.java
new file mode 100644 (file)
index 0000000..efd1a44
--- /dev/null
@@ -0,0 +1,347 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import de.schlichtherle.io.ArchiveDetector;
+import de.schlichtherle.io.ArchiveException;
+import de.schlichtherle.io.DefaultArchiveDetector;
+import de.schlichtherle.io.File;
+import de.schlichtherle.io.FileInputStream;
+
+
+/**
+ * Provides a convenience wrapper around TrueZip and java.util.zip for read/write access to zip archives.
+ * The API under java.util.zip does not provide ability to update individual entries in archives
+ * and hence can be cumbersome and slow to use so TrueZip is added to ease this pain.
+ * <p>
+ * This wrapper also encapsulates the use of de.schlichtherle.io.File and only takes java.io.File
+ * as explicit arguments. When differentiating the two, only java.io.File must be explicit.
+ * <p>
+ * For more information see https://truezip.dev.java.net/
+ *
+ */
+public class ZipFileUtils {
+       
+       /**
+        * Delete a file from an archive
+        * @param fileName - File name relative path in the archive
+        * @param zipFile - The zip file on disk
+        * @param extensions - File extension of the zip format archive
+        * @return true on success
+        */
+       public static boolean deleteFileFromZip(String fileName, java.io.File zipFile, String[] extensions){
+               String archiveFileName = zipFile + File.separator + fileName;   
+               
+               ArchiveDetector detector = getArchiveDetector(extensions);
+               
+               File file = null;
+               if (detector != null){
+                       file = new File(archiveFileName, detector);
+               } else {
+                       file = new File(archiveFileName);
+               }
+               
+               boolean success = file.delete();
+
+               unmount();
+               
+               return success; 
+       }
+       
+       /**
+        * Delete a file from an archive
+        * @param fileName - File name relative path in the archive
+        * @param zipFile - File extension of the zip format archive
+        * @return true on success
+        * 
+        * @see {@link deleteFileFromZip(String fileName, java.io.File zipFile, String[] extensions)}
+        */
+       public static boolean deleteFileFromZip(String fileName, java.io.File zipFile) {
+               return deleteFileFromZip(fileName, zipFile, null);
+       }
+       
+       /**
+        * Copies a source file into a specified zip file. If the file exists it will be overwritten.
+        * @param src - The originating source to be copied
+        * @param zipFile - The destination for src
+        * @param extensions - File extension of the zip archive
+        * @return true on success
+        */
+       public static boolean addFileToZip(java.io.File src, java.io.File zipFile, String[] extensions){
+               
+               boolean success = false;
+               ArchiveDetector detector = getArchiveDetector(extensions);
+               
+               File toBeAddedFile = null;
+
+               if (detector != null){
+                       toBeAddedFile = new File(src, detector);
+                       success = toBeAddedFile.archiveCopyTo(new File(zipFile, toBeAddedFile.getName(), detector));
+               } else {
+                       toBeAddedFile = new File(src);
+                       success = toBeAddedFile.archiveCopyTo(new File(zipFile, toBeAddedFile.getName()));
+               }
+               
+               unmount();
+               
+               return success; 
+       }
+       
+       /**
+        * Copies a source file into a specified zip file. If the file exists it will be overwritten.
+        * @param src - The originating source to be copied
+        * @param zipFile - The destination for src
+        * @return true on success
+        * 
+        * @see {@link addFileToZip(java.io.File src, java.io.File zipFile, String[] extensions)}
+        */
+       public static boolean addFileToZip(java.io.File srcFile, java.io.File zipFile) {
+               return addFileToZip(srcFile, zipFile, null);
+       }
+       
+       /**
+        * Copies source file(s) into a specified zip file. If the file exists it will be overwritten.
+        * @param src - The originating sources to be copied
+        * @param zipFile - The destination for src
+        * @param extensions - File extension of the zip archive
+        * @return true on success
+        */
+       public static boolean addFilesToZip(java.io.File[] src, java.io.File zipFile, String[] extensions){
+               
+               boolean success = false;
+               ArchiveDetector detector = getArchiveDetector(extensions);
+               
+               for (java.io.File currSrcFile : src) {
+                       
+                       try {
+                       
+                       File toBeAddedFile = null;
+                               if (detector != null) {
+
+                                       toBeAddedFile = new File(currSrcFile.getCanonicalFile(),
+                                                       detector);
+
+                                       success = toBeAddedFile.archiveCopyTo(new File(zipFile,
+                                                       toBeAddedFile.getName(), detector));
+                               } else {
+                                       toBeAddedFile = new File(currSrcFile.getCanonicalFile());
+                                       success = toBeAddedFile.archiveCopyTo(new File(zipFile,
+                                                       toBeAddedFile.getName()));
+                               }
+
+                       unmount();
+                       
+                       } catch (ArchiveException e) {
+                               e.printStackTrace();
+                       } catch (IOException e) {
+                               e.printStackTrace();
+                       }
+               }
+               return success; 
+       }
+       
+       /**
+        * Copies source file(s) into a specified zip file. If the file exists it will be overwritten.
+        * @param src - The originating source to be copied
+        * @param zipFile - The destination for src
+        * @return true on success
+        * 
+        * @see ZipFileUtils#addFilesToZip(java.io.File[], java.io.File, String[])
+        */
+       public static boolean addFilesToZip(java.io.File[] src, java.io.File zipFile) {
+               return addFilesToZip(src, zipFile, null);
+       }
+       
+       /**
+        * TrueZip detects archive types by file extension and only has built in support for known types.
+        * If other file extensions are used that TrueZip does not have in it's default configuration
+        * it will complain that it does not recognize the archive type. Passing an array of extensions will
+        * allow TrueZip to recognize any arbitrary file extension as a zip archive. This only works for zip archvies.
+        * 
+        * @param extensions - array of extension TrueZip should recognize as zip files.
+        * @return ArchiveDetector
+        */
+       private static ArchiveDetector getArchiveDetector(String[] extensions){
+               List<Object> zipFileExtensions = new ArrayList<Object>();
+               ArchiveDetector detector = null;
+               if (extensions != null && extensions.length > 0){
+                       for (String ext : extensions){
+                               zipFileExtensions.add(ext);
+                               zipFileExtensions.add(new de.schlichtherle.io.archive.zip.ZipDriver());
+                       }
+                       
+                       detector = new DefaultArchiveDetector(ArchiveDetector.NULL,
+                                       zipFileExtensions.toArray());
+               }
+               
+               return detector;
+       }
+       
+       /**
+        * 
+        * @param zipFileName
+        * @return
+        * @throws IOException
+        * 
+        */
+       public static List<ZipEntry> listZipContents(String zipFileName) throws IOException{
+               List<ZipEntry> zipContents = new ArrayList<ZipEntry>();
+
+               ZipFile zipFile = new ZipFile(zipFileName);
+               Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
+               while (zipEntries.hasMoreElements()) {
+                       zipContents.add(zipEntries.nextElement());
+               }
+               
+               return zipContents;
+       }
+       
+       /**
+        * Get a java.io.BufferedInputStream for reading 'src' from the specified 'zipFile'. Clients should make sure to call {@link ZipFileUtils#unmount()} when reading is complete.
+        * @param zipFile - Archive to read
+        * @param src - File to open for reading in the zipFile
+        * @param extensions - Extensions for zip file used if not standard
+        * @return
+        */
+       public static java.io.BufferedInputStream openFile(java.io.File zipFile, String src, String[] extensions){
+               ArchiveDetector detector = getArchiveDetector(extensions);
+               String archiveFileName = zipFile + File.separator + src;
+               try {
+                       File.setDefaultArchiveDetector(detector);
+                       FileInputStream fs = new FileInputStream(archiveFileName);
+                       java.io.BufferedInputStream stream = new java.io.BufferedInputStream(fs);
+                       return stream;
+               } catch (FileNotFoundException e) {
+                       e.printStackTrace();
+               } 
+               
+               return null;
+       }
+
+       /**
+        * Close all input and output streams.
+        * Equivalent to {@link File#umount(boolean, boolean, boolean, boolean)
+        */
+       public static void unmount(){
+               try {
+                       File.umount();
+               } catch (ArchiveException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       public static boolean createNewZip(java.io.File zipFileToCreate) {
+               boolean success = false;        
+               if (zipFileToCreate.exists()){
+                       return true;
+               }
+               
+               if (!zipFileToCreate.getParentFile().exists()){
+                       zipFileToCreate.mkdirs();
+               }
+               
+               File f = new File(zipFileToCreate);
+
+               try {
+                       success = f.createNewFile();
+               } catch (IOException e) {
+                       e.printStackTrace();
+               } finally {
+                       unmount();
+               }
+               
+               return success;
+       }
+       
+       /**
+        * Only unzips files in zip file not directories
+        * 
+        * @param zipped
+        *            file
+        * @param destPath
+        *            Destination path
+        * @return Files that were unzipped
+        */
+       public static List<File> unzipFiles(java.io.File zippedfile, String destPath, IProgressMonitor monitor)
+                       throws FileNotFoundException, IOException {
+               ZipFile zipFile = new ZipFile(zippedfile);
+
+               Enumeration<? extends ZipEntry> entries = zipFile.entries();
+               List<File> outputFiles = new ArrayList<File>();
+               File destinationFile = new File(destPath);
+               if (!destinationFile.exists()) {
+                       destinationFile.mkdirs();
+               }
+               while (entries.hasMoreElements()) {
+                       ZipEntry entry = entries.nextElement();
+                       File outputFile = new File(destinationFile, entry.getName());
+                       if (entry.isDirectory() && !outputFile.exists()) {
+                               outputFile.mkdirs();
+                               continue;
+                       }
+
+                       if (!outputFile.getParentFile().exists()) {
+                               outputFile.getParentFile().mkdirs();
+                       }
+
+                       java.io.InputStream inputStream = zipFile.getInputStream(entry);
+                       java.io.FileOutputStream outStream = new java.io.FileOutputStream(outputFile);
+                       copyByteStream(inputStream, outStream);
+
+                       outputFiles.add(outputFile);
+                       if (monitor != null) {
+                               monitor.worked(1);
+                       }
+                       outStream.close();
+                       inputStream.close();
+               }
+               zipFile.close();
+               return outputFiles;
+       }
+       
+       public static void copyByteStream(java.io.InputStream in, java.io.OutputStream out) throws IOException {
+               if (in != null && out != null) {
+                       java.io.BufferedInputStream inBuffered = new java.io.BufferedInputStream(in);
+
+                       int bufferSize = 1000;
+                       byte[] buffer = new byte[bufferSize];
+
+                       int readCount;
+
+                       java.io.BufferedOutputStream fout = new java.io.BufferedOutputStream(out);
+
+                       while ((readCount = inBuffered.read(buffer)) != -1) {
+                               if (readCount < bufferSize) {
+                                       fout.write(buffer, 0, readCount);
+                               } else {
+                                       fout.write(buffer);
+                               }
+                       }
+                       fout.flush();
+                       fout.close();
+                       in.close();
+               }
+       }
+
+
+
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTEvalMessages.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTEvalMessages.java
new file mode 100644 (file)
index 0000000..0f8eda1
--- /dev/null
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine;
+
+import org.eclipse.osgi.util.NLS;
+
+public class ASTEvalMessages extends NLS {
+       private static final String BUNDLE_NAME = "org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages"; //$NON-NLS-1$
+
+       public static String DivideByZero;
+       public static String UnhandledTypeCode;
+       public static String UnhandledSize;
+       public static String UnsupportedStringOperation;
+
+       public static String ASTEvaluationEngine_DidNotDetectType;
+       
+       public static String ASTInstructionCompiler_InvalidNumber;
+
+       public static String ArraySubscript_ArrayHasNoBounds;
+       public static String ArraySubscript_CannotIndirectTemporary;
+       public static String ArraySubscript_ErrorDereferencingArray;
+       public static String ArraySubscript_MustSubscriptArray;
+       public static String ArraySubscript_ReadingPastEndOfString;
+       public static String ArraySubscript_SubscriptMustBeInteger;
+
+       public static String EvaluateID_CannotResolveName;
+       public static String EvaluateID_NameHasNoLocation;
+       public static String EvaluateID_VariableNotFound;
+
+       public static String FieldReference_InvalidPointerDeref;
+       public static String FieldReference_InvalidDotDeref;
+       public static String FieldReference_InvalidMember;
+       public static String FieldReference_AmbiguousMember;
+       public static String FieldReference_CannotDereferenceType;
+       public static String FieldReference_UnhandledOperandSize;
+
+       public static String GetValue_TypePromotionError;
+
+       public static String Instruction_CannotUseCompositeType;
+       public static String Instruction_EmptyStack;
+       public static String Instruction_UnhandledTypeCombination;
+
+       public static String OperandValue_CannotGetAddress;
+       public static String OperandValue_CannotReadUnspecifiedType;
+       public static String OperandValue_CannotReadVoid;
+       public static String OperandValue_UnhandledType;
+       public static String OperandValue_VariableNoAddress;
+
+       public static String OperatorAddrOf_RequiresVariable;
+       public static String OperatorAddrOf_NoRegister;
+       public static String OperatorAddrOf_NoBitField;
+
+       public static String OperatorCast_CannotCastString;
+
+       public static String OperatorIndirection_RequiresPointer;
+       public static String OperatorIndirection_NoBitField;
+       public static String OperatorIndirection_NoFunction;
+       public static String OperatorIndirection_UnhandledType;
+
+       public static String OperatorMinus_NonPtrMinusPtr;
+       public static String OperatorPlus_PtrPlusPtr;
+
+       public static String VariableWithValue_CannotLocateVariable;
+       public static String VariableWithValue_NoTwelveByteLongDouble; 
+       public static String VariableWithValue_UnhandledType;
+       public static String VariableWithValue_UnknownLocation;
+       public static String VariableWithValue_VariableHasNoType;
+
+       static {
+               // initialize resource bundle
+               NLS.initializeMessages(BUNDLE_NAME, ASTEvalMessages.class);
+       }
+
+       private ASTEvalMessages() {
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTEvalMessages.properties b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTEvalMessages.properties
new file mode 100644 (file)
index 0000000..e7d930a
--- /dev/null
@@ -0,0 +1,55 @@
+###############################################################################
+# Copyright (c) 2010 Nokia and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Nokia - Initial API and implementation
+###############################################################################
+DivideByZero=divide by zero
+ASTEvaluationEngine_DidNotDetectType=did not detect type
+ASTInstructionCompiler_InvalidNumber=invalid number format
+ArraySubscript_ArrayHasNoBounds=array type has no bounds
+ArraySubscript_CannotIndirectTemporary=cannot indirect temporary
+ArraySubscript_ErrorDereferencingArray=error dereferencing array
+ArraySubscript_MustSubscriptArray=only arrays or pointers may be subscripted
+ArraySubscript_ReadingPastEndOfString=reading past end of string
+ArraySubscript_SubscriptMustBeInteger=subscript not an integral type
+UnhandledSize=unhandled size {0}
+EvaluateID_CannotResolveName=cannot resolve {0}
+EvaluateID_NameHasNoLocation=no location found for {0}
+EvaluateID_VariableNotFound=''{0}'' not found
+FieldReference_InvalidPointerDeref=left operand of '->' not a pointer to a class, struct, or union
+FieldReference_InvalidDotDeref=left operand of '.' not a class, struct, or union, or reference to one
+FieldReference_InvalidMember=''{0}'' is an invalid class, struct, or union member
+FieldReference_AmbiguousMember=''{0}'' matches 2 or more members (possibly inherited) of ''{1}''
+FieldReference_CannotDereferenceType=cannot dereference this type
+FieldReference_UnhandledOperandSize=unhandled operand size 
+GetValue_TypePromotionError=internal error: type promotion failure
+Instruction_CannotUseCompositeType=cannot use composite type in expression
+Instruction_EmptyStack=empty stack
+Instruction_UnhandledTypeCombination=unhandled type combination {0} and {1}
+UnhandledTypeCode=unhandled type code 
+UnsupportedStringOperation=operation not supported on strings
+OperandValue_CannotGetAddress=cannot get address of {0}
+OperandValue_CannotReadUnspecifiedType=cannot read from unspecified type
+OperandValue_CannotReadVoid=cannot read from void
+OperandValue_UnhandledType=Unhandled type
+OperandValue_VariableNoAddress=variable has no address
+OperatorAddrOf_RequiresVariable=unary '&' requires a memory location
+OperatorAddrOf_NoRegister=cannot get memory address of the variable because it is in register
+OperatorAddrOf_NoBitField=cannot get memory address of a bit-field
+OperatorCast_CannotCastString=cannot cast string literal
+OperatorIndirection_RequiresPointer=unary '*' requires a pointer
+OperatorIndirection_NoBitField=unary '*' cannot be applied to a bit-field
+OperatorIndirection_NoFunction=cannot dereference a function pointer
+OperatorIndirection_UnhandledType=unhandled type {0}
+OperatorMinus_NonPtrMinusPtr=subtracting pointer from non-pointer
+OperatorPlus_PtrPlusPtr=adding two pointers
+VariableWithValue_CannotLocateVariable=Cannot locate variable
+VariableWithValue_NoTwelveByteLongDouble=12-byte long double not implemented
+VariableWithValue_UnhandledType=Unhandled type 
+VariableWithValue_UnknownLocation=unknown location
+VariableWithValue_VariableHasNoType=Variable has no type
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTEvaluationEngine.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTEvaluationEngine.java
new file mode 100644 (file)
index 0000000..b501681
--- /dev/null
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.core.dom.ast.ASTVisitor;
+import org.eclipse.cdt.core.dom.ast.IASTProblem;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.ast.IASTTypeId;
+import org.eclipse.cdt.core.dom.parser.ISourceCodeParser;
+import org.eclipse.cdt.core.dom.parser.c.GCCScannerExtensionConfiguration;
+import org.eclipse.cdt.core.dom.parser.cpp.GPPParserExtensionConfiguration;
+import org.eclipse.cdt.core.parser.FileContent;
+import org.eclipse.cdt.core.parser.IScanner;
+import org.eclipse.cdt.core.parser.IScannerInfo;
+import org.eclipse.cdt.core.parser.IncludeFileContentProvider;
+import org.eclipse.cdt.core.parser.NullLogService;
+import org.eclipse.cdt.core.parser.ParserLanguage;
+import org.eclipse.cdt.core.parser.ParserMode;
+import org.eclipse.cdt.core.parser.ScannerInfo;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.InstructionSequence;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.Interpreter;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.symbols.TypeEngine;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.GNUCPPSourceParser;
+import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
+import org.eclipse.core.runtime.CoreException;
+
+@SuppressWarnings("restriction")
+public class ASTEvaluationEngine {
+
+       public static final String UNKNOWN_TYPE = "<UNKNOWN>"; //$NON-NLS-1$
+       private final EDCServicesTracker tracker;
+       private final IDMContext context;
+       private final TypeEngine typeEngine;
+
+       private static final Map<String, InstructionSequence> compiledExpressionsCache =
+               Collections.synchronizedMap(new HashMap<String, InstructionSequence>());
+
+       /**
+        * @param context 
+        * @param tracker 
+        * 
+        */
+       public ASTEvaluationEngine(EDCServicesTracker tracker, IDMContext context, TypeEngine typeEngine) {
+               this.tracker = tracker;
+               this.context = context;
+               this.typeEngine = typeEngine;
+       }
+       
+       public InstructionSequence getCompiledExpression(String expression) throws CoreException {
+
+               // the creation and parsing of the AST can get expensive so we cache it for
+               // the given expression
+               InstructionSequence instructions = compiledExpressionsCache.get(expression);
+               if (instructions == null) {
+                       FileContent reader = FileContent.create("<edc-expression>", ("void* dummy_func() { return " + //$NON-NLS-1$ //$NON-NLS-2$
+                                       expression + " ; }").toCharArray()); //$NON-NLS-1$
+                       IScannerInfo scannerInfo = new ScannerInfo(); // creates an empty scanner info
+                       IScanner scanner = new CPreprocessor(reader, scannerInfo, ParserLanguage.CPP, new NullLogService(), GCCScannerExtensionConfiguration.getInstance(), IncludeFileContentProvider.getEmptyFilesProvider());
+                       ISourceCodeParser parser = new GNUCPPSourceParser(scanner, ParserMode.COMPLETE_PARSE, new NullLogService(), GPPParserExtensionConfiguration.getInstance(), null);
+                       IASTTranslationUnit ast = parser.parse();
+                       
+                       ASTInstructionCompiler visitor = new ASTInstructionCompiler(expression);
+                       ast.accept(visitor);
+                       
+                       if (visitor.hasErrors())
+                               throw EDCDebugger.newCoreException(visitor.getErrorMessage());
+
+                       instructions = visitor.getInstructions();
+
+                       // Remove NoOps
+                       instructions.removeNoOps();
+
+                       compiledExpressionsCache.put(expression, instructions);
+               }
+
+               
+               // make a copy of the cached generic instruction sequence since we'll make
+               // context specific changes below (reduceCasts)
+               InstructionSequence sequence = new InstructionSequence(instructions);
+
+               // Reduce (possibly internally generated) cast expressions to avoid 
+               // taking the address of a register or bitfield.
+               sequence.reduceCasts(typeEngine);
+               
+               return sequence;
+
+       }
+
+       public Interpreter evaluateCompiledExpression(InstructionSequence expression) throws CoreException {
+               Interpreter interpreter = new Interpreter(tracker, context, typeEngine, expression);
+               interpreter.execute();
+               return interpreter;
+       }
+
+       /**
+        * Get the type engine
+        * @return
+        */
+       public TypeEngine getTypeEngine() {
+               return typeEngine;
+       }
+
+       
+       static private class ASTTypeVisitor extends ASTVisitor {
+               private IASTTypeId theType;
+               private String errorMessage;
+               
+               {
+                       shouldVisitTypeIds = true;
+                       shouldVisitProblems = true;
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.core.dom.ast.ASTVisitor#visit(org.eclipse.cdt.core.dom.ast.IASTTypeId)
+                */
+               @Override
+               public int visit(IASTTypeId typeId) {
+                       theType = typeId;
+                       return PROCESS_ABORT;
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.core.dom.ast.ASTVisitor#visit(org.eclipse.cdt.core.dom.ast.IASTProblem)
+                */
+               @Override
+               public int visit(IASTProblem problem) {
+                       errorMessage = problem.getMessage();
+                       return PROCESS_ABORT;
+               }
+       }
+       /**
+        * Parse the given type string and get the AST tree for it
+        * @param type
+        * @return IASTTypeId instance
+        * @throws CoreException
+        */
+       public IASTTypeId getCompiledType(String type) throws CoreException {
+
+               FileContent reader = FileContent.create("<edc-expression>", ("void* dummy_func() { typeof(" + //$NON-NLS-1$ //$NON-NLS-2$
+                                                       type + ") x; }").toCharArray()); //$NON-NLS-1$
+               IScannerInfo scannerInfo = new ScannerInfo(); // creates an empty scanner info
+               IScanner scanner = new CPreprocessor(reader, scannerInfo, ParserLanguage.CPP, new NullLogService(), GCCScannerExtensionConfiguration.getInstance(), IncludeFileContentProvider.getEmptyFilesProvider());
+               ISourceCodeParser parser = new GNUCPPSourceParser(scanner, ParserMode.COMPLETE_PARSE, new NullLogService(), GPPParserExtensionConfiguration.getInstance(), null);
+               IASTTranslationUnit ast = parser.parse();
+
+               ASTTypeVisitor visitor = new ASTTypeVisitor();
+               ast.accept(visitor);
+               if (visitor.errorMessage != null)
+                       throw EDCDebugger.newCoreException(visitor.errorMessage);
+               if (visitor.theType == null)
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.ASTEvaluationEngine_DidNotDetectType);
+               
+               return visitor.theType;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTInstructionCompiler.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/ASTInstructionCompiler.java
new file mode 100644 (file)
index 0000000..6b0d3fe
--- /dev/null
@@ -0,0 +1,522 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine;
+
+import java.util.Stack;
+
+import org.eclipse.cdt.core.dom.ast.ASTVisitor;
+import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
+import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
+import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
+import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
+import org.eclipse.cdt.core.dom.ast.IASTComment;
+import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTExpression;
+import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
+import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
+import org.eclipse.cdt.core.dom.ast.IASTProblem;
+import org.eclipse.cdt.core.dom.ast.IASTStatement;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.ast.IASTTypeId;
+import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
+import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.ArraySubscript;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.CompoundInstruction;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.EvaluateID;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.FieldReference;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.Instruction;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.InstructionSequence;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.NoOp;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorAddrOf;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorBinaryAnd;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorBinaryOr;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorBinaryXor;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorBitwiseNot;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorCast;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorCastValue;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorDivide;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorEquals;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorGreaterEqual;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorGreaterThan;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorIndirection;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorLessEqual;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorLessThan;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorLogicalAnd;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorLogicalNot;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorLogicalOr;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorMinus;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorModulo;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorMultiply;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorNotEquals;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorPlus;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorShiftLeft;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorShiftRight;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorUnaryMinus;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperatorUnaryPlus;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.PushBoolean;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.PushChar;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.PushDouble;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.PushFloat;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.PushLongOrBigInteger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.PushString;
+import org.eclipse.cdt.debug.edc.symbols.TypeEngine;
+import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode;
+
+@SuppressWarnings("restriction")
+public class ASTInstructionCompiler extends ASTVisitor {
+
+       private final Stack<Instruction> stack;
+       private final InstructionSequence instructions;
+       private int counter;
+       private String errorMessage;
+       private boolean active = true;
+
+       public ASTInstructionCompiler( String snippet) {
+               super(true);
+               stack = new Stack<Instruction>();
+               instructions = new InstructionSequence(snippet);
+       }
+
+       private void push(Instruction i) {
+               stack.push(i);
+       }
+
+       private Instruction pop() {
+               return stack.pop();
+       }
+
+       /**
+        * Returns the instruction sequence generated by this AST instruction
+        * compiler
+        */
+       public InstructionSequence getInstructions() {
+               return instructions;
+       }
+
+       public boolean hasErrors() {
+               return errorMessage != null;
+       }
+
+       public String getErrorMessage() {
+               return errorMessage;
+       }
+
+       private boolean isActive() {
+               return active;
+       }
+
+       private void storeInstruction() {
+               Instruction instruction = pop();
+               counter++;
+               if (instruction instanceof CompoundInstruction) {
+                       ((CompoundInstruction) instruction).setEnd(counter);
+               }
+               instructions.add(instruction);
+       }
+
+       @Override
+       public int leave(IASTArrayModifier arrayModifier) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(arrayModifier)); }
+               return super.leave(arrayModifier);
+       }
+
+       @SuppressWarnings("deprecation")        // we're simply wrapping a deprecated method
+       @Override
+       public int leave(IASTComment comment) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(comment)); }
+               return super.leave(comment);
+       }
+
+       @Override
+       public int leave(IASTDeclaration declaration) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(declaration)); }
+               return super.leave(declaration);
+       }
+
+       @Override
+       public int leave(IASTDeclarator declarator) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(declarator)); }
+               return super.leave(declarator);
+       }
+
+       @Override
+       public int leave(IASTDeclSpecifier declSpec) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(declSpec)); }
+               return super.leave(declSpec);
+       }
+
+       @Override
+       public int leave(IASTEnumerator enumerator) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(enumerator)); }
+               return super.leave(enumerator);
+       }
+
+       @Override
+       public int leave(IASTExpression expression) {
+               if (!isActive() || hasErrors())
+                       return PROCESS_CONTINUE;
+               storeInstruction();
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(expression)); }
+               return super.leave(expression);
+       }
+
+       @Override
+       public int leave(IASTInitializer initializer) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(initializer)); }
+               return super.leave(initializer);
+       }
+
+       @Override
+       public int leave(IASTName name) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(name)); }
+               return super.leave(name);
+       }
+
+       @Override
+       public int leave(IASTParameterDeclaration parameterDeclaration) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(parameterDeclaration)); }
+               return super.leave(parameterDeclaration);
+       }
+
+       @Override
+       public int leave(IASTPointerOperator ptrOperator) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(ptrOperator)); }
+               return super.leave(ptrOperator);
+       }
+
+       @Override
+       public int leave(IASTProblem problem) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(problem)); }
+               return super.leave(problem);
+       }
+
+       @Override
+       public int leave(IASTStatement statement) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(statement)); }
+               return super.leave(statement);
+       }
+
+       @Override
+       public int leave(IASTTranslationUnit tu) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(tu)); }
+               return super.leave(tu);
+       }
+
+       @Override
+       public int leave(IASTTypeId typeId) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(typeId)); }
+               return super.leave(typeId);
+       }
+
+       @Override
+       public int visit(IASTArrayModifier arrayModifier) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(arrayModifier)); }
+               return super.visit(arrayModifier);
+       }
+
+       @SuppressWarnings("deprecation")        // we're simply wrapping a deprecated method
+       @Override
+       public int visit(IASTComment comment) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(comment)); }
+               return super.visit(comment);
+       }
+
+       @Override
+       public int visit(IASTDeclaration declaration) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(declaration)); }
+               return super.visit(declaration);
+       }
+
+       @Override
+       public int visit(IASTDeclarator declarator) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(declarator)); }
+               return super.visit(declarator);
+       }
+
+       @Override
+       public int visit(IASTDeclSpecifier declSpec) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(declSpec)); }
+               return super.visit(declSpec);
+       }
+
+       @Override
+       public int visit(IASTEnumerator enumerator) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(enumerator)); }
+               return super.visit(enumerator);
+       }
+
+       @Override
+       public int visit(IASTInitializer initializer) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(initializer)); }
+               return super.visit(initializer);
+       }
+
+       @Override
+       public int visit(IASTParameterDeclaration parameterDeclaration) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg("visit: " + parameterDeclaration.getClass().getSimpleName())); } //$NON-NLS-1$
+               return super.visit(parameterDeclaration);
+       }
+
+       @Override
+       public int visit(IASTPointerOperator ptrOperator) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(ptrOperator)); }
+               return super.visit(ptrOperator);
+       }
+
+       @Override
+       public int visit(IASTStatement statement) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(statement)); }
+               return super.visit(statement);
+       }
+
+       @Override
+       public int visit(IASTTranslationUnit tu) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(tu)); }
+               return super.visit(tu);
+       }
+
+       @Override
+       public int visit(IASTTypeId typeId) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(typeId)); }
+               return super.visit(typeId);
+       }
+
+       @Override
+       public int visit(ASTAmbiguousNode astAmbiguousNode) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(astAmbiguousNode)); }
+               return super.visit(astAmbiguousNode);
+       }
+
+       @Override
+       public int visit(IASTName name) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(name)); }
+               return super.visit(name);
+       }
+
+       @Override
+       public int visit(IASTProblem problem) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(problem)); }
+               return super.visit(problem);
+       }
+
+       @Override
+       public int visit(IASTExpression expression) {
+               if (EDCTrace.EXPRESSION_PARSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(expression)); }
+
+               if (expression instanceof IASTLiteralExpression) {
+                       visitLiteralExpression((IASTLiteralExpression) expression);
+               } else if (expression instanceof IASTBinaryExpression) {
+                       visitBinaryExpression((IASTBinaryExpression) expression);
+               } else if (expression instanceof IASTUnaryExpression) {
+                       visitUnaryExpression((IASTUnaryExpression) expression);
+               } else if (expression instanceof IASTIdExpression) {
+                       visitIDExpression((IASTIdExpression) expression);
+               } else if (expression instanceof IASTArraySubscriptExpression) {
+                       visitArraySubscriptExpression((IASTArraySubscriptExpression) expression);
+               } else if (expression instanceof IASTFieldReference) {
+                       visitFieldReference((IASTFieldReference) expression);
+               } else if (expression instanceof IASTCastExpression) {
+                       visitCastExpression((IASTCastExpression) expression);
+               } else
+                       push(new NoOp(counter));
+
+               return super.visit(expression);
+       }
+
+       private void visitIDExpression(IASTIdExpression expression) {
+               push(new EvaluateID(expression));
+       }
+
+       private void visitArraySubscriptExpression(IASTArraySubscriptExpression expression) {
+               push(new ArraySubscript(counter));
+       }
+
+       private void visitFieldReference(IASTFieldReference expression) {
+               push(new FieldReference(expression, counter));
+       }
+
+       private void visitCastExpression(IASTCastExpression expression) {
+               if (expression.getOperator() == ICPPASTCastExpression.op_reinterpret_cast) 
+                       push(new OperatorCastValue(counter, expression));
+               else
+                       push(new OperatorCast(counter, expression));
+       }
+
+       private void visitLiteralExpression(IASTLiteralExpression expression) {
+               int kind = expression.getKind();
+               String value = new String(expression.getValue());
+               switch (kind) {
+               case IASTLiteralExpression.lk_integer_constant:
+                       try {
+                               push(new PushLongOrBigInteger(value));
+                       } catch (NumberFormatException nfe) {
+                               errorMessage = ASTEvalMessages.ASTInstructionCompiler_InvalidNumber;
+                       }
+                       break;
+               case IASTLiteralExpression.lk_float_constant:
+                       // check for explicitly float constant
+                       try {
+                               if (value.toUpperCase().endsWith("F")) //$NON-NLS-1$
+                                       push(new PushFloat(value));
+                               else
+                                       push(new PushDouble(value));
+                       } catch (NumberFormatException nfe) {
+                               errorMessage = ASTEvalMessages.ASTInstructionCompiler_InvalidNumber;
+                       }
+                       break;
+               case IASTLiteralExpression.lk_char_constant:
+                       try {
+                               push(new PushChar(value));
+                       } catch (NumberFormatException nfe) {
+                               errorMessage = ASTEvalMessages.ASTInstructionCompiler_InvalidNumber;
+                       }
+                       break;
+               case IASTLiteralExpression.lk_string_literal:
+                       push(new PushString(value));
+                       break;
+               case IASTLiteralExpression.lk_false:
+                       push(new PushBoolean(false));
+                       break;
+               case IASTLiteralExpression.lk_true:
+                       push(new PushBoolean(true));
+                       break;
+               case IASTLiteralExpression.lk_this:
+                       push(new EvaluateID("this")); //$NON-NLS-1$
+                       break;
+               default:
+                       push(new NoOp(counter));
+               }
+       }
+
+       private void visitBinaryExpression(IASTBinaryExpression expression) {
+               int op = expression.getOperator();
+
+               switch (op) {
+               case IASTBinaryExpression.op_binaryAnd:
+                       push(new OperatorBinaryAnd(counter));
+                       break;
+
+               case IASTBinaryExpression.op_binaryOr:
+                       push(new OperatorBinaryOr(counter));
+                       break;
+
+               case IASTBinaryExpression.op_binaryXor:
+                       push(new OperatorBinaryXor(counter));
+                       break;
+
+               case IASTBinaryExpression.op_plus:
+                       push(new OperatorPlus(counter));
+                       break;
+
+               case IASTBinaryExpression.op_minus:
+                       push(new OperatorMinus(counter));
+                       break;
+
+               case IASTBinaryExpression.op_multiply:
+                       push(new OperatorMultiply(counter));
+                       break;
+
+               case IASTBinaryExpression.op_divide:
+                       push(new OperatorDivide(counter));
+                       break;
+
+               case IASTBinaryExpression.op_modulo:
+                       push(new OperatorModulo(counter));
+                       break;
+
+               case IASTBinaryExpression.op_shiftLeft:
+                       push(new OperatorShiftLeft(counter));
+                       break;
+
+               case IASTBinaryExpression.op_shiftRight:
+                       push(new OperatorShiftRight(counter));
+                       break;
+
+               case IASTBinaryExpression.op_equals:
+                       push(new OperatorEquals(counter));
+                       break;
+
+               case IASTBinaryExpression.op_notequals:
+                       push(new OperatorNotEquals(counter));
+                       break;
+
+               case IASTBinaryExpression.op_greaterEqual:
+                       push(new OperatorGreaterEqual(counter));
+                       break;
+
+               case IASTBinaryExpression.op_greaterThan:
+                       push(new OperatorGreaterThan(counter));
+                       break;
+
+               case IASTBinaryExpression.op_lessEqual:
+                       push(new OperatorLessEqual(counter));
+                       break;
+
+               case IASTBinaryExpression.op_lessThan:
+                       push(new OperatorLessThan(counter));
+                       break;
+
+               case IASTBinaryExpression.op_logicalAnd:
+                       push(new OperatorLogicalAnd(counter));
+                       break;
+
+               case IASTBinaryExpression.op_logicalOr:
+                       push(new OperatorLogicalOr(counter));
+                       break;
+
+               default:
+                       push(new NoOp(counter));
+               }
+       }
+
+       private void visitUnaryExpression(IASTUnaryExpression expression) {
+               int op = expression.getOperator();
+
+               switch (op) {
+               case IASTUnaryExpression.op_minus:
+                       push(new OperatorUnaryMinus(counter));
+                       break;
+
+               case IASTUnaryExpression.op_not:
+                       push(new OperatorLogicalNot(counter));
+                       break;
+
+               case IASTUnaryExpression.op_plus:
+                       push(new OperatorUnaryPlus(counter));
+                       break;
+
+               case IASTUnaryExpression.op_tilde:
+                       push(new OperatorBitwiseNot(counter));
+                       break;
+
+               case IASTUnaryExpression.op_star:
+                       push(new OperatorIndirection(counter));
+                       break;
+
+               case IASTUnaryExpression.op_amper:
+                       push(new OperatorAddrOf(counter));
+                       break;
+
+               default:
+                       push(new NoOp(counter));
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/ArrayDimensionType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/ArrayDimensionType.java
new file mode 100644 (file)
index 0000000..7897423
--- /dev/null
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.Type;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+
+// Internal expression type to hold all dimensions of a multidimensional array except the smallest.
+// E.g., for "int a[6][7][8];", this type might hold info about "a[2]" or "a[2][4]", but not "a[2][4][3]".
+public class ArrayDimensionType extends Type implements IArrayDimensionType {
+
+       private final OperandValue value; // needed for scope,
+                                                                                                               // frame, services
+                                                                                                               // tracker, etc.
+       private final IArrayType arrayType;
+       private IVariableLocation location;
+       private int dimensionCount; // number of dimensions processed so far
+
+       public ArrayDimensionType(String name, OperandValue value, IArrayType arrayType, IVariableLocation location) {
+               super(name, null, 0, null);
+               this.value = value;
+               this.arrayType = arrayType;
+               this.location = location;
+               this.dimensionCount = 1;
+       }
+
+       public OperandValue getOperandValue() {
+               return this.value;
+       }
+
+       public IArrayType getArrayType() {
+               return this.arrayType;
+       }
+
+       public IVariableLocation getLocation() {
+               return this.location;
+       }
+
+       public int getDimensionCount() {
+               return this.dimensionCount;
+       }
+
+       public void addDimension(long subscript, long increase) {
+               this.name += "[" + subscript + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+               this.location = location.addOffset(increase);
+               this.dimensionCount++;
+       }
+
+       @Override
+       public IType getType() {
+               return null;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/ArraySubscript.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/ArraySubscript.java
new file mode 100644 (file)
index 0000000..f5971f5
--- /dev/null
@@ -0,0 +1,227 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.IAggregate;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IEnumeration;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ITypedef;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.cdt.debug.edc.symbols.VariableLocationFactory;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Array subscript instruction
+ */
+public class ArraySubscript extends CompoundInstruction {
+
+       /**
+        * Constructor for array subscript instruction
+        * 
+        * @param expression
+        *            - array subscript expression
+        * @param start
+        *            - instruction start
+        */
+       public ArraySubscript(int start) {
+               super(start);
+       }
+
+       /**
+        * Resolve an array subscript expression
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() throws CoreException {
+               OperandValue subscriptOperand = popValue();
+               OperandValue variableOperand = popValue();
+
+               long subscript = 0;
+
+               if (subscriptOperand.isFloating())
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.ArraySubscript_SubscriptMustBeInteger);
+               
+               subscript = subscriptOperand.getLongValue();
+
+               IType variableType = TypeUtils.getStrippedType(variableOperand.getValueType());
+
+               IArrayType arrayType;
+               IVariableLocation location = null;
+               IType arrayElementType;
+               int byteSize;
+
+               if (variableType instanceof IArrayDimensionType)
+                       arrayElementType = TypeUtils.getStrippedType(((IArrayDimensionType) variableType).getArrayType().getType());
+               else
+                       arrayElementType = TypeUtils.getStrippedType(variableType.getType());
+               if (arrayElementType == null)
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.ArraySubscript_MustSubscriptArray);
+               
+               if (variableType instanceof IArrayType)
+                       byteSize = variableType.getByteSize();
+               else
+                       byteSize = arrayElementType.getByteSize();
+                       
+
+               IVariableLocation varLocation = variableOperand.getValueLocation();
+               if (varLocation == null) {
+                       // may be a string...
+                       String stringValue = variableOperand.getStringValue();
+                       if (stringValue != null) {
+                               if (subscript < stringValue.length()) {
+                                       pushNewValue(arrayElementType, (int) stringValue.charAt((int) subscript));
+                               } else if (subscript == stringValue.length()) {
+                                       pushNewValue(arrayElementType, 0);
+                               } else {
+                                       throw EDCDebugger.newCoreException(ASTEvalMessages.ArraySubscript_ReadingPastEndOfString);
+                               }
+                               return;
+                       }
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.ArraySubscript_CannotIndirectTemporary);
+               }
+
+               // If the variable type is just a pointer, then add the pointer base type's size
+               //
+               // *(ptr+element)
+               if (variableType instanceof IPointerType) {
+                       IPointerType pointerType = (IPointerType) variableType;
+                       
+                       // dereference ptr
+                       BigInteger ptrValue = varLocation.readValue(pointerType.getByteSize());
+                       
+                       // point into array
+                       location = VariableLocationFactory.createMemoryVariableLocation(
+                                       fInterpreter.getServicesTracker(), fInterpreter.getContext(), 
+                                       ptrValue.add(BigInteger.valueOf(byteSize * subscript)));
+
+                       // dereference to fetch offset 
+                       OperandValue op = new OperandValue(pointerType.getType());
+                       
+                       op.setValueLocation(VariableLocationFactory.createMemoryVariableLocation(
+                                       fInterpreter.getServicesTracker(), fInterpreter.getContext(), 
+                                       location.getAddress().getValue()));
+                       
+                       // read actual value
+                       Number newValue = op.getValueByType(op.getValueType(), op.getValueLocation());
+                       op.setValue(newValue);
+                       push(op);
+                       
+                       return;
+
+               }
+               
+               // if the variable is an IArrayType, there are two cases:
+               //   we're accessing a single element of a one dimensional array
+               //   we're accessing an entire dimension of a multidimensional array
+               if (variableType instanceof IArrayType) {
+
+                       arrayType = (IArrayType) variableType;
+
+                       if (arrayType.getBoundsCount() == 0) {
+                               throw EDCDebugger.newCoreException(ASTEvalMessages.ArraySubscript_ArrayHasNoBounds);
+                       }
+
+                       // find the location of indexed 1st dimension element, or of entire
+                       // dimension
+                       location = varLocation.addOffset(arrayType.getBounds()[0].getElementCount() * byteSize
+                                                       * subscript);
+
+                       if (arrayType.getBoundsCount() == 1) {
+                               // we're accessing a single element of a one dimensional array
+                               pushArrayElement(variableOperand, location, arrayElementType);
+                       } else {
+                               String name = variableOperand.getValueType().getName() + "[" + subscript + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+                               ArrayDimensionType arrayDimensionType = new ArrayDimensionType(name, variableOperand, arrayType,
+                                               location);
+                               OperandValue opValue = new OperandValue(arrayDimensionType);
+
+                               opValue.setAddressValue(location);
+                               opValue.setValueLocation(location);
+                               push(opValue);
+                       }
+                       return;
+               }
+
+               if (!(variableType instanceof IArrayDimensionType)) {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.ArraySubscript_MustSubscriptArray);
+               }
+
+               // if the variable is an ArrayDimensionType, there are two cases:
+               //   we're accessing a single element of a multidimensional array
+               //   we're accessing another entire dimension of a multidimensional array
+               ArrayDimensionType arrayDimension = (ArrayDimensionType) variableType;
+               arrayType = arrayDimension.getArrayType();
+               arrayElementType = TypeUtils.getStrippedType(arrayType.getType());
+
+               byteSize = arrayElementType.getByteSize();
+               if (arrayElementType instanceof ITypedef) {
+                       byteSize = TypeUtils.getStrippedType(arrayElementType.getType()).getByteSize();
+               }
+
+               arrayDimension.addDimension(subscript, arrayType.getBound(arrayDimension.getDimensionCount()).getElementCount()
+                               * byteSize * subscript);
+               location = arrayDimension.getLocation();
+
+               if (arrayDimension.getDimensionCount() >= arrayType.getBoundsCount()) {
+                       // we're accessing a single element of a multidimensional array
+                       pushArrayElement(arrayDimension.getOperandValue(), location, arrayElementType);
+               } else {
+                       // we're accessing another entire dimension of a multidimensional
+                       // array
+                       variableOperand.setAddressValue(location);
+                       variableOperand.setValueLocation(location);
+                       push(variableOperand);
+               }
+       }
+
+       private void pushArrayElement(OperandValue originalVariableValue, IVariableLocation location, IType arrayElementType) throws CoreException {
+               OperandValue varValue = new OperandValue(arrayElementType);
+
+               varValue.setValueLocation(location);
+
+               // for a lvalues (base arithmetic types, enums, and pointers), read the
+               // value and cast it to the right type
+               if (arrayElementType instanceof IBasicType || arrayElementType instanceof IEnumeration
+                               || arrayElementType instanceof IPointerType) {
+                       int byteSize = arrayElementType.getByteSize();
+
+                       // TODO support 12-byte long double
+                       if (byteSize != 1 && byteSize != 2 && byteSize != 4 && byteSize != 8) {
+                               throw EDCDebugger.newCoreException(MessageFormat.format(ASTEvalMessages.UnhandledSize, byteSize));
+                       }
+
+                       // read the value pointed to
+                       Number newValue = originalVariableValue.getValueByType(arrayElementType, location);
+                       varValue.setValue(newValue);
+                       push(varValue);
+
+               } else if (arrayElementType instanceof IAggregate) {
+                       // for aggregates, the address of the aggregate is the value
+                       // returned
+                       varValue.setAddressValue(location);
+                       push(varValue);
+
+               } else {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.ArraySubscript_ErrorDereferencingArray);
+               }
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/BinaryLogicalOperator.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/BinaryLogicalOperator.java
new file mode 100644 (file)
index 0000000..44911a5
--- /dev/null
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary logical operator, such as "<"
+ */
+public abstract class BinaryLogicalOperator extends CompoundInstruction {
+
+       /**
+        * Constructor for a binary logical operator, such as "<"
+        * 
+        * @param resultId - for assignment, variable ID of the result 
+        * @param isAssignmentOperator - whether the result is assigned
+        * @param start - instruction start
+        */
+       protected BinaryLogicalOperator(int resultId, boolean isAssignmentOperator, int start) {
+               super(start);
+       }
+
+       /**
+        * Resolve a binary logical operator, such as "<"
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() throws CoreException {
+               OperandValue right = popValue();
+               OperandValue left = popValue();
+
+               right = convertForPromotion(right);
+               left = convertForPromotion(left);
+
+               int promotedType = getJavaBinaryPromotionType(right, left);
+               IType type = fInterpreter.getTypeEngine().getBooleanType(1);
+               
+               switch (promotedType) {
+               case T_String:
+                       pushNewValue(type, getStringResult(GetValue.getStringValue(left), GetValue.getStringValue(right)));
+                       break;
+               case T_double:
+                       pushNewValue(type, getDoubleResult(GetValue.getDoubleValue(left), GetValue.getDoubleValue(right)));
+                       break;
+               case T_float:
+                       pushNewValue(type, getFloatResult(GetValue.getFloatValue(left), GetValue.getFloatValue(right)));
+                       break;
+               case T_long:
+                       pushNewValue(type, getLongResult(GetValue.getLongValue(left), GetValue.getLongValue(right)));
+                       break;
+               case T_int:
+                       pushNewValue(type, getIntResult(GetValue.getIntValue(left), GetValue.getIntValue(right)));
+                       break;
+               case T_boolean:
+                       pushNewValue(type, getBooleanResult(GetValue.getBooleanValue(left), GetValue.getBooleanValue(right)));
+                       break;
+               case T_BigInt:
+                       pushNewValue(type, getBigIntegerResult(GetValue.getBigIntegerValue(left), GetValue.getBigIntegerValue(right)));
+                       break;
+               }
+       }
+
+       /**
+        * Get boolean result of applying a binary logical operation to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract boolean getIntResult(int leftOperand, int rightOperand) throws CoreException;
+
+       /**
+        * Get boolean result of applying a binary logical operation to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract boolean getLongResult(long leftOperand, long rightOperand) throws CoreException;
+
+       /**
+        * Get boolean result of applying a binary logical operation to two
+        * BigIntegers
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract boolean getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand)
+                       throws CoreException;
+
+       /**
+        * Get boolean result of applying a binary logical operation to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract boolean getFloatResult(float leftOperand, float rightOperand);
+
+       /**
+        * Get boolean result of applying a binary logical operation to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract boolean getDoubleResult(double leftOperand, double rightOperand);
+
+       /**
+        * Get boolean result of applying a binary logical operation to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract boolean getBooleanResult(boolean leftOperand, boolean rightOperand);
+
+       /**
+        * Get boolean result of applying a binary logical operation to two strings
+        * 
+        * @param leftOperand
+        *            - left string operand
+        * @param rightOperand
+        *            - right string operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract boolean getStringResult(String leftOperand, String rightOperand) throws CoreException;
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/BinaryOperator.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/BinaryOperator.java
new file mode 100644 (file)
index 0000000..b289f63
--- /dev/null
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary arithmetic operator, such as "/"
+ */
+public abstract class BinaryOperator extends CompoundInstruction {
+
+       /**
+        * Constructor for a binary arithmetic operator, such as "/"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected BinaryOperator(int resultId, boolean isAssignmentOperator, int start) {
+               super(start);
+       }
+
+       /**
+        * Resolve a binary arithmetic operator, such as "/"
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() throws CoreException {
+               OperandValue right = popValue();
+               OperandValue left = popValue();
+
+               right = convertForPromotion(right);
+               left = convertForPromotion(left);
+
+               if (customHandleOperation(fInterpreter, left, right))
+                       return;
+
+               int resultType = getJavaBinaryPromotionType(right, left);
+               IType type;
+               if (resultType == T_String)
+                       type = left.getValueType();
+               else
+                       type = getBinaryPromotionType(right, left);
+               
+               // non-logical operations on booleans are int results
+               if ((type instanceof ICPPBasicType) && ((ICPPBasicType) type).getBaseType() == ICPPBasicType.t_bool) {
+                       type = fInterpreter.getTypeEngine().getIntegerTypeFor(TypeUtils.BASIC_TYPE_INT, true);
+               }
+
+               switch (resultType) {
+               case T_String:
+                       pushNewValue(type, getStringResult(GetValue.getStringValue(left), GetValue.getStringValue(right)));
+                       break;
+               case T_double:
+                       pushNewValue(type, getDoubleResult(GetValue.getDoubleValue(left), GetValue.getDoubleValue(right)));
+                       break;
+               case T_float:
+                       pushNewValue(type, getFloatResult(GetValue.getFloatValue(left), GetValue.getFloatValue(right)));
+                       break;
+               case T_long:
+                       pushNewValue(type, getLongResult(GetValue.getLongValue(left), GetValue.getLongValue(right)));
+                       break;
+               case T_int:
+                       pushNewValue(type, getIntResult(GetValue.getIntValue(left), GetValue.getIntValue(right)));
+                       break;
+               case T_boolean:
+                       pushNewValue(type, getBooleanResult(GetValue.getBooleanValue(left), GetValue.getBooleanValue(right)));
+                       break;
+               case T_BigInt:
+                       pushNewValue(type, getBigIntegerResult(GetValue.getBigIntegerValue(left), GetValue.getBigIntegerValue(right), 8));
+                       break;
+               default:
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.UnhandledTypeCode + resultType);
+               }
+       }
+
+       /**
+        * Handle type operation in a non-standard way
+        * @param fInterpreter
+        * @param left
+        * @param right
+        * @return true if handled
+        */
+       protected boolean customHandleOperation(Interpreter fInterpreter, OperandValue left, OperandValue right) throws CoreException {
+               return false;
+       }
+
+       /**
+        * Get int result of applying a binary operation to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return int result of the operation if possible, or an operation-specific
+        *         default
+        * @throws CoreException
+        */
+       protected abstract int getIntResult(int leftOperand, int rightOperand) throws CoreException;
+
+       /**
+        * Get long result of applying a binary operation to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return long result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract long getLongResult(long leftOperand, long rightOperand) throws CoreException;
+
+       /**
+        * Get BigInteger result of applying a binary operation to two longs
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return BigInteger result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException;
+
+       /**
+        * Get float result of applying a binary operation to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return float result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract float getFloatResult(float leftOperand, float rightOperand);
+
+       /**
+        * Get double result of applying a binary operation to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return double result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract double getDoubleResult(double leftOperand, double rightOperand);
+
+       /**
+        * Get boolean result of applying a binary operation to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract boolean getBooleanResult(boolean leftOperand, boolean rightOperand);
+
+       /**
+        * Get string result of applying a binary operation to two strings.
+        * Default implementation throws.
+        * 
+        * @param leftOperand
+        *            - left string operand
+        * @param rightOperand
+        *            - right string operand
+        * @return string result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected String getStringResult(String leftOperand, String rightOperand) throws CoreException {
+               throw EDCDebugger.newCoreException(ASTEvalMessages.UnsupportedStringOperation);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/CompoundInstruction.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/CompoundInstruction.java
new file mode 100644 (file)
index 0000000..720631d
--- /dev/null
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+public abstract class CompoundInstruction extends Instruction {
+
+       private int size;
+
+       /**
+        * Constructor for a compound instruction
+        * 
+        * @param start
+        *            - instruction start
+        */
+       protected CompoundInstruction(int start) {
+               size = -start;
+       }
+
+       /**
+        * Set compound instruction end
+        * 
+        * @param end
+        *            - compound instruction end
+        */
+       public void setEnd(int end) {
+               size += end;
+       }
+
+       /**
+        * Get compound instruction size
+        * 
+        * @return compound instruction size
+        */
+       @Override
+       public int getSize() {
+               return size;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/EvaluateID.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/EvaluateID.java
new file mode 100644 (file)
index 0000000..f9f97a3
--- /dev/null
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.text.MessageFormat;
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Symbols;
+import org.eclipse.cdt.debug.edc.internal.symbols.InvalidVariableLocation;
+import org.eclipse.cdt.debug.edc.services.IEDCModuleDMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCModules;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.services.Stack.EnumeratorDMC;
+import org.eclipse.cdt.debug.edc.services.Stack.IVariableEnumeratorContext;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.services.Stack.VariableDMC;
+import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+public class EvaluateID extends SimpleInstruction {
+
+       private String name;
+       private final ICPPASTQualifiedName qualifiedName;
+
+       /**
+        * Constructor for ID (number + variable name) evaluate instruction
+        * 
+        * @param idExpression
+        */
+       public EvaluateID(IASTIdExpression idExpression) {
+               IASTName lookupName;
+
+               if (idExpression.getName() instanceof ICPPASTQualifiedName) {
+                       // the name has the form namespace::...::variable
+                       qualifiedName = (ICPPASTQualifiedName) idExpression.getName();
+                       lookupName = qualifiedName.getLastName();
+               } else {
+                       lookupName = idExpression.getName();
+                       qualifiedName = null;
+               }
+
+               name = new String(lookupName.getLookupKey());
+       }
+       
+       /**
+        * Constructor for lookup of a specific literal name
+     * (presumably a local, like "this")
+     *
+     * @param name the literal name
+        */
+       public EvaluateID(String name) {
+               this.name = name;
+               this.qualifiedName = null;
+       }
+
+       /**
+        * Resolve a variable ID
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() throws CoreException {
+
+               IDMContext context = getContext();
+
+               if (!(context instanceof StackFrameDMC))
+                       throw EDCDebugger.newCoreException(MessageFormat.format(ASTEvalMessages.EvaluateID_CannotResolveName, name));
+
+               StackFrameDMC frame = (StackFrameDMC) context;
+               EDCServicesTracker servicesTracker = frame.getEDCServicesTracker();
+               IEDCModules modules = servicesTracker.getService(IEDCModules.class);
+
+               // check by name for a variable or enumerator
+               IVariableEnumeratorContext variableOrEnumerator = frame.findVariableOrEnumeratorByName(name, qualifiedName != null ? qualifiedName.getRawSignature() : null, false);
+               VariableDMC variable = variableOrEnumerator instanceof VariableDMC ?
+                                                                       (VariableDMC)variableOrEnumerator : null;
+               EnumeratorDMC enumerator = variableOrEnumerator instanceof EnumeratorDMC ?
+                                                                       (EnumeratorDMC)variableOrEnumerator : null;
+
+               // This may be called on debugger shutdown, in which case the "modules" 
+               // service may have been shutdown.
+               if (variable != null && modules != null) {
+                       IVariableLocation valueLocation = null;
+                       ILocationProvider provider = variable.getVariable().getLocationProvider();
+                       IEDCModuleDMContext module = frame.getModule();
+                       if (module != null && provider != null) {
+                               valueLocation = provider.getLocation(servicesTracker, frame, module.toLinkAddress(frame.getInstructionPtrAddress()),
+                                                                                                        TypeUtils.isConstType(variable.getVariable().getType()));
+                       }
+                       if (valueLocation == null) {
+                               // unhandled
+                               valueLocation = new InvalidVariableLocation(MessageFormat.format(ASTEvalMessages.EvaluateID_NameHasNoLocation, variable.getName()));
+                       }
+                       // create a VariableWithValue and push on the stack
+                       VariableWithValue varWval = new VariableWithValue(servicesTracker, frame, variable.getVariable());
+                       varWval.setValueLocation(valueLocation);
+                       push(varWval);
+                       return;
+               }
+
+               if (enumerator != null) {
+                       // TODO: map IEnumerator to an IEnumeration and use the real type
+                       pushNewValue(fInterpreter.getTypeEngine().getIntegerTypeOfSize(4, true),
+                                       enumerator.getEnumerator().getValue());
+                       return;
+               }
+
+               // match against function names visible in the module
+               Symbols symbolsService = servicesTracker.getService(Symbols.class);
+               if (symbolsService != null) {
+                       IEDCModuleDMContext module = frame.getModule();
+                       if (module != null) {
+                               String searchName = name;
+                               if (qualifiedName != null)
+                                       searchName = qualifiedName.getRawSignature();
+                               List<IAddress> addresses = symbolsService.getFunctionAddress(module, searchName);
+                               if (addresses.size() > 0) {
+                                       pushNewValue(fInterpreter.getTypeEngine().getIntegerTypeOfSize(4, false),
+                                                       addresses.get(0).getValue().longValue());
+                                       return;
+                               }
+                               // show the whole qualified name in the exception message
+                               name = searchName;
+                       }
+               }
+
+               // did not find a variable, enumerator, or function to match the expression
+               throw EDCDebugger.newCoreException(
+                               MessageFormat.format(ASTEvalMessages.EvaluateID_VariableNotFound, name));
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/FieldReference.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/FieldReference.java
new file mode 100644 (file)
index 0000000..fd3daa6
--- /dev/null
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.text.MessageFormat;
+
+import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.IAggregate;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICompositeType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IEnumeration;
+import org.eclipse.cdt.debug.edc.internal.symbols.IField;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IReferenceType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.cdt.debug.edc.symbols.VariableLocationFactory;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Field reference instruction, such as "." or "->" 
+ */
+public class FieldReference extends CompoundInstruction {
+
+       private final IASTFieldReference refExpression;
+
+       /**
+        * Constructor for field reference instruction
+        * 
+        * @param expression
+        *            - field reference expression
+        * @param start
+        *            - instruction start
+        */
+       public FieldReference(IASTFieldReference expression, int start) {
+               super(start);
+               this.refExpression = expression;
+       }
+
+       /**
+        * Resolve a field reference operator, such as "." or "->"
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() throws CoreException {
+               // pop the structure variable at the start of the field references
+               OperandValue operand = popValue();
+
+               if (operand == null)
+                       return;
+
+               IType variableType = TypeUtils.getStrippedType(operand.getValueType());
+
+               IVariableLocation location = null;
+               boolean referenceType = variableType instanceof IReferenceType;
+
+               if (refExpression.isPointerDereference()) {
+                       // '->' operator requires a pointer type
+                       boolean validPointerType = variableType instanceof IPointerType;
+                       
+                       if (!validPointerType) {
+                               throw EDCDebugger.newCoreException(ASTEvalMessages.FieldReference_InvalidPointerDeref);
+                       }
+
+                       IPointerType pointer = (IPointerType) variableType;
+
+                       IType pointedTo = pointer.getType();
+                       variableType = TypeUtils.getStrippedType(pointedTo);
+               } else if (referenceType) {
+                       // '.' may be used with a reference "&" type
+                       IReferenceType pointer = (IReferenceType) variableType;
+
+                       IType pointedTo = pointer.getType();
+                       variableType = TypeUtils.getStrippedType(pointedTo);
+               }
+
+               if (!TypeUtils.isCompositeType(variableType)) {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.FieldReference_InvalidDotDeref);
+               }
+
+               // get the field/member
+               ICompositeType compositeType = (ICompositeType) variableType;
+               String fieldName  = refExpression.getFieldName().toString();
+               IField[] fields = compositeType.findFields(fieldName);
+
+               if (fields == null) {
+                       throw EDCDebugger.newCoreException(
+                                       MessageFormat.format(ASTEvalMessages.FieldReference_InvalidMember, fieldName));
+               }
+               
+               if (fields.length > 1) {
+                       throw EDCDebugger.newCoreException(
+                                       MessageFormat.format(ASTEvalMessages.FieldReference_AmbiguousMember, fieldName,
+                                               operand.getValueType().getName()));
+               }
+               
+               // type and address of the field
+               IField field = fields[0];
+               IType typeOfField = field.getType();
+
+               if (   refExpression.isPointerDereference()
+                       || (!refExpression.isPointerDereference() && referenceType)) {
+                       // pointer with '->' operator, or reference with '.' 
+                       location = VariableLocationFactory.createMemoryVariableLocation(
+                                       fInterpreter.getServicesTracker(), fInterpreter.getContext(),
+                                       operand.getValue());
+               } else {
+                       // '.' operator
+                       location = operand.getValueLocation();
+               }
+
+               location = location.addOffset(field.getFieldOffset());
+               
+               OperandValue varValue = new OperandValue(typeOfField, field.getBitSize() > 0);
+
+               typeOfField = TypeUtils.getStrippedType(typeOfField);
+
+               // for lvalues (base arithmetic types, enums, and pointers), read the
+               // value and cast it to the right type
+               if (   typeOfField instanceof ICPPBasicType || typeOfField instanceof IPointerType
+                       || typeOfField instanceof IEnumeration  || typeOfField instanceof IReferenceType) {
+                       int byteSize = typeOfField.getByteSize();
+
+                       // TODO support 12-byte long double
+                       if (byteSize != 1 && byteSize != 2 && byteSize != 4 && byteSize != 8 &&
+                               !(typeOfField instanceof IPointerType && byteSize == 0)) {
+                               throw EDCDebugger.newCoreException(ASTEvalMessages.FieldReference_UnhandledOperandSize + byteSize);
+                       }
+
+                       // read the value pointed to
+                       Number newValue = varValue.getValueByType(typeOfField, location);
+
+                       // if this is a bit-field, then mask and/or extend the value
+                       // appropriately
+                       // Note: only unnamed bit-fields have a 0 bit size, so a named field
+                       // with a 0 bit size is not a bit-field
+                       if (field.getBitSize() > 0) {
+                               int bitSize = field.getBitSize();
+                               int bitOffset = field.getBitOffset();
+                               boolean isSignedInt = false;
+
+                               if (typeOfField instanceof ICPPBasicType)
+                                       isSignedInt = ((ICPPBasicType) typeOfField).isSigned();
+                               else if (typeOfField instanceof IEnumeration)
+                                       isSignedInt = true;
+
+                               newValue = TypeUtils.extractBitField(newValue, byteSize, bitSize, bitOffset, isSignedInt);
+                       }
+                       varValue.setValue(newValue);
+                       varValue.setValueLocation(location);
+
+               } else if (typeOfField instanceof IAggregate) {
+                       // for aggregates, the address of the aggregate is the value
+                       // returned
+                       varValue.setAddressValue(location);
+                       varValue.setValueLocation(location);
+
+               } else {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.FieldReference_CannotDereferenceType);
+               }
+
+               push(varValue);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/GetValue.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/GetValue.java
new file mode 100644 (file)
index 0000000..fcaf336
--- /dev/null
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Get the correct type of value from an object, converting if needed.
+ * <p>
+ * All of these expect to be called with values no larger than their types (e.g. by {@link Instruction#convertForPromotion(Object)})
+ * so we throw exceptions if not.
+ */
+public class GetValue {
+
+       private static CoreException badType() {
+               return EDCDebugger.newCoreException(ASTEvalMessages.GetValue_TypePromotionError);
+       }
+       
+       /**
+        * Get the boolean value of an object
+        * 
+        * @param value
+        *            - possibly Boolean object
+        * @return boolean value of param, or false if param is not a Boolean object
+        */
+       public static boolean getBooleanValue(OperandValue op) throws CoreException {
+               Number value = op.getValue();
+               if (value instanceof BigInteger)
+                       return ((BigInteger) value).signum() != 0 ? true : false;
+               return value.longValue() != 0;
+       }
+
+       /**
+        * Get the integer value of an object
+        * 
+        * @param value
+        *            - possibly Integer, Short, or Byte object
+        * @return integer value of param, or 0 if param is not an integer object
+        */
+       public static int getIntValue(OperandValue op) throws CoreException  {
+               Number value = op.getValue();
+               if (value instanceof Integer)
+                       return (Integer) value;
+               if (value instanceof Short)
+                       return new Integer((Short) value);
+               if (value instanceof Byte)
+                       return new Integer((Byte) value);
+               throw badType();
+       }
+
+       /**
+        * Get the long value of an object
+        * 
+        * @param value value with Long, Integer, Short, or Byte value
+        * @return long value of param, or 0 if param is not an integral object
+        */
+       public static long getLongValue(OperandValue op) throws CoreException  {
+               Number value = op.getValue();
+               if (value instanceof Long)
+                       return (Long) value;
+               if (value instanceof Integer)
+                       return new Long((Integer) value);
+               if (value instanceof Short)
+                       return new Long((Short) value);
+               if (value instanceof Byte)
+                       return new Long((Byte) value);
+               throw badType();
+       }
+
+       /**
+        * Get the BigInteger value of an object
+        * 
+        * @param value value with possibly BigInteger, Long, Integer, Short, Byte, or
+        *            Character object
+        * @return BigInteger value of param, or 0 if param is not an integral
+        *         object
+        */
+       public static BigInteger getBigIntegerValue(OperandValue op) throws CoreException  {
+               Number value = op.getValue();
+               if (value instanceof BigInteger)
+                       return (BigInteger) value;
+               if (value instanceof Long)
+                       return new BigInteger(((Long) value).toString());
+               if (value instanceof Integer)
+                       return new BigInteger(((Integer) value).toString());
+               if (value instanceof Short)
+                       return new BigInteger(((Short) value).toString());
+               if (value instanceof Byte)
+                       return new BigInteger(new byte[] { (Byte) value });
+               //if (value instanceof Character)
+               //      return new BigInteger(new byte[] { (byte) Character.getNumericValue((Character) value) });
+               throw badType();
+       }
+
+       /**
+        * Get the float value of an object
+        * 
+        * @param value with possibly Float or integral (e.g., Long) object
+        * @return float value of param, or 0 if param is not a Float or integral
+        *         object
+        */
+       public static float getFloatValue(OperandValue op) throws CoreException  {
+               Number value = op.getValue();
+               if (value instanceof Float)
+                       return (Float) value;
+               if (value instanceof Long)
+                       return new Float((Long) value);
+               if (value instanceof Integer)
+                       return new Float((Integer) value);
+               if (value instanceof Short)
+                       return new Float((Short) value);
+               if (value instanceof Byte)
+                       return new Float((Byte) value);
+               if (value instanceof BigInteger)
+                       return new Float(((BigInteger) value).floatValue());
+               throw badType();
+       }
+
+       /**
+        * Get the double value of an object
+        * 
+        * @param value
+        *            - possibly float (e.g., Double) or integral (e.g., Long)
+        *            object
+        * @return double value of param, or 0 if param is not a float or integral
+        *         object
+        */
+       public static double getDoubleValue(OperandValue op) throws CoreException  {
+               Number value = op.getValue();
+               if (value instanceof Double)
+                       return (Double) value;
+               if (value instanceof Float)
+                       return new Double((Float) value);
+               if (value instanceof Long)
+                       return new Double((Long) value);
+               if (value instanceof Integer)
+                       return new Double((Integer) value);
+               if (value instanceof Short)
+                       return new Double((Short) value);
+               if (value instanceof Byte)
+                       return new Double((Byte) value);
+               if (value instanceof BigInteger)
+                       return new Double(((BigInteger) value).doubleValue());
+               throw badType();
+       }
+
+       /**
+        * Get the string value of an object
+        * 
+        * @param value
+        *            - String or Character object
+        * @return string value of String param, or quoted string for Character
+        *         param
+        */
+       public static String getStringValue(OperandValue value) throws CoreException  {
+               if (value.getStringValue() != null)
+                       return value.getStringValue();
+               return "\"" + (char) (value.getValue().longValue()) + "\""; //$NON-NLS-1$ //$NON-NLS-2$
+               //throw badType();
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/IArrayDimensionType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/IArrayDimensionType.java
new file mode 100644 (file)
index 0000000..bf50556
--- /dev/null
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.IAggregate;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+
+public interface IArrayDimensionType extends IAggregate {
+
+       public IArrayType getArrayType();
+
+       public IVariableLocation getLocation();
+
+       public int getDimensionCount();
+
+       public void addDimension(long subscript, long increase);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/IInvalidExpression.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/IInvalidExpression.java
new file mode 100644 (file)
index 0000000..684b7ea
--- /dev/null
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+/**
+ * Invalid expression
+ */
+public interface IInvalidExpression {
+
+       /**
+        * Get message telling why the expression is invalid
+        * 
+        * @return messsage
+        */
+       public String getMessage();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/Instruction.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/Instruction.java
new file mode 100644 (file)
index 0000000..87f5942
--- /dev/null
@@ -0,0 +1,521 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICompositeType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IEnumeration;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+public abstract class Instruction {
+
+       protected static BigInteger Mask8Bytes = new BigInteger("ffffffffffffffff", 16); //$NON-NLS-1$
+
+       protected Interpreter fInterpreter;
+
+       /**
+        * Get instruction size
+        * 
+        * return instruction size
+        */
+       public abstract int getSize();
+
+       /**
+        * Set instruction's fInterpreter
+        * 
+        * @param interpreter
+        */
+       public void setInterpreter(Interpreter interpreter) {
+               fInterpreter = interpreter;
+       }
+
+       /**
+        * Stop the instruction fInterpreter
+        */
+       public void stop() {
+               fInterpreter.stop();
+       }
+
+       /**
+        * Execute the instruction
+        * @throws CoreException
+        */
+       public abstract void execute() throws CoreException;
+
+       /**
+        * Get the instruction's context
+        * 
+        * @return instruction fInterpreter context
+        */
+       protected IDMContext getContext() {
+               return fInterpreter.getContext();
+       }
+
+       /**
+        * Jump to an instruction fInterpreter offset
+        * 
+        * @param offset
+        *            - fInterpreter offset
+        */
+       protected void jump(int offset) {
+               fInterpreter.jump(offset);
+       }
+
+       /**
+        * Push an object on the instruction stack
+        * 
+        * @param op
+        */
+       protected OperandValue push(OperandValue op) {
+               fInterpreter.push(op);
+               return op;
+       }
+
+       /**
+        * Pop an object off the instruction stack
+        * 
+        * @return object on the top of the stack
+        */
+       protected OperandValue pop() {
+               return fInterpreter.pop();
+       }
+
+       /**
+        * Pop a value from the instruction stack
+        * 
+        * @return current top of stack, if the stack is not empty, or
+        *         <code>null</code> otherwise
+        * @throws CoreException 
+        */
+       protected OperandValue popValue() throws CoreException {
+               OperandValue value = null;
+               if (!fInterpreter.isEmpty())
+                       value = fInterpreter.pop();
+               if (value == null)
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.Instruction_EmptyStack);
+               return value;
+       }
+
+       /**
+        * Push a boolean on the instruction stack
+        * 
+        * @param value
+        *            - boolean value
+        */
+       protected OperandValue pushNewValue(IType type, boolean value) {
+               OperandValue op = new OperandValue(value ? 1 : 0, type);
+               fInterpreter.push(op);
+               return op;
+       }
+       
+
+       /**
+        * Push a number on the instruction stack
+        * 
+        * @param value
+        *            - number value
+        */
+       protected OperandValue pushNewValue(IType type, Number value) {
+               OperandValue op = new OperandValue(value, type);
+               fInterpreter.push(op);
+               return op;
+       }
+
+       /**
+        * Push a string on the instruction stack
+        * 
+        * @param value
+        *            - string value
+        */
+       protected OperandValue pushNewValue(IType type, String value) {
+               OperandValue op = new OperandValue(value, type);
+               fInterpreter.push(op);
+               return op;
+       }
+
+       /**
+        * Convert operands to types expected by getBinaryPromotionType() (e.g.,
+        * VariableWithValue to its underlying Long)
+        * 
+        * @param operand
+        *            - original operand
+        * @return result operand type
+        * @throws CoreException if value cannot be fetched
+        */
+       protected OperandValue convertForPromotion(OperandValue operand) throws CoreException {
+               IType type = getBasicType(operand.getValueType());
+               if (type instanceof ICompositeType) {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.Instruction_CannotUseCompositeType);
+               }
+               if (type instanceof IArrayType && operand.getValueLocation() != null) {
+                       // take address as value
+                       return new OperandValue(operand.getValueLocationAddress(), fInterpreter.getTypeEngine().getPointerSizeType());
+               }
+               return operand;
+       }
+
+       /**
+        * Get result binary operation type given types of the left and right
+        * operands, according to Java rules
+        * 
+        * @param left
+        *            - left operand
+        * @param right
+        *            - right operand
+        * @return result T_ type
+        * @throws CoreException 
+        */
+       public int getJavaBinaryPromotionType(OperandValue left, OperandValue right) throws CoreException {
+               int leftType = getValueType(left);
+               int rightType = getValueType(right);
+               return fTypeTable[leftType][rightType];
+       }
+
+       /**
+        * Get result binary operation type given types of the left and right
+        * operands
+        * 
+        * @param left
+        *            - left operand T_ type
+        * @param right
+        *            - right operand T_type
+        * @return result T_ type
+        */
+       public int getBinaryPromotionType(int left, int right) {
+               return fTypeTable[left][right];
+       }
+
+       /**
+        * Get T_ type for a base Java type (e.g., Character or Boolean).
+        * <p>
+        * This differs from the actual C type in that we pick the Java
+        * type that has the same size as the C type.  I.e., "char" of size 1
+        * becomes T_byte and "wchar_t" of size 4 becomes T_int.
+        * 
+        * @param value
+        *            - base Java type object
+        * @return corresponding T_ type, or T_undefined if value is not a base type
+        * @throws CoreException 
+        */
+       public int getValueType(OperandValue op) throws CoreException {
+               Number value = op.getValue();
+               if (value == null) {
+                       if (op.getStringValue() != null)
+                               return T_String;
+               }
+               // respect Java types first, since C types can alias (e.g. int == long)
+               if (value instanceof Integer)
+                       return T_int;
+               if (value instanceof Short)
+                       return T_short;
+               if (value instanceof Byte)
+                       return T_byte;
+               if (value instanceof Long)
+                       return T_long;
+               if (value instanceof Float)
+                       return T_float;
+               if (value instanceof Double)
+                       return T_double;
+               if (value instanceof BigInteger)
+                       return T_BigInt;
+               
+               return getJavaValueType(op.getValueType());
+       }
+
+       /**
+        * Get T_ type corresponding to the given C type.  This is used for promotion.
+        * Note: in this interpretation, long long maps to T_BigInt.
+        *  
+        * @param type the basic type
+        * @return corresponding T_ type, or T_undefined if value is not a base type
+        * @throws CoreException 
+        */
+       public int getCValueType(OperandValue op) throws CoreException {
+               if (op.getStringValue() != null) {
+                       return T_String;
+               }
+               
+               IType type_ = getBasicType(op.getValueType());
+               
+               if (!(type_ instanceof ICPPBasicType))
+                       return T_undefined;
+               
+               ICPPBasicType type = (ICPPBasicType) type_;
+               
+               switch (type.getBaseType()) {
+               case ICPPBasicType.t_bool:
+                       return T_boolean;
+               case ICPPBasicType.t_char:
+                       return T_char;
+               case ICPPBasicType.t_float:
+                       return T_float;
+               case ICPPBasicType.t_double:
+                       if (type.isLong())
+                               assert(false); // TODO; need long double type
+                       return T_double;
+               case ICPPBasicType.t_int:
+                       if (type.isLongLong())
+                               return T_BigInt;
+                       if (type.isLong())
+                               return T_long;
+                       if (type.isShort())
+                               return T_short;
+                       return T_int;
+               case ICPPBasicType.t_unspecified:
+                       return T_undefined;
+               case ICPPBasicType.t_void:
+                       return T_void;
+               }
+               return T_undefined;
+       }
+
+       /**
+        * Get result binary operation type given types of the left and right
+        * operands.  This uses the C rules for type promotion.  
+        * 
+        * @param left
+        *            - left type
+        * @param right
+        *            - right type
+        * @return result type or <code>null</code> if an undefined promotion
+        */
+       public IType getBinaryPromotionType(OperandValue leftOp, OperandValue rightOp) throws CoreException {
+               
+               int leftType = getCValueType(leftOp);
+               int rightType = getCValueType(rightOp);
+               int promoted = getBinaryPromotionType(leftType, rightType);
+
+               if (promoted == T_null || promoted == T_undefined || promoted == T_void)
+                       throw EDCDebugger.newCoreException(MessageFormat.format(ASTEvalMessages.Instruction_UnhandledTypeCombination,
+                                       leftOp.getValueType().getName(), rightOp.getValueType().getName()));
+               
+               // promoted type loses qualifier bits and enum-ness
+               if (leftType == promoted)
+                       return getBasicType(leftOp.getValueType());
+               if (rightType == promoted)
+                       return getBasicType(rightOp.getValueType());
+               
+               // we're here because the promoted type is bigger than either of the
+               // incoming types (e.g. short + float -> double)
+               
+               boolean isSigned = true;
+               
+               switch (promoted) {
+               case T_char:
+                       return fInterpreter.getTypeEngine().getIntegerTypeFor(TypeUtils.BASIC_TYPE_CHAR, isSigned);
+               case T_short:
+                       return fInterpreter.getTypeEngine().getIntegerTypeFor(TypeUtils.BASIC_TYPE_SHORT, isSigned);
+               case T_int:
+                       return fInterpreter.getTypeEngine().getIntegerTypeFor(TypeUtils.BASIC_TYPE_INT, isSigned);
+               case T_long:
+                       return fInterpreter.getTypeEngine().getIntegerTypeFor(TypeUtils.BASIC_TYPE_LONG, isSigned);
+               case T_float:
+                       return fInterpreter.getTypeEngine().getFloatTypeOfSize(TypeUtils.BASIC_TYPE_FLOAT);
+               case T_double:
+                       return fInterpreter.getTypeEngine().getFloatTypeOfSize(TypeUtils.BASIC_TYPE_DOUBLE);
+               // TODO: long double
+                       
+               case T_byte:    // should not happen
+               case T_null:    // should not happen
+               case T_Object:  // should not happen
+               case T_String:  // should not happen
+               default:
+                       assert(false);
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.UnhandledTypeCode + promoted);
+               }
+       }
+       
+       /**
+        * Get the stripped down basic type that promotion rules work with.
+        * Ignore const/volatile/... qualifiers, demote enums to ints, etc.
+        * @param type
+        * @return adjusted type
+        */
+       private IType getBasicType(IType type) {
+               type = TypeUtils.getStrippedType(type);
+               if (type instanceof IEnumeration) {
+                       // discover the appropriate integer to hold this
+                       int byteSize = ((IEnumeration) type).getByteSize();
+                       type = fInterpreter.getTypeEngine().getIntegerTypeOfSize(byteSize, true);
+               }
+               return type;
+       }
+
+       /**
+        * Get T_ type for a base Java type that can hold a given type
+        * (e.g., Character or Boolean).
+        * <p>
+        * This differs from the actual C type in that we pick the Java
+        * type that has a compatible size as the C type.  I.e., "char" of size 1
+        * becomes T_byte and "wchar_t" of size 4 becomes T_int.  (An actual
+        * target may have larger or smaller primitive types than Java.)
+        * <p> 
+        * Note: when we do unsigned math, we go up one type size in order to handle
+        * unsigned math properly.
+        * 
+        * @param value
+        *            - base Java type object
+        * @return corresponding T_ type, T_string, or T_undefined if value is not a base or string type
+        */
+       public int getJavaValueType(IType type_) {
+               type_ = getBasicType(type_);
+               if (!(type_ instanceof ICPPBasicType)) {
+                       if (type_ instanceof IArrayType && type_.getType() instanceof ICPPBasicType
+                               && ((((ICPPBasicType) type_.getType()).getBaseType() == ICPPBasicType.t_char
+                               || ((ICPPBasicType) type_.getType()).getBaseType() == ICPPBasicType.t_wchar_t))) {
+                               return T_String;
+                       }
+                       return T_undefined;
+               }
+               
+               ICPPBasicType type = (ICPPBasicType) type_;
+               
+               switch (type.getBaseType()) {
+               case ICPPBasicType.t_bool:
+                       return T_boolean;
+               case ICPPBasicType.t_char:
+                       return T_char;
+               case ICPPBasicType.t_float:
+                       return T_float;
+               case ICPPBasicType.t_double:
+                       if (type.isLong())
+                               assert(false); // TODO
+                       return T_double;
+               case ICPPBasicType.t_unspecified:
+                       return T_undefined;
+               case ICPPBasicType.t_void:
+                       return T_void;
+               case ICPPBasicType.t_int:
+                       if (type.isLongLong()) {
+                               if (type.getByteSize() > 8 || (type.getByteSize() == 8 && type.isUnsigned()))
+                                       return T_BigInt;        // java long cannot handle unsigned 8-byte math
+                               else
+                                       return T_long;
+                       }
+                       if (type.isLong()) {
+                               if (type.getByteSize() > 8 || (type.getByteSize() == 8 && type.isUnsigned()))
+                                       return T_BigInt;        // java long cannot handle unsigned 8-byte math
+                               else
+                                       return T_long;
+                       }
+                       switch (type.getByteSize()) {
+                       case 1:
+                               if (type.isUnsigned())
+                                       return T_short;
+                               else
+                                       return T_byte;
+                       case 2:
+                               if (type.isUnsigned())
+                                       return T_int;
+                               else
+                                       return T_short;
+                       case 4:
+                               if (type.isUnsigned())
+                                       return T_int;
+                               else
+                                       return T_short;
+                       }
+                       if (type.isLong()) {
+                               if (type.isUnsigned() && type.getByteSize() > 8)
+                                       return T_BigInt;
+                               else
+                                       return T_long;
+                       }
+                       
+                       
+               }
+               return T_undefined;
+       }
+
+       static public final int T_undefined = 0;
+       static public final int T_Object = 1;
+       static public final int T_char = 2;
+       static public final int T_byte = 3;
+       static public final int T_short = 4;
+       static public final int T_boolean = 5;
+       static public final int T_void = 6;
+       static public final int T_long = 7;
+       static public final int T_double = 8;
+       static public final int T_float = 9;
+       static public final int T_int = 10;
+       static public final int T_String = 11;
+       static public final int T_null = 12;
+       static public final int T_BigInt = 13;
+
+       private static final int[][] fTypeTable = {
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* undefined */ {       T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined},
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* object */    {       T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_String,               T_undefined,    T_undefined },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* char */              {       T_undefined,    T_undefined,    T_int,                  T_int,                  T_int,                  T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_long,                 T_double,               T_float,                T_int,                  T_String,               T_undefined,    T_BigInt },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* byte */              {       T_undefined,    T_undefined,    T_int,                  T_int,                  T_int,                  T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_long,                 T_double,               T_float,                T_int,                  T_String,               T_undefined,    T_BigInt },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* short */             {       T_undefined,    T_undefined,    T_int,                  T_int,                  T_int,                  T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_long,                 T_double,               T_float,                T_int,                  T_String,               T_undefined,    T_BigInt },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* boolean */   {       T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_boolean,              T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_String,               T_undefined,    T_undefined },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* void */              {       T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* long */              {       T_undefined,    T_undefined,    T_long,                 T_long,                 T_long,                 T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_long,                 T_double,               T_float,                T_long,                 T_String,               T_undefined,    T_BigInt },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* double */    {       T_undefined,    T_undefined,    T_double,               T_double,               T_double,               T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_double,               T_double,               T_double,               T_double,               T_String,               T_undefined,    T_double },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* float */             {       T_undefined,    T_undefined,    T_float,                T_float,                T_float,                T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_float,                T_double,               T_float,                T_float,                T_String,               T_undefined,    T_float },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* int */               {       T_undefined,    T_undefined,    T_int,                  T_int,                  T_int,                  T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_long,                 T_double,               T_float,                T_int,                  T_String,               T_undefined,    T_BigInt },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* String */    {       T_undefined,    T_String,               T_String,               T_String,               T_String,               T_String,               T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_String,               T_String,               T_String,               T_String,               T_String,               T_String,               T_undefined },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* null */              {       T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_undefined,    T_undefined,    T_undefined,    T_undefined,    T_String,               T_undefined,    T_undefined },
+                                               //      undefined               object                  char                    byte                    short                   boolean                 void
+               /* BigInteger */{       T_undefined,    T_undefined,    T_BigInt,               T_BigInt,               T_BigInt,               T_undefined,    T_undefined,
+                                               //      long                    double                  float                   int                             String                  null                    BigInteger
+                                                       T_BigInt,               T_double,               T_float,                T_BigInt,               T_undefined,    T_undefined,    T_BigInt },             
+               };
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/InstructionSequence.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/InstructionSequence.java
new file mode 100644 (file)
index 0000000..e417b20
--- /dev/null
@@ -0,0 +1,259 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeEngine;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Instruction sequence
+ */
+public class InstructionSequence {
+
+       private List<Instruction> fInstructions;
+       /**
+        * A collection of error messages (<code>String</code>) that occurred while
+        * creating this expression
+        */
+       private List<String> fErrors;
+       private String fSnippet;
+       private CoreException fException;
+
+       /**
+        * Constructor for an instruction sequence
+        * 
+        * @param snippet
+        *            - expression the instruction sequence represents
+        */
+       public InstructionSequence(String snippet) {
+               fInstructions = new ArrayList<Instruction>(10);
+               fErrors = new ArrayList<String>();
+               fSnippet = snippet;
+       }
+
+       /**
+        * Copy constructor
+        * 
+        * @param original - the instance to copy
+        */
+       public InstructionSequence(InstructionSequence original) {
+               fInstructions = new ArrayList<Instruction>(Arrays.asList(original.getInstructions()));
+               fErrors = new ArrayList<String>(Arrays.asList(original.getErrorMessages()));
+               fSnippet = original.getSnippet();
+               fException = original.getException();
+       }
+       
+       /**
+        * Get the runtime exception that occurred while evaluating this expression
+        * 
+        * @param runtime
+        *            exception, or <code>null</code> if no exception occurred
+        */
+       public CoreException getException() {
+               return fException;
+       }
+
+       /**
+        * @see ICompiledExpression#getSnippet()
+        */
+       public String getSnippet() {
+               return fSnippet;
+       }
+
+       /**
+        * Adds the given error to the list of errors that occurred while compiling
+        * this instruction sequence
+        */
+       public void addError(String error) {
+               fErrors.add(error);
+       }
+
+       /**
+        * @see ICompiledExpression#hasErrors()
+        */
+       public boolean hasErrors() {
+               return !fErrors.isEmpty();
+       }
+
+       /**
+        * @see org.eclipse.jdt.debug.eval.ICompiledExpression#getErrorMessages()
+        */
+       public String[] getErrorMessages() {
+               return fErrors.toArray(new String[fErrors.size()]);
+       }
+
+       /**
+        * Get the array of instructions
+        * 
+        * return array of instructions, or an empty array
+        */
+       public Instruction[] getInstructions() {
+               int size = fInstructions.size();
+               Instruction[] instructions = new Instruction[size];
+               if (size > 0) {
+                       fInstructions.toArray(instructions);
+               }
+               return instructions;
+       }
+
+       /**
+        * Get the instruction at the given address
+        * 
+        * @param address
+        *            - address of instruction
+        * @return instruction at the address
+        */
+       public Instruction getInstruction(int address) {
+               return fInstructions.get(address);
+       }
+
+       /**
+        * Add the given instruction to the end of the list
+        * 
+        * @param instruction
+        *            - instruction to add
+        */
+       public void add(Instruction instruction) {
+               fInstructions.add(instruction);
+       }
+
+       /**
+        * Get the index of an instruction
+        * 
+        * @param instruction
+        *            - instruction to find
+        * @return index of instruction, or -1 if the instruction does not exist
+        */
+       public int indexOf(Instruction instruction) {
+               return fInstructions.indexOf(instruction);
+       }
+
+       /**
+        * Tell whether the instruction sequence is empty
+        * 
+        * @return true if the instruction sequence is empty, and false otherwise
+        */
+       public boolean isEmpty() {
+               return fInstructions.isEmpty();
+       }
+
+       /**
+        * Insert the instruction at the given index. If the index is less than 0 or
+        * greater than the current instruction count, the instruction is added at
+        * the end of the sequence.
+        * 
+        * Instructs the instructions to update their program counters.
+        */
+       public void insert(Instruction instruction, int index) {
+               fInstructions.add(index, instruction);
+       }
+
+       /**
+        * Get the instruction at the given address
+        * 
+        * @param address
+        *            - instruction address
+        * @return instruction at the given address
+        */
+       public Instruction get(int address) {
+               return fInstructions.get(address);
+       }
+
+       /**
+        * Get the index of the last instruction in the sequence
+        * 
+        * @return size of the instruction sequence - 1
+        */
+       public int getEnd() {
+               return fInstructions.size() - 1;
+       }
+
+       /**
+        * Remove no-ops from the instruction list
+        */
+       public void removeNoOps() {
+               for (Iterator<Instruction> iter = fInstructions.iterator(); iter.hasNext(); ) {
+                       if (iter.next() instanceof NoOp) {
+                               iter.remove();
+                       }
+               }
+       }
+
+       /**
+        * Fixup instructions like:  *(<type>*)&<something>
+        *<p>
+        * We want to avoid getting the address of a register or bitfield and
+        * causing an error, so just make a synthetic "cast value" operator here.
+        * <p>
+        * If there is a concern about incorrectly avoiding an error here -- 
+        * "if the variable is in a register, then this should fail" -- I argue that 
+        * the user doesn't necessarily know it's in a register at compile time, and 
+        * we should try harder to allow evaluating such an expression.  Asking him to 
+        * modify and rebuild his code so the variable will be in memory is a bit draconian.   
+        * @param typeEngine 
+        */
+       public void reduceCasts(TypeEngine typeEngine) {
+               boolean anyChanges = false;
+               for (int i = 0; i < fInstructions.size(); i++) {
+                       Instruction inst = fInstructions.get(i);
+                       if ((inst instanceof OperatorAddrOf) && i + 1 < fInstructions.size()) {
+                               Instruction inst2 = fInstructions.get(i + 1);
+                               if (inst2 instanceof OperatorCast && i + 2 < fInstructions.size()) {
+                                       Instruction inst3 = fInstructions.get(i + 2);
+                                       if (inst3 instanceof OperatorIndirection) {
+                                               // see if it's a pointer or array
+                                               IType castType = null;
+                                               try {
+                                                       castType = TypeUtils.getStrippedType(((OperatorCast) inst2).getCastType(typeEngine));
+                                               } catch (CoreException e) {
+                                                       // ignore
+                                                       continue;
+                                               }
+                                               if (castType instanceof IPointerType || castType instanceof IArrayType) {
+                                                       OperatorCastValue cv = new OperatorCastValue(inst.getSize(), castType.getType());
+                                                       fInstructions.set(i, cv);
+                                                       fInstructions.set(i + 1, new NoOp(inst2.getSize()));
+                                                       fInstructions.set(i + 2, new NoOp(inst3.getSize()));
+                                                       anyChanges = true;
+                                               }
+                                       }
+                               } else if (inst2 instanceof OperatorCastValue) {
+                                       // see if it's a pointer or array
+                                       IType castType;
+                                       try {
+                                               castType = TypeUtils.getStrippedType(((OperatorCastValue)inst2).getCastType(typeEngine));
+                                       } catch (CoreException e) {
+                                               // ignore
+                                               continue;
+                                       }
+                                       if (castType instanceof IPointerType || castType instanceof IArrayType) {
+                                               OperatorCastValue cv = new OperatorCastValue(inst.getSize(), castType.getType());
+                                               fInstructions.set(i, cv);
+                                               fInstructions.set(i + 1, new NoOp(inst2.getSize()));
+                                               anyChanges = true;
+                                       }
+                               }
+                       }
+               }
+               if (anyChanges) {
+                       removeNoOps();
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/Interpreter.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/Interpreter.java
new file mode 100644 (file)
index 0000000..4ceae01
--- /dev/null
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.util.EmptyStackException;
+import java.util.Stack;
+
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.symbols.TypeEngine;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+public class Interpreter {
+       private final Instruction[] instructions;
+       private int instructionCounter;
+       private final IDMContext context;
+       private Stack<OperandValue> stack;
+       private OperandValue lastValue;
+
+       private boolean fStopped = false;
+       private final EDCServicesTracker tracker;
+       private final TypeEngine typeEngine;
+
+       /**
+        * Constructor for fInterpreter
+        * @param context 
+        * @param instructionSequence
+        *            - instruction sequence to execute
+        * @param context
+        *            - instruction context
+        */
+       public Interpreter(EDCServicesTracker tracker, IDMContext context, 
+                       TypeEngine typeEngine,
+                       InstructionSequence instructionSequence) {
+               this.tracker = tracker;
+               this.context = context;
+               this.typeEngine = typeEngine;
+               this.instructions = instructionSequence.getInstructions();
+       }
+
+       public EDCServicesTracker getServicesTracker() {
+               return tracker;
+       }
+
+       /**
+        * Execute an instruction sequence
+        * 
+        * @throws CoreException
+        */
+       public void execute() throws CoreException {
+               reset();
+               while (instructionCounter < instructions.length && !fStopped) {
+                       Instruction instruction = instructions[instructionCounter++];
+                       synchronized(instruction)
+                       {
+                               Interpreter old = instruction.fInterpreter;
+                               instruction.setInterpreter(this);
+                               instruction.execute();
+                               instruction.setInterpreter(old);
+                       }
+               }
+       }
+
+       /**
+        * Stop the fInterpreter
+        */
+       public void stop() {
+               fStopped = true;
+       }
+
+       /**
+        * Reset the fInterpreter
+        */
+       private void reset() {
+               stack = new Stack<OperandValue>();
+               instructionCounter = 0;
+       }
+
+       /**
+        * Jump to a relative instruction counter offset
+        * 
+        * @param offset
+        *            - offset from the current instruction counter
+        */
+       public void jump(int offset) {
+               instructionCounter += offset;
+       }
+
+       /**
+        * Push an object on the stack. Disables garbage collection for any interim
+        * object pushed onto the stack. Objects are released after the evaluation
+        * completes.
+        * 
+        * @param object
+        */
+       public void push(OperandValue object) {
+               stack.push(object);
+       }
+
+       /**
+        * Tell whether the stack is empty
+        * 
+        * @return true if the stack is empty, and false otherwise
+        */
+       public boolean isEmpty() {
+               return stack.isEmpty();
+       }
+
+       /**
+        * Peek at the top object of the stack
+        * 
+        * @return object on the top of the stack
+        */
+       public OperandValue peek() {
+               return stack.peek();
+       }
+
+       /**
+        * Pop an object off of the stack
+        * 
+        * @return object on the top of the stack
+        */
+       public OperandValue pop() throws EmptyStackException {
+               return stack.pop();
+       }
+
+       /**
+        * Get the context for the fInterpreter
+        * 
+        * @return fInterpreter context
+        */
+       public IDMContext getContext() {
+               return context;
+       }
+
+       /**
+        * Get current instruction result
+        * 
+        * @return current top of stack, or the last stack value if the stack is
+        *         <code>null</code> or empty
+        */
+       public OperandValue getResult() {
+               if (stack == null || stack.isEmpty()) {
+                       return lastValue;
+               }
+               OperandValue top = stack.peek();
+               return top;
+       }
+
+       public TypeEngine getTypeEngine() {
+               return typeEngine;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/NoOp.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/NoOp.java
new file mode 100644 (file)
index 0000000..e706b7e
--- /dev/null
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * No-op instruction
+ */
+public class NoOp extends CompoundInstruction {
+
+       /**
+        * Constructor for no-op instruction
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public NoOp(int start) {
+               super(start);
+       }
+
+       /**
+        * Resolve a no-op instruction
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() throws CoreException {
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperandValue.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperandValue.java
new file mode 100644 (file)
index 0000000..56af32c
--- /dev/null
@@ -0,0 +1,409 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.IAggregate;
+import org.eclipse.cdt.debug.edc.internal.symbols.IBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IEnumeration;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IQualifierType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IReferenceType;
+import org.eclipse.cdt.debug.edc.internal.symbols.TypedefType;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.symbols.IEnumerator;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.cdt.debug.edc.symbols.VariableLocationFactory;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * This is the basic unit of work when evaluating expressions.  It carries
+ * a type and a number.  Subclasses like {@link VariableWithValue} may hold
+ * additional information, like a specific variable and a location.
+ */
+public class OperandValue {
+
+       protected IVariableLocation valueLocation;
+
+       protected Number value;
+       protected String stringValue;
+       protected IType type;
+       protected boolean isBitField;
+
+
+       public OperandValue(IType type) {
+               this(type, false);
+       }
+
+       public OperandValue(IType type, boolean isBitField) {
+               this.type = type;
+               this.isBitField = isBitField;
+       }
+
+       // operand order switched so we don't accidentally invoke isBitField variant with Boolean
+       public OperandValue(Number value, IType type) {
+               this.type = type;
+               this.value = value;
+       }
+       
+       public OperandValue(String string, IType type) {
+               this(type, false);
+               this.stringValue = string;
+       }
+
+       /**
+        * @return the type
+        */
+       public IType getValueType() {
+               return type;
+       }
+
+       public IVariableLocation getValueLocation() {
+               return valueLocation;
+       }
+
+       public void setValueLocation(IVariableLocation valueLocation) {
+               this.valueLocation = valueLocation;
+       }
+
+       public Number getValueLocationAddress() throws CoreException {
+               IVariableLocation location = getValueLocation();
+               if (location == null)
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperandValue_VariableNoAddress);
+               return getLocationAddress(location);
+       }
+
+       public Number getValueByType(IType varType, IVariableLocation location)
+                       throws CoreException {
+               Number result;
+               
+               if (varType != null) {
+                       if (varType instanceof ICPPBasicType)
+                               result = getBasicTypeValue(varType, location);
+                       else if (varType instanceof IPointerType)
+                               result = getBasicTypeValue(varType, location);
+                       else if (varType instanceof IReferenceType) {
+                               result = getBasicTypeValue(varType, location);
+                               
+                               // use result as the location of the referenced variable's value
+                               if (location != null && location.getContext() != null && location.getServicesTracker() != null) {
+                                       IDMContext context = location.getContext();
+                                       EDCServicesTracker servicesTracker = location.getServicesTracker();
+                                       IType pointedTo = TypeUtils.getStrippedType(varType).getType();
+                                       if (pointedTo instanceof ICPPBasicType || pointedTo instanceof IPointerType ||
+                                               pointedTo instanceof IEnumeration) {
+                                               IVariableLocation newLocation = VariableLocationFactory.createMemoryVariableLocation(servicesTracker, context, result);
+                                               setValueLocation(newLocation);
+                                               result = getBasicTypeValue(pointedTo, newLocation);
+                                       }
+                               }
+                       } else if (varType instanceof IAggregate)
+                               result = getAggregateTypeValue((IAggregate) varType, location);
+                       else if (varType instanceof IQualifierType || varType instanceof TypedefType)
+                               result = getValueByType(varType.getType(), location);
+                       else if (varType instanceof IEnumeration)
+                               result = getBasicTypeValue(varType, location);
+                       else {
+                               assert false;
+                               throw EDCDebugger.newCoreException(ASTEvalMessages.VariableWithValue_UnhandledType + varType.getName());
+                       }
+               } else {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.VariableWithValue_VariableHasNoType);
+               }
+               return result;
+       }
+
+       public Number getValue() throws CoreException {
+               return value;
+       }
+
+       public void setValue(Number value) {
+               this.value = value;
+       }
+
+       public String getStringValue() {
+               return stringValue;
+       }
+
+       public void setStringValue(String stringValue) {
+               this.stringValue = stringValue;
+       }
+       
+       public void setAddressValue(IVariableLocation location) throws CoreException {
+               setValue(getLocationAddress(location));
+       }
+
+       protected Number getLocationAddress(IVariableLocation location) throws CoreException {
+               IAddress addr = location.getAddress();
+               if (addr == null)
+                       throw EDCDebugger.newCoreException(
+                                       MessageFormat.format(ASTEvalMessages.OperandValue_CannotGetAddress, location.getLocationName()));
+               return addr.getValue();
+       }
+
+       private Number getAggregateTypeValue(IAggregate varType, IVariableLocation location)
+               throws CoreException {
+               // assumes that an array, class, struct, or union is always located in
+               // memory, not in a register
+               return getLocationAddress(location);
+       }
+
+       private Number getBasicTypeValue(IType varType, IVariableLocation location)
+               throws CoreException {
+               if (EDCTrace.VARIABLE_VALUE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { varType, location })); }
+               Number result = null;
+               try {
+                       result = doGetBasicTypeValue(varType, location);
+                       return result;
+               } finally {
+                       if (EDCTrace.VARIABLE_VALUE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(result)); }
+               }
+       }
+
+       private Number doGetBasicTypeValue(IType varType, IVariableLocation location) throws CoreException {
+                       
+               Number result = null;
+               int varSize = varType.getByteSize();
+       
+               // get characteristics of the type
+               int basicType = IBasicType.t_unspecified;
+               boolean isSigned = false;
+               boolean isShort = false;
+               boolean isLong = false;
+               boolean isLongLong = false;
+               boolean isComplex = false;
+       
+               if (varType instanceof IBasicType) {
+                       IBasicType type = (IBasicType) varType;
+                       basicType = type.getBaseType();
+                       
+                       if (basicType == ICPPBasicType.t_void)
+                               throw EDCDebugger.newCoreException(ASTEvalMessages.OperandValue_CannotReadVoid);
+                       if (basicType == ICPPBasicType.t_unspecified)
+                               throw EDCDebugger.newCoreException(ASTEvalMessages.OperandValue_CannotReadUnspecifiedType);
+                       
+                       isSigned = type.isSigned();
+                       isShort = type.isShort();
+                       isLong = type.isLong();
+                       
+                       if (varType instanceof ICPPBasicType) {
+                               ICPPBasicType cppType = (ICPPBasicType) varType;
+                               isLongLong = cppType.isLongLong();
+                               isComplex  = cppType.isComplex();
+                       }
+               } else if (varType instanceof IPointerType) {
+                       // treat pointer as an unsigned int
+                       basicType = IBasicType.t_int;
+               } else if (varType instanceof IEnumerator){
+                       // treat enumerator as a signed int
+                       basicType = IBasicType.t_int;
+                       isSigned = true;
+               } else {
+                       // treat unknown type as an unsigned int
+                       basicType = IBasicType.t_int;
+                       isSigned = false;
+               }
+       
+               // if variable's size is 0, use its default size
+               if (varSize == 0) {
+                       varSize = getDefaultSize(varType, basicType, isShort, isLong, isLongLong, isComplex);
+               }
+       
+               // all other locations
+               IVariableLocation varLocation = location;
+               BigInteger varValue = null;
+               
+               if (varLocation != null) {
+                       varValue = varLocation.readValue(varSize);
+               } else {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.VariableWithValue_UnknownLocation);
+               }
+               
+               switch (basicType) {
+               case IBasicType.t_float:
+               case IBasicType.t_double:
+                       if (varSize == 4) {
+                               result = Float.intBitsToFloat(varValue.intValue());
+                       } else if (varSize == 8) {
+                               result = Double.longBitsToDouble(varValue.longValue());
+                       } else {
+                               // TODO: support 12-byte long double read from register
+                               throw EDCDebugger.newCoreException(ASTEvalMessages.VariableWithValue_NoTwelveByteLongDouble);
+                       }
+                       break;
+       
+               case ICPPBasicType.t_bool:
+               case ICPPBasicType.t_wchar_t:
+               case IBasicType.t_char:
+               case IBasicType.t_int:
+               case IBasicType.t_void:
+                       if (isSigned) {
+                               // as needed, mask the value and sign-extend
+                               if (varSize == 4) {
+                                       result = new Integer(varValue.intValue());
+                               } else if (varSize == 2) {
+                                       int intResult = varValue.intValue() & 0xffff;
+                                       if ((intResult & 0x00008000) != 0)
+                                               intResult |= 0xffff0000;
+                                       result = new Integer(intResult);
+                               } else if (varSize == 1) {
+                                       int intResult = varValue.intValue() & 0xff;
+                                       if ((intResult & 0x00000080) != 0)
+                                               intResult |= 0xffffff00;
+                                       result = new Integer(intResult);
+                               } else {
+                                       // assume an 8-byte long is the default
+                                       result = new Long(varValue.longValue());
+                               }
+                       } else {
+                               if (varSize == 4) {
+                                       result = new Long(varValue.longValue() & 0xffffffffL);  // keep it unsigned
+                               } else if (varSize == 2) {
+                                       result = new Integer(varValue.intValue() & 0xffff);
+                               } else if (varSize == 1) {
+                                       result = new Integer(varValue.intValue() & 0xff);
+                               } else {
+                                       // assume an 8-byte long is the default
+                                       result = new Long(varValue.longValue());
+                               }
+                       }
+                       break;
+       
+               case IBasicType.t_unspecified:
+               default:
+                       assert false;
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperandValue_UnhandledType);
+               }
+               return result;
+       }
+
+       private int getDefaultSize(IType varType, int basicType, boolean isShort,
+                       boolean isLong, boolean isLongLong, boolean isComplex) {
+               int varSize = 0;
+
+               // debug info should never claim something is zero size any more
+               /*
+               Object retrievedSize = null;
+               ITargetEnvironment targetEnvironmentService = servicesTracker.getService(ITargetEnvironment.class);
+               if (targetEnvironmentService != null) {
+                       Map<Integer, Integer> sizes = targetEnvironmentService.getBasicTypeSizes();
+                       
+                       switch(basicType) {
+               case IBasicType.t_char:
+                       retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_CHAR);
+                       break;
+               case IBasicType.t_int:
+                       if (isShort) {
+                               retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_SHORT);
+                       } else if (isLongLong) {
+                               retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_LONG_LONG);
+                       } else if (isLong) {
+                               retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_LONG);
+                       } else {
+                               retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_INT);
+                       }
+                       break;
+               case IBasicType.t_float:
+                       if (isComplex) {
+                               retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_FLOAT_COMPLEX);
+                       } else {
+                               retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_FLOAT);
+                       }
+                       break;
+               case IBasicType.t_double:
+                       if (isComplex) {
+                               if (isLong) {
+                                       retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_LONG_DOUBLE_COMPLEX);
+                               } else {
+                                       retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_DOUBLE_COMPLEX);
+                               }
+                       } else {
+                               if (isLong) {
+                                       retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_LONG_DOUBLE);
+                               } else {
+                                       retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_DOUBLE);
+                               }
+                       }
+                       break;
+               case ICPPBasicType.t_bool:
+                       retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_BOOL);
+                       break;
+               case ICPPBasicType.t_wchar_t:
+                       retrievedSize = sizes.get(TypeUtils.BASIC_TYPE_WCHAR_T);
+                       break;
+               default:
+                       retrievedSize = 1;
+                       }
+               }
+               if (retrievedSize != null)
+                       varSize = (Integer) retrievedSize;
+               */
+               
+               varSize = 1;
+               return varSize;
+       }
+
+       /**
+        * Get the operand value as a long
+        * @return long
+        * @throws CoreException 
+        */
+       public long getLongValue() throws CoreException {
+               return getValue().longValue();
+       }
+
+       /**
+        * @return
+        */
+       public boolean isFloating() {
+               return value instanceof Float || value instanceof Double;
+       }
+
+
+       public boolean isBitField() {
+               return isBitField;
+       }
+       
+       /**
+        * Get the value as a BigInteger 
+        * @return value or 0 if not a number
+        */
+       public BigInteger getBigIntValue() throws CoreException {
+               BigInteger bigIntVal;
+               if (getValue() == null)
+                       return BigInteger.ZERO;
+               if (value instanceof BigInteger)
+                       bigIntVal = (BigInteger) value;
+               else
+                       bigIntVal = BigInteger.valueOf(value.longValue());
+               return bigIntVal;
+       }
+       
+       public OperandValue copyWithType(IType otherType) {
+               OperandValue value = new OperandValue(otherType);
+               value.value = this.value;
+               value.stringValue = this.stringValue;
+               value.valueLocation = this.valueLocation;
+               return value;
+       }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorAddrOf.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorAddrOf.java
new file mode 100644 (file)
index 0000000..9644e54
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.PointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.RegisterVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Unary address of operation "&"
+ */
+public class OperatorAddrOf extends CompoundInstruction {
+
+       /**
+        * Constructor for address of operation "&"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorAddrOf(int start) {
+               super(start);
+       }
+
+       /**
+        * Resolve an address of operation "&"
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() throws CoreException {
+               OperandValue operand = popValue();
+
+               // only allow address of an lvalue
+               if (operand.getValueLocation() == null) {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperatorAddrOf_RequiresVariable);
+               }
+
+               IType subType = operand.getValueType();
+
+               // do not allow a variable that is in a register
+               if (operand.getValueLocation() instanceof RegisterVariableLocation) {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperatorAddrOf_NoRegister);
+               }
+
+               // do not allow a bit-field
+               if (operand.isBitField()) {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperatorAddrOf_NoBitField);
+               }
+
+               PointerType pointer = new PointerType();
+               pointer.setType(subType);
+
+               OperandValue addr = new OperandValue(pointer);
+               addr.setValueLocation(operand.getValueLocation());
+               addr.setValue(operand.getValueLocationAddress());
+               push(addr);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBinaryAnd.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBinaryAnd.java
new file mode 100644 (file)
index 0000000..91a8e83
--- /dev/null
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary AND operation "&"
+ */
+public class OperatorBinaryAnd extends BinaryOperator {
+
+       /**
+        * Constructor for a binary AND operation "&"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorBinaryAnd(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary AND operation "&"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorBinaryAnd(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get int result of applying binary AND "&" to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>leftOperand</code> & <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand & rightOperand;
+       }
+
+       /**
+        * Get long result of applying binary AND "&" to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>leftOperand</code> & <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand & rightOperand;
+       }
+
+       /**
+        * Get BigInteger result of applying binary AND "&" to two BigIntegers
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return <code>leftOperand</code> & <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException {
+               return leftOperand.and(rightOperand);
+       }
+
+       /**
+        * Get float result of applying binary AND "&" to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return 0
+        */
+       @Override
+       protected float getFloatResult(float leftOperand, float rightOperand) {
+               return 0;
+       }
+
+       /**
+        * Get double result of applying binary AND "&" to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return 0
+        */
+       @Override
+       protected double getDoubleResult(double leftOperand, double rightOperand) {
+               return 0;
+       }
+
+       /**
+        * Get boolean result of applying binary AND "&" to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>leftOperand</code> & <code>rightOperand</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return leftOperand & rightOperand;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBinaryOr.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBinaryOr.java
new file mode 100644 (file)
index 0000000..74c8f21
--- /dev/null
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary OR operation "|"
+ */
+public class OperatorBinaryOr extends BinaryOperator {
+
+       /**
+        * Constructor for a binary OR operation "|"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorBinaryOr(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary OR operation "|"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorBinaryOr(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get int result of applying binary OR "|" to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>leftOperand</code> | <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand | rightOperand;
+       }
+
+       /**
+        * Get long result of applying binary OR "|" to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>leftOperand</code> | <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand | rightOperand;
+       }
+
+       /**
+        * Get BigInteger result of applying binary OR "|" to two BigIntegers
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return <code>leftOperand</code> | <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException {
+               return leftOperand.or(rightOperand);
+       }
+
+       /**
+        * Get float result of applying binary OR "|" to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return 0
+        */
+       @Override
+       protected float getFloatResult(float leftOperand, float rightOperand) {
+               return 0;
+       }
+
+       /**
+        * Get double result of applying binary OR "|" to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return 0
+        */
+       @Override
+       protected double getDoubleResult(double leftOperand, double rightOperand) {
+               return 0;
+       }
+
+       /**
+        * Get boolean result of applying binary OR "|" to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>leftOperand</code> | <code>rightOperand</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return leftOperand | rightOperand;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBinaryXor.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBinaryXor.java
new file mode 100644 (file)
index 0000000..6cfbd77
--- /dev/null
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary XOR operation "^"
+ */
+public class OperatorBinaryXor extends BinaryOperator {
+
+       /**
+        * Constructor for a binary XOR operation "^"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorBinaryXor(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary XOR operation "^"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorBinaryXor(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get int result of applying binary XOR "^" to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>leftOperand</code> ^ <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand ^ rightOperand;
+       }
+
+       /**
+        * Get long result of applying binary XOR "^" to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>leftOperand</code> ^ <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand ^ rightOperand;
+       }
+
+       /**
+        * Get BigInteger result of applying binary XOR "^" to two BigIntegers
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return <code>leftOperand</code> ^ <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException {
+               return leftOperand.xor(rightOperand);
+       }
+
+       /**
+        * Get float result of applying binary XOR "^" to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return 0
+        */
+       @Override
+       protected float getFloatResult(float leftOperand, float rightOperand) {
+               return 0;
+       }
+
+       /**
+        * Get double result of applying binary XOR "^" to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return 0
+        */
+       @Override
+       protected double getDoubleResult(double leftOperand, double rightOperand) {
+               return 0;
+       }
+
+       /**
+        * Get boolean result of applying binary XOR "^" to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>leftOperand</code> ^ <code>rightOperand</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return leftOperand ^ rightOperand;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBitwiseNot.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorBitwiseNot.java
new file mode 100644 (file)
index 0000000..553bbc7
--- /dev/null
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Unary bit-wise NOT operation "~"
+ */
+public class OperatorBitwiseNot extends UnaryOperator {
+
+       /**
+        * Constructor for a unary bit-wise NOT operation "~"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorBitwiseNot(int start) {
+               super(start);
+       }
+
+       /**
+        * Constructor for a unary bit-wise NOT operation "~"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       public OperatorBitwiseNot(int resultId, boolean isAssignmentOperator, int start) {
+               super(start);
+       }
+
+       /**
+        * Get int result of applying unary bit-wise NOT "~" to an int
+        * 
+        * @param operand
+        *            - int operand
+        * @return ~<code>operand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int operand) throws CoreException {
+               return ~operand;
+       }
+
+       /**
+        * Get long result of applying unary bit-wise NOT "~" to a long
+        * 
+        * @param operand
+        *            - long operand
+        * @return ~<code>operand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long operand) throws CoreException {
+               return ~operand;
+       }
+
+       /**
+        * Get BigInteger result of applying unary bit-wise NOT "~" to a BigInteger
+        * 
+        * @param operand
+        *            - BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return ~<code>operand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger operand, int length) throws CoreException {
+               return operand.not();
+       }
+
+       /**
+        * Get float result of applying unary bit-wise NOT "~" to a float
+        * 
+        * @param operand
+        *            - float operand
+        * @return 0
+        */
+       @Override
+       protected float getFloatResult(float operand) {
+               return 0;
+       }
+
+       /**
+        * Get double result of applying unary bit-wise NOT "~" to a double
+        * 
+        * @param operand
+        *            - double operand
+        * @return 0
+        */
+       @Override
+       protected double getDoubleResult(double operand) {
+               return 0;
+       }
+
+       /**
+        * Get boolean result of applying unary bit-wise NOT "~" to a boolean
+        * 
+        * @param operand
+        *            - boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean operand) {
+               return false;
+       }
+
+       /**
+        * Get string result of applying unary bit-wise NOT "~" to a string
+        * 
+        * @param operand
+        *            - string operand
+        * @return <code>null</code>
+        * @throws CoreException
+        */
+       @Override
+       protected String getStringResult(String operand) throws CoreException {
+               throw EDCDebugger.newCoreException(ASTEvalMessages.UnsupportedStringOperation);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorCast.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorCast.java
new file mode 100644 (file)
index 0000000..6d3880b
--- /dev/null
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
+import org.eclipse.cdt.core.dom.ast.IASTTypeId;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.TypeEngine;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * 
+ */
+public class OperatorCast extends CompoundInstruction {
+
+       private final IASTCastExpression castExpr;
+       private IType castType;
+
+       public OperatorCast(int start, IASTCastExpression castExpr) {
+               super(start);
+               this.castExpr = castExpr;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.Instruction#execute()
+        */
+       @Override
+       public void execute() throws CoreException {
+               OperandValue value = fInterpreter.pop();
+               if (value.getStringValue() != null)
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperatorCast_CannotCastString);
+               
+               castType = getCastType(fInterpreter.getTypeEngine());
+               
+               IVariableLocation location = value.getValueLocation();
+               
+               OperandValue castValue = new OperandValue(castType);
+               Number origValue = value.getValue();
+               Number castedValue = origValue;
+               
+               if (castType instanceof ICPPBasicType) {
+                       ICPPBasicType cppType = (ICPPBasicType) castType;
+                       // when casting to primtive integral type, reduce or zero/sign extend
+                       if (cppType.getBaseType() == ICPPBasicType.t_char || 
+                                       cppType.getBaseType() == ICPPBasicType.t_int ||
+                                       cppType.getBaseType() == ICPPBasicType.t_wchar_t ||
+                                       cppType.getBaseType() == ICPPBasicType.t_bool) {
+                               switch (cppType.getByteSize()) {
+                               case 1:
+                                       if (cppType.isSigned())
+                                               castedValue = origValue.byteValue();
+                                       else
+                                               castedValue = origValue.byteValue() & 0xff;
+                                       break;
+                               case 2:
+                                       if (cppType.isSigned())
+                                               castedValue = origValue.shortValue();
+                                       else
+                                               castedValue = origValue.shortValue() & 0xfffff;
+                                       break;
+                               case 4:
+                                       if (cppType.isSigned())
+                                               castedValue = origValue.intValue();
+                                       else
+                                               castedValue = origValue.intValue() & 0xffffffffL;
+                                       break;
+                               case 8:
+                                       if (cppType.isSigned())
+                                               castedValue = BigInteger.valueOf(origValue.longValue());
+                                       else
+                                               castedValue = BigInteger.valueOf(origValue.longValue()).and(Mask8Bytes);
+                                       break;
+                               }
+                       } else if (cppType.getBaseType() == ICPPBasicType.t_float ||
+                                       cppType.getBaseType() == ICPPBasicType.t_double) {
+                               // and be sure integers promoted to floats, if needed
+                               switch (cppType.getByteSize()) {
+                               case 4:
+                                       castedValue = Float.valueOf(origValue.longValue());
+                                       break;
+                               case 8:
+                               case 12:
+                                       castedValue = Double.valueOf(origValue.longValue());
+                                       break;
+                               }
+                       }
+               }
+               
+               castValue.setValue(castedValue);
+               castValue.setValueLocation(location);
+               
+               fInterpreter.push(castValue);
+       }
+
+       /**
+        * @return 
+        * @throws CoreException
+        */
+       public IType getCastType(TypeEngine typeEngine) throws CoreException {
+               if (castType == null) {
+                       IASTTypeId typeId = castExpr.getTypeId();
+                       castType = typeEngine.getTypeForTypeId(typeId);
+               }
+               return castType;
+       }
+
+       public IASTCastExpression getCastExpr() {
+               return castExpr;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorCastValue.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorCastValue.java
new file mode 100644 (file)
index 0000000..fd09ba5
--- /dev/null
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
+import org.eclipse.cdt.core.dom.ast.IASTTypeId;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.ValueVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.TypeEngine;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * This operator directly casts the value of an expression without going through
+ * "*(type*)&expr".  
+ */
+public class OperatorCastValue extends CompoundInstruction {
+       private IASTCastExpression castExpr;
+       private IType castType;
+
+       public OperatorCastValue(int start, IType castType) {
+               super(start);
+               this.castType = castType;
+       }
+       
+       public OperatorCastValue(int start, IASTCastExpression castExpr) {
+               super(start);
+               this.castExpr = castExpr;
+       }
+       
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.Instruction#execute()
+        */
+       @Override
+       public void execute() throws CoreException {
+               OperandValue value = fInterpreter.pop();
+               if (value.getStringValue() != null)
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperatorCast_CannotCastString);
+               
+               castType = getCastType(fInterpreter.getTypeEngine());
+               
+               IVariableLocation location = value.getValueLocation();
+               OperandValue castValue = new OperandValue(castType);
+               
+               if (location == null)
+                       location = new ValueVariableLocation(value.getBigIntValue());
+               
+               Number castedValue = castValue.getValueByType(castType, location);
+               
+               castValue.setValue(castedValue);
+               castValue.setValueLocation(location);
+       
+               fInterpreter.push(castValue);
+       }
+
+       public IType getCastType(TypeEngine typeEngine) throws CoreException {
+               if (castType == null) {
+                       IASTTypeId typeId = castExpr.getTypeId();
+                       castType = typeEngine.getTypeForTypeId(typeId);
+               }
+               return castType;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorDivide.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorDivide.java
new file mode 100644 (file)
index 0000000..091ae94
--- /dev/null
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary divide operation "/"
+ */
+public class OperatorDivide extends BinaryOperator {
+
+       /**
+        * Constructor for a binary divide operation "/"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorDivide(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary divide operation "/"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorDivide(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get int result of applying binary divide "/" to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>leftOperand</code> / <code>rightOperand</code>
+        * @throws CoreException
+        *             if <code>rightOperand</code> is 0
+        */
+       @Override
+       protected int getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               if (rightOperand == 0)
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.DivideByZero);
+               else
+                       return leftOperand / rightOperand;
+       }
+
+       /**
+        * Get long result of applying binary divide "/" to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>leftOperand</code> / <code>rightOperand</code>
+        * @throws CoreException
+        *             if <code>rightOperand</code> is 0
+        */
+       @Override
+       protected long getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               if (rightOperand == 0)
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.DivideByZero);
+               else
+                       return leftOperand / rightOperand;
+       }
+
+       /**
+        * Get BigInteger result of applying binary divide "/" to two BigIntegers
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return <code>leftOperand</code> / <code>rightOperand</code>
+        * @throws CoreException
+        *             if <code>rightOperand</code> is 0
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException {
+               if (rightOperand.equals(BigInteger.ZERO))
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.DivideByZero);
+               else
+                       return leftOperand.divide(rightOperand);
+       }
+
+       /**
+        * Get float result of applying binary divide "/" to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return <code>leftOperand</code> / <code>rightOperand</code>
+        */
+       @Override
+       protected float getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand / rightOperand;
+       }
+
+       /**
+        * Get double result of applying binary divide "/" to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return <code>leftOperand</code> / <code>rightOperand</code>
+        */
+       @Override
+       protected double getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand / rightOperand;
+       }
+
+       /**
+        * Get boolean result of applying binary divide "/" to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorEquals.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorEquals.java
new file mode 100644 (file)
index 0000000..f524b01
--- /dev/null
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary equals operation "=="
+ */
+public class OperatorEquals extends BinaryLogicalOperator {
+
+       /**
+        * Constructor for a binary equals operation "=="
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorEquals(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary equals operation "=="
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorEquals(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get boolean result of comparing two ints with equals "=="
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return true if <code>leftOperand</code> == <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand == rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two longs with equals "=="
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return true if <code>leftOperand</code> == <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand == rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two BigIntegers with equals "=="
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @return true if <code>leftOperand</code> == <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand) throws CoreException {
+               return leftOperand.equals(rightOperand);
+       }
+
+       /**
+        * Get boolean result of comparing two floats with equals "=="
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return true if <code>leftOperand</code> == <code>rightOperand</code>,
+        *         and false otherwise
+        */
+       @Override
+       protected boolean getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand == rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two doubles with equals "=="
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return true if <code>leftOperand</code> == <code>rightOperand</code>,
+        *         and false otherwise
+        */
+       @Override
+       protected boolean getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand == rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two booleans with equals "=="
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return true if <code>leftOperand</code> == <code>rightOperand</code>,
+        *         and false otherwise
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return leftOperand == rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two strings with equals "=="
+        * 
+        * @param leftOperand
+        *            - left string operand
+        * @param rightOperand
+        *            - right string operand
+        * @return true if <code>leftOperand</code> == <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getStringResult(String leftOperand, String rightOperand) throws CoreException {
+               return leftOperand.equals(rightOperand);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorGreaterEqual.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorGreaterEqual.java
new file mode 100644 (file)
index 0000000..20c9626
--- /dev/null
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary greater or equal operation ">="
+ */
+public class OperatorGreaterEqual extends BinaryLogicalOperator {
+
+       /**
+        * Constructor for a binary greater or equal operation ">="
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorGreaterEqual(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary greater or equal operation ">="
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorGreaterEqual(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get boolean result of comparing two ints with greater or equal ">="
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return true if <code>leftOperand</code> >= <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand >= rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two longs with greater or equal ">="
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return true if <code>leftOperand</code> >= <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand >= rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two BigIntegers with greater or equal
+        * ">="
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @return true if <code>leftOperand</code> >= <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand) throws CoreException {
+               return leftOperand.compareTo(rightOperand) >= 0;
+       }
+
+       /**
+        * Get boolean result of comparing two floats with greater or equal ">="
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return true if <code>leftOperand</code> >= <code>rightOperand</code>,
+        *         and false otherwise
+        */
+       @Override
+       protected boolean getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand >= rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two doubles with greater or equal ">="
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return true if <code>leftOperand</code> >= <code>rightOperand</code>,
+        *         and false otherwise
+        */
+       @Override
+       protected boolean getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand >= rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two booleans with greater or equal ">="
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+
+       /**
+        * Get boolean result of comparing two strings with greater or equal ">="
+        * 
+        * @param leftOperand
+        *            - left string operand
+        * @param rightOperand
+        *            - right string operand
+        * @return true if <code>leftOperand</code> >= <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getStringResult(String leftOperand, String rightOperand) throws CoreException {
+               return leftOperand.compareTo(rightOperand) >= 0;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorGreaterThan.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorGreaterThan.java
new file mode 100644 (file)
index 0000000..2da911e
--- /dev/null
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary greater than operation ">"
+ */
+public class OperatorGreaterThan extends BinaryLogicalOperator {
+
+       /**
+        * Constructor for a binary greater than operation ">"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorGreaterThan(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary greater than operation ">"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorGreaterThan(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get boolean result of comparing two ints with greater than ">"
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return true if <code>leftOperand</code> > <code>rightOperand</code>, and
+        *         false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand > rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two longs with greater than ">"
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return true if <code>leftOperand</code> > <code>rightOperand</code>, and
+        *         false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand > rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two BigIntegers with greater than ">"
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @return true if <code>leftOperand</code> > <code>rightOperand</code>, and
+        *         false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand) throws CoreException {
+               return leftOperand.compareTo(rightOperand) > 0;
+       }
+
+       /**
+        * Get boolean result of comparing two floats with greater than ">"
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return true if <code>leftOperand</code> > <code>rightOperand</code>, and
+        *         false otherwise
+        */
+       @Override
+       protected boolean getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand > rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two doubles with greater than ">"
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return true if <code>leftOperand</code> > <code>rightOperand</code>, and
+        *         false otherwise
+        */
+       @Override
+       protected boolean getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand > rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two booleans with greater than ">"
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+
+       /**
+        * Get boolean result of comparing two longs with greater than ">"
+        * 
+        * @param leftOperand
+        *            - left string operand
+        * @param rightOperand
+        *            - right string operand
+        * @return true if <code>leftOperand</code> > <code>rightOperand</code>, and
+        *         false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getStringResult(String leftOperand, String rightOperand) throws CoreException {
+               return leftOperand.compareTo(rightOperand) > 0;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorIndirection.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorIndirection.java
new file mode 100644 (file)
index 0000000..124e7ad
--- /dev/null
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.text.MessageFormat;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.IAggregate;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IEnumeration;
+import org.eclipse.cdt.debug.edc.internal.symbols.IField;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISubroutineType;
+import org.eclipse.cdt.debug.edc.symbols.IMemoryVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.cdt.debug.edc.symbols.VariableLocationFactory;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Unary indirection operation "*"
+ */
+public class OperatorIndirection extends CompoundInstruction {
+
+       /**
+        * Constructor for a unary indirection operation "*"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorIndirection(int start) {
+               super(start);
+       }
+
+       /**
+        * Resolve a unary indirection expression
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() throws CoreException {
+               OperandValue operand = popValue();
+
+               IType opType = TypeUtils.getUnRefStrippedType(operand.getValueType());
+               
+               if (operand.getStringValue() != null) {
+                       // read first char of a string constant
+                       pushNewValue(opType.getType(), (int) operand.getStringValue().charAt(0));
+                       return;
+               }
+               
+               if (!TypeUtils.isPointerType(opType)) {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperatorIndirection_RequiresPointer);
+               }
+
+               IPointerType pointer = (IPointerType) opType;
+               IType pointedTo = pointer.getType();
+               IType unqualifiedPointedTo = TypeUtils.getStrippedType(pointedTo);
+
+               // do not allow a pointer to a bit-field
+               if ((unqualifiedPointedTo instanceof IField) && (((IField) unqualifiedPointedTo).getBitSize() != 0)) {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperatorIndirection_NoBitField);
+               }
+
+               OperandValue opValue = new OperandValue(unqualifiedPointedTo);
+               
+               // for a lvalues (base arithmetic types, enums, and pointers), read the
+               // value and cast it to the right type
+               IMemoryVariableLocation location = VariableLocationFactory.createMemoryVariableLocation(
+                               fInterpreter.getServicesTracker(), fInterpreter.getContext(),
+                               operand.getValue());
+               
+               if (unqualifiedPointedTo instanceof ICPPBasicType || unqualifiedPointedTo instanceof IPointerType
+                               || unqualifiedPointedTo instanceof IEnumeration) {
+                       int byteSize = unqualifiedPointedTo.getByteSize();
+                       
+                       // treat ICPPBasicType of byte size 0 as a void pointer (size 4)
+                       if (unqualifiedPointedTo instanceof ICPPBasicType && byteSize == 0)
+                               byteSize = 4;
+
+                       if (byteSize != 1 && byteSize != 2 && byteSize != 4 && byteSize != 8) {
+                               throw EDCDebugger.newCoreException(MessageFormat.format(ASTEvalMessages.UnhandledSize, byteSize));
+                       }
+
+                       // read the value pointed to
+                       Number newValue = operand.getValueByType(unqualifiedPointedTo, location);
+                       opValue.setValue(newValue);
+                       opValue.setValueLocation(location);
+                       push(opValue);
+
+               } else if (unqualifiedPointedTo instanceof IAggregate) {
+                       // for aggregates, the address of the aggregate is the value
+                       // returned
+                       opValue.setAddressValue(location);
+                       opValue.setValueLocation(location);
+                       push(opValue);
+
+               } else {
+                       if (unqualifiedPointedTo instanceof ISubroutineType)
+                               throw EDCDebugger.newCoreException(ASTEvalMessages.OperatorIndirection_NoFunction);
+                       else
+                               throw EDCDebugger.newCoreException(MessageFormat.format(ASTEvalMessages.OperatorIndirection_UnhandledType, 
+                                               unqualifiedPointedTo != null ? unqualifiedPointedTo.getName() : "null"));
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLessEqual.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLessEqual.java
new file mode 100644 (file)
index 0000000..42f4674
--- /dev/null
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary less or equal operation "<="
+ */
+public class OperatorLessEqual extends BinaryLogicalOperator {
+
+       /**
+        * Constructor for a binary less or equal operation "<="
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorLessEqual(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary less or equal operation "<="
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorLessEqual(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get boolean result of comparing two ints with less or equal "<="
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return true if <code>leftOperand</code> <= <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand <= rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two longs with less or equal "<="
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return true if <code>leftOperand</code> <= <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand <= rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two BigIntegers with less or equal "<="
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @return true if <code>leftOperand</code> <= <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand) throws CoreException {
+               return leftOperand.compareTo(rightOperand) <= 0;
+       }
+
+       /**
+        * Get boolean result of comparing two floats with less or equal "<="
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return true if <code>leftOperand</code> <= <code>rightOperand</code>,
+        *         and false otherwise
+        */
+       @Override
+       protected boolean getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand <= rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two doubles with less or equal "<="
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return true if <code>leftOperand</code> <= <code>rightOperand</code>,
+        *         and false otherwise
+        */
+       @Override
+       protected boolean getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand <= rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two booleans with less or equal "<="
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+
+       /**
+        * Get boolean result of comparing two strings with less or equal "<="
+        * 
+        * @param leftOperand
+        *            - left string operand
+        * @param rightOperand
+        *            - right string operand
+        * @return true if <code>leftOperand</code> <= <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getStringResult(String leftOperand, String rightOperand) throws CoreException {
+               return leftOperand.compareTo(rightOperand) <= 0;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLessThan.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLessThan.java
new file mode 100644 (file)
index 0000000..36bf245
--- /dev/null
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary less than operation "<"
+ */
+public class OperatorLessThan extends BinaryLogicalOperator {
+
+/**
+        * Constructor for a binary less than operation "<"
+        * 
+        * @param start - instruction start
+        */
+       public OperatorLessThan(int start) {
+               this(0, false, start);
+       }
+
+/**
+        * Constructor for a binary less than operation "<"
+        * 
+        * @param resultId - for assignment, variable ID of the result 
+        * @param isAssignmentOperator - whether the result is assigned
+        * @param start - instruction start
+        */
+       protected OperatorLessThan(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+/**
+        * Get boolean result of comparing two ints with less than "<"
+        * 
+        * @param leftOperand - left int operand
+        * @param rightOperand - right int operand
+        * @return true if <code>leftOperand</code> < <code>rightOperand</code>, and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand < rightOperand;
+       }
+
+/**
+        * Get boolean result of comparing two longs with less than "<"
+        * 
+        * @param leftOperand - left long operand
+        * @param rightOperand - right long operand
+        * @return true if <code>leftOperand</code> < <code>rightOperand</code>, and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand < rightOperand;
+       }
+
+/**
+        * Get boolean result of comparing two BigIntegers with less than "<"
+        * 
+        * @param leftOperand - left BigInteger operand
+        * @param rightOperand - right BigInteger operand
+        * @return true if <code>leftOperand</code> < <code>rightOperand</code>, and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand) throws CoreException {
+               return leftOperand.compareTo(rightOperand) < 0;
+       }
+
+/**
+        * Get boolean result of comparing two floats with less than "<"
+        * 
+        * @param leftOperand - left float operand
+        * @param rightOperand - right float operand
+        * @return true if <code>leftOperand</code> < <code>rightOperand</code>, and false otherwise
+        */
+       @Override
+       protected boolean getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand < rightOperand;
+       }
+
+/**
+        * Get boolean result of comparing two doubles with less than "<"
+        * 
+        * @param leftOperand - left double operand
+        * @param rightOperand - right double operand
+        * @return true if <code>leftOperand</code> < <code>rightOperand</code>, and false otherwise
+        */
+       @Override
+       protected boolean getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand < rightOperand;
+       }
+
+/**
+        * Get boolean result of comparing two longs with less than "<"
+        * 
+        * @param leftOperand - left long operand
+        * @param rightOperand - right long operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+
+/**
+        * Get boolean result of comparing two strings with less than "<"
+        * 
+        * @param leftOperand - left string operand
+        * @param rightOperand - right string operand
+        * @return true if <code>leftOperand</code> < <code>rightOperand</code>, and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getStringResult(String leftOperand, String rightOperand) throws CoreException {
+               return leftOperand.compareTo(rightOperand) < 0;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLogicalAnd.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLogicalAnd.java
new file mode 100644 (file)
index 0000000..ddbae53
--- /dev/null
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary logical AND operation "&&"
+ */
+public class OperatorLogicalAnd extends BinaryLogicalOperator {
+
+       /**
+        * Constructor for a binary logical AND operation "&&"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorLogicalAnd(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary logical AND operation "&&"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorLogicalAnd(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get boolean result of comparing two ints with logical AND "&&"
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               // as bools
+               return (leftOperand != 0) && (rightOperand != 0);
+       }
+
+       /**
+        * Get boolean result of comparing two longs with logical AND "&&"
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               // as bools
+               return (leftOperand != 0) && (rightOperand != 0);
+       }
+
+       /**
+        * Get boolean result of comparing two BigIntegers with logical AND "&&"
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand) throws CoreException {
+               // as bools
+               return (leftOperand.signum() != 0) && (rightOperand.signum() != 0);
+       }
+
+       /**
+        * Get boolean result of comparing two floats with logical AND "&&"
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getFloatResult(float leftOperand, float rightOperand) {
+               // as bools
+               return (leftOperand != 0) && (rightOperand != 0);
+       }
+
+       /**
+        * Get boolean result of comparing two doubles with logical AND "&&"
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getDoubleResult(double leftOperand, double rightOperand) {
+               // as bools
+               return (leftOperand != 0) && (rightOperand != 0);
+       }
+
+       /**
+        * Get boolean result of comparing two booleans with logical AND "&&"
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return true if <code>leftOperand</code> && <code>rightOperand</code> is
+        *         true, and false otherwise
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return leftOperand && rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two strings with logical AND "&&"
+        * 
+        * @param leftOperand
+        *            - left string operand
+        * @param rightOperand
+        *            - right string operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getStringResult(String leftOperand, String rightOperand) throws CoreException {
+               return true;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLogicalNot.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLogicalNot.java
new file mode 100644 (file)
index 0000000..000a315
--- /dev/null
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Unary logical NOT operation "!"
+ */
+public class OperatorLogicalNot extends UnaryLogicalOperator {
+
+       /**
+        * Constructor for a unary logical NOT operation "!"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorLogicalNot(int start) {
+               super(start);
+       }
+
+       /**
+        * Get boolean result of applying logical NOT "!" to an int
+        * 
+        * @param operand
+        *            - int operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getIntResult(int leftOperand) throws CoreException {
+               // as bool
+               return leftOperand == 0;
+       }
+
+       /**
+        * Get boolean result of applying logical NOT "!" to a long
+        * 
+        * @param operand
+        *            - long operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getLongResult(long leftOperand) throws CoreException {
+               // as bool
+               return leftOperand == 0;
+       }
+
+       /**
+        * Get boolean result of applying logical NOT "!" to a BigInteger
+        * 
+        * @param operand
+        *            - BigInteger operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getBigIntegerResult(BigInteger leftOperand) throws CoreException {
+               // as bool
+               return leftOperand.signum() == 0;
+       }
+
+       /**
+        * Get boolean result of applying logical NOT "!" to a float
+        * 
+        * @param operand
+        *            - float operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getFloatResult(float leftOperand) {
+               // as bool
+               return leftOperand == 0;
+       }
+
+       /**
+        * Get boolean result of applying logical NOT "!" to a double
+        * 
+        * @param operand
+        *            - double operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getDoubleResult(double leftOperand) {
+               // as bool
+               return leftOperand == 0;
+       }
+
+       /**
+        * Get boolean result of applying logical NOT "!" to a boolean
+        * 
+        * @param operand
+        *            - boolean operand
+        * @return !<code>operand</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand) {
+               return !leftOperand;
+       }
+
+       /**
+        * Get boolean result of applying logical NOT "!" to a string
+        * 
+        * @param operand
+        *            - string operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getStringResult(String leftOperand) throws CoreException {
+               // not of address
+               return false;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLogicalOr.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorLogicalOr.java
new file mode 100644 (file)
index 0000000..4d97b43
--- /dev/null
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary logical OR operation "||"
+ */
+public class OperatorLogicalOr extends BinaryLogicalOperator {
+
+       /**
+        * Constructor for a binary logical OR operation "||"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorLogicalOr(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary logical OR operation "||"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorLogicalOr(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get boolean result of comparing two ints with logical OR "||"
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               // as bools
+               return (leftOperand != 0) || (rightOperand != 0);
+       }
+
+       /**
+        * Get boolean result of comparing two longs with logical OR "||"
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               // as bools
+               return (leftOperand != 0) || (rightOperand != 0);
+       }
+
+       /**
+        * Get boolean result of comparing two BigIntegers with logical OR "||"
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand) throws CoreException {
+               // as bools
+               return (leftOperand.signum() != 0) || (rightOperand.signum() != 0);
+       }
+
+       /**
+        * Get boolean result of comparing two floats with logical OR "||"
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getFloatResult(float leftOperand, float rightOperand) {
+               // as bools
+               return (leftOperand != 0) || (rightOperand != 0);
+
+       }
+
+       /**
+        * Get boolean result of comparing two doubles with logical OR "||"
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getDoubleResult(double leftOperand, double rightOperand) {
+               // as bools
+               return (leftOperand != 0) || (rightOperand != 0);
+       }
+
+       /**
+        * Get boolean result of comparing two booleans with logical OR "||"
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return true if <code>leftOperand</code> || <code>rightOperand</code> is
+        *         true, and false otherwise
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return leftOperand || rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two strings with logical OR "||"
+        * 
+        * @param leftOperand
+        *            - left string operand
+        * @param rightOperand
+        *            - right string operand
+        * @return <code>false</code>
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getStringResult(String leftOperand, String rightOperand) throws CoreException {
+               // address or
+               return true;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorMinus.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorMinus.java
new file mode 100644 (file)
index 0000000..e1b999e
--- /dev/null
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary minus operation "-"
+ */
+public class OperatorMinus extends BinaryOperator {
+
+       /**
+        * Constructor for a binary minus operation "-"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorMinus(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary minus operation "-"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorMinus(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.BinaryOperator#customHandleOperation(org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperandValue, org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperandValue)
+        */
+       @Override
+       protected boolean customHandleOperation(Interpreter fInterpreter,
+                       OperandValue left, OperandValue right) throws CoreException {
+               IType rightType = null;
+               IType leftType = null;
+
+               boolean isLeftPointer = false;
+               leftType = TypeUtils.getStrippedType(left.getValueType());
+               isLeftPointer = leftType instanceof IPointerType || leftType instanceof IArrayType;
+
+               boolean isRightPointer = false;
+               rightType = TypeUtils.getStrippedType(right.getValueType());
+               isRightPointer = rightType instanceof IPointerType || rightType instanceof IArrayType;
+
+               // no pointer operands
+               if (!isLeftPointer && !isRightPointer) {
+                       return false;
+               }
+
+               // only pointer is on the right
+               if (!isLeftPointer && isRightPointer) {
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperatorMinus_NonPtrMinusPtr);
+               }
+
+               // ignore strings
+               if (getValueType(left) == T_String && getValueType(right) == T_String)
+                       return false;
+               
+               BigInteger bigIntAddress = left.getBigIntValue();
+               
+               BigInteger aggregateSize;
+               if (leftType instanceof IPointerType)
+                       aggregateSize = BigInteger.valueOf(leftType.getByteSize());
+               else
+                       aggregateSize = BigInteger.valueOf(TypeUtils.getStrippedType(leftType.getType())
+                                       .getByteSize());
+
+               if (!isRightPointer) {
+                       right = convertForPromotion(right);
+               }
+
+               BigInteger subtractAmount = right.getBigIntValue();
+
+               if (!isRightPointer)
+                       subtractAmount = subtractAmount.multiply(aggregateSize);
+
+               bigIntAddress = bigIntAddress.subtract(subtractAmount);
+
+               // if both are pointers, subtract, then divide by size of what's pointed
+               // to
+               if (isRightPointer && aggregateSize.longValue() != 0)
+                       bigIntAddress = bigIntAddress.divide(aggregateSize);
+
+               if (isRightPointer)
+                       pushNewValue(left.getValueType(), bigIntAddress);
+               else
+                       pushNewValue(fInterpreter.getTypeEngine().getPointerSizeType(), bigIntAddress);
+               
+               return true;
+       }
+
+       /**
+        * Get int result of applying binary minus "-" to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>leftOperand</code> - <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand - rightOperand;
+       }
+
+       /**
+        * Get long result of applying binary minus "-" to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>leftOperand</code> - <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand - rightOperand;
+       }
+
+       /**
+        * Get BigInteger result of applying binary minus "-" to two BigIntegers
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return <code>leftOperand</code> - <code>rightOperand</code>, truncated
+        *         to 8 bytes
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException {
+               return leftOperand.subtract(rightOperand).and(Instruction.Mask8Bytes);
+       }
+
+       /**
+        * Get float result of applying binary minus "-" to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return <code>leftOperand</code> - <code>rightOperand</code>
+        */
+       @Override
+       protected float getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand - rightOperand;
+       }
+
+       /**
+        * Get double result of applying binary minus "-" to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return <code>leftOperand</code> - <code>rightOperand</code>
+        */
+       @Override
+       protected double getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand - rightOperand;
+       }
+
+       /**
+        * Get boolean result of applying binary minus "-" to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorModulo.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorModulo.java
new file mode 100644 (file)
index 0000000..85b96ef
--- /dev/null
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary modulo operation "%"
+ */
+public class OperatorModulo extends BinaryOperator {
+
+       /**
+        * Constructor for a binary modulo operation "%"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorModulo(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary modulo operation "%"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorModulo(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get int result of applying binary modulo "%" to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>leftOperand</code> % <code>rightOperand</code>
+        * @throws CoreException
+        *             if <code>rightOperand</code> is 0
+        */
+       @Override
+       protected int getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               if (rightOperand == 0)
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.DivideByZero);
+               else
+                       return leftOperand % rightOperand;
+       }
+
+       /**
+        * Get long result of applying binary modulo "%" to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>leftOperand</code> % <code>rightOperand</code>
+        * @throws CoreException
+        *             if <code>rightOperand</code> is 0
+        */
+       @Override
+       protected long getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               if (rightOperand == 0)
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.DivideByZero);
+               else
+                       return leftOperand % rightOperand;
+       }
+
+       /**
+        * Get BigInteger result of applying binary modulo "%" to two BigIntegers
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return <code>leftOperand</code> % <code>rightOperand</code>
+        * @throws CoreException
+        *             if <code>rightOperand</code> is 0
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException {
+               if (rightOperand.equals(BigInteger.ZERO))
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.DivideByZero);
+               else
+                       return leftOperand.mod(rightOperand);
+       }
+
+       /**
+        * Get float result of applying binary modulo "%" to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return 0
+        */
+       @Override
+       protected float getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand % rightOperand;
+       }
+
+       /**
+        * Get double result of applying binary modulo "%" to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return 0
+        */
+       @Override
+       protected double getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand % rightOperand;
+       }
+
+       /**
+        * Get boolean result of applying binary modulo "%" to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorMultiply.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorMultiply.java
new file mode 100644 (file)
index 0000000..40cb543
--- /dev/null
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary multiply operation "*"
+ */
+public class OperatorMultiply extends BinaryOperator {
+
+       /**
+        * Constructor for a binary multiply operation "*"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorMultiply(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary multiply operation "*"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorMultiply(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get int result of applying binary multiply "*" to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>leftOperand</code> * <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand * rightOperand;
+       }
+
+       /**
+        * Get long result of applying binary multiply "*" to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>leftOperand</code> * <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand * rightOperand;
+       }
+
+       /**
+        * Get BigInteger result of applying binary multiply "*" to two BigIntegers
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return <code>leftOperand</code> * <code>rightOperand</code>, truncated
+        *         to 8 bytes
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException {
+               return leftOperand.multiply(rightOperand).and(Instruction.Mask8Bytes);
+       }
+
+       /**
+        * Get float result of applying binary multiply "*" to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return <code>leftOperand</code> * <code>rightOperand</code>
+        */
+       @Override
+       protected float getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand * rightOperand;
+       }
+
+       /**
+        * Get double result of applying binary multiply "*" to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return <code>leftOperand</code> * <code>rightOperand</code>
+        */
+       @Override
+       protected double getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand * rightOperand;
+       }
+
+       /**
+        * Get boolean result of applying binary multiply "*" to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorNotEquals.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorNotEquals.java
new file mode 100644 (file)
index 0000000..748e7eb
--- /dev/null
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary not equals operation "!="
+ */
+public class OperatorNotEquals extends BinaryLogicalOperator {
+
+       /**
+        * Constructor for a binary not equals operation "!="
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorNotEquals(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary not equals operation "!="
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorNotEquals(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get boolean result of comparing two ints with not equals "!="
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return true if <code>leftOperand</code> != <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand != rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two longs with not equals "!="
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return true if <code>leftOperand</code> != <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand != rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two BigIntegers with not equals "!="
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @return true if <code>leftOperand</code> != <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand) throws CoreException {
+               return !leftOperand.equals(rightOperand);
+       }
+
+       /**
+        * Get boolean result of comparing two floats with not equals "!="
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return true if <code>leftOperand</code> != <code>rightOperand</code>,
+        *         and false otherwise
+        */
+       @Override
+       protected boolean getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand != rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two doubles with not equals "!="
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return true if <code>leftOperand</code> != <code>rightOperand</code>,
+        *         and false otherwise
+        */
+       @Override
+       protected boolean getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand != rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two booleans with not equals "!="
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return true if <code>leftOperand</code> != <code>rightOperand</code>,
+        *         and false otherwise
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return leftOperand != rightOperand;
+       }
+
+       /**
+        * Get boolean result of comparing two strings with not equals "!="
+        * 
+        * @param leftOperand
+        *            - left string operand
+        * @param rightOperand
+        *            - right string operand
+        * @return true if <code>leftOperand</code> != <code>rightOperand</code>,
+        *         and false otherwise
+        * @throws CoreException
+        */
+       @Override
+       protected boolean getStringResult(String leftOperand, String rightOperand) throws CoreException {
+               return !leftOperand.equals(rightOperand);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorPlus.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorPlus.java
new file mode 100644 (file)
index 0000000..0fe52cb
--- /dev/null
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary add operation "+"
+ */
+public class OperatorPlus extends BinaryOperator {
+
+       /**
+        * Constructor for a binary add operation "+"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorPlus(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary add operation "+"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorPlus(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.BinaryOperator#customHandleOperation(org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperandValue, org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperandValue)
+        */
+       @Override
+       protected boolean customHandleOperation(Interpreter fInterpreter,
+                       OperandValue left, OperandValue right) throws CoreException {
+               IType rightType = null;
+               IType leftType = null;
+
+               boolean isLeftPointer = false;
+               leftType = TypeUtils.getStrippedType(left.getValueType());
+               isLeftPointer = leftType instanceof IPointerType || leftType instanceof IArrayType;
+
+               boolean isRightPointer = false;
+               rightType = TypeUtils.getStrippedType(right.getValueType());
+               isRightPointer = rightType instanceof IPointerType || rightType instanceof IArrayType;
+
+               // zero pointer operands
+               if (!isLeftPointer && !isRightPointer) {
+                       return false;
+               }
+
+               // two pointer operands
+               if (isLeftPointer && isRightPointer) {
+                       // allow for strings...
+                       if (getValueType(left) == T_String && getValueType(right) == T_String)
+                               return false;
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.OperatorPlus_PtrPlusPtr);
+               }
+
+               // get the non-pointer on the left
+               if (isRightPointer) {
+                       OperandValue temp = right;
+                       right = left;
+                       left = temp;
+                       temp = right;
+                       right = left;
+                       left = temp;
+                       IType tempType = rightType;
+                       rightType = leftType;
+                       leftType = tempType;
+               }
+
+               // convert the left address to BigInteger
+               BigInteger bigIntAddress = left.getBigIntValue();
+
+               BigInteger aggregateSize = BigInteger.ZERO;
+               if (leftType instanceof IPointerType)
+                       aggregateSize = BigInteger.valueOf(leftType.getByteSize());
+               else
+                       aggregateSize = BigInteger.valueOf(TypeUtils.getStrippedType(leftType.getType())
+                                       .getByteSize());
+               BigInteger addAmount = aggregateSize;
+
+               right = convertForPromotion(right);
+               
+               addAmount = addAmount.multiply(right.getBigIntValue());         
+
+               bigIntAddress = bigIntAddress.add(addAmount);
+
+               pushNewValue(left.getValueType(), bigIntAddress);
+
+               return true;
+       }
+
+       /**
+        * Get int result of applying binary plus "+" to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>leftOperand</code> + <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand + rightOperand;
+       }
+
+       /**
+        * Get long result of applying binary plus "+" to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>leftOperand</code> + <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand + rightOperand;
+       }
+
+       /**
+        * Get BigInteger result of applying binary plus "+" to two BigIntegers
+        * 
+        * @param leftOperand
+        *            - BigInteger long operand
+        * @param rightOperand
+        *            - BigInteger long operand
+        * @param length
+        *            - length in bytes of result
+        * @return <code>leftOperand</code> + <code>rightOperand</code>, truncated
+        *         to 8 bytes
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException {
+               return leftOperand.add(rightOperand).and(Instruction.Mask8Bytes);
+       }
+
+       /**
+        * Get float result of applying binary plus "+" to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return <code>leftOperand</code> + <code>rightOperand</code>
+        */
+       @Override
+       protected float getFloatResult(float leftOperand, float rightOperand) {
+               return leftOperand + rightOperand;
+       }
+
+       /**
+        * Get double result of applying binary plus "+" to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return <code>leftOperand</code> + <code>rightOperand</code>
+        */
+       @Override
+       protected double getDoubleResult(double leftOperand, double rightOperand) {
+               return leftOperand + rightOperand;
+       }
+
+       /**
+        * Get boolean result of applying binary plus "+" to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+
+       /**
+        * Get string result of applying binary plus "+" to two strings
+        * 
+        * @param leftOperand
+        *            - left string operand
+        * @param rightOperand
+        *            - right string operand
+        * @return <code>leftOperand</code> + <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected String getStringResult(String leftOperand, String rightOperand) throws CoreException {
+               return leftOperand + rightOperand;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorShiftLeft.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorShiftLeft.java
new file mode 100644 (file)
index 0000000..c61b040
--- /dev/null
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary shift left operation "<<"
+ */
+public class OperatorShiftLeft extends BinaryOperator {
+
+       /**
+        * Constructor for a binary shift left operation "<<"
+        * 
+        * @param start - instruction start
+        */
+       public OperatorShiftLeft(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary shift left operation "<<"
+        * 
+        * @param resultId - for assignment, variable ID of the result 
+        * @param isAssignmentOperator - whether the result is assigned
+        * @param start - instruction start
+        */
+       protected OperatorShiftLeft(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get int result of applying binary shift left "<<" to two ints
+        * 
+        * @param leftOperand - left int operand
+        * @param rightOperand - right int operand
+        * @return <code>leftOperand</code> << <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand << rightOperand;
+       }
+
+       /**
+        * Get long result of applying binary shift left "<<" to two longs
+        * 
+        * @param leftOperand - left long operand
+        * @param rightOperand - right long operand
+        * @return <code>leftOperand</code> << <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand << rightOperand;
+       }
+
+       /**
+        * Get BigInteger result of applying binary shift left "<<" to two BigIntegers
+        * 
+        * @param leftOperand - left BigInteger operand
+        * @param rightOperand - right BigInteger operand
+        * @param length - length in bytes of result
+        * @return <code>leftOperand</code> << <code>rightOperand</code>, truncated to 8 bytes
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException {
+               return leftOperand.shiftLeft(rightOperand.intValue()).and(Instruction.Mask8Bytes);
+       }
+
+       /**
+        * Get float result of applying binary shift left "<<" to two floats
+        * 
+        * @param leftOperand - left float operand
+        * @param rightOperand - right float operand
+        * @return 0
+        */
+       @Override
+       protected float getFloatResult(float leftOperand, float rightOperand) {
+               return 0;
+       }
+
+       /**
+        * Get double result of applying binary shift left "<<" to two doubles
+        * 
+        * @param leftOperand - left double operand
+        * @param rightOperand - right double operand
+        * @return 0
+        */
+       @Override
+       protected double getDoubleResult(double leftOperand, double rightOperand) {
+               return 0;
+       }
+
+       /**
+        * Get boolean result of applying binary shift left "<<" to two booleans
+        * 
+        * @param leftOperand - left boolean operand
+        * @param rightOperand - right boolean operand
+        * @return boolean
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorShiftRight.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorShiftRight.java
new file mode 100644 (file)
index 0000000..8f36735
--- /dev/null
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Binary shift right operation ">>"
+ */
+public class OperatorShiftRight extends BinaryOperator {
+
+       /**
+        * Constructor for a binary shift right operation ">>"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorShiftRight(int start) {
+               this(0, false, start);
+       }
+
+       /**
+        * Constructor for a binary shift right operation ">>"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       protected OperatorShiftRight(int resultId, boolean isAssignmentOperator, int start) {
+               super(resultId, isAssignmentOperator, start);
+       }
+
+       /**
+        * Get int result of applying binary shift right ">>" to two ints
+        * 
+        * @param leftOperand
+        *            - left int operand
+        * @param rightOperand
+        *            - right int operand
+        * @return <code>leftOperand</code> >> <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int leftOperand, int rightOperand) throws CoreException {
+               return leftOperand >> rightOperand;
+       }
+
+       /**
+        * Get long result of applying binary shift right ">>" to two longs
+        * 
+        * @param leftOperand
+        *            - left long operand
+        * @param rightOperand
+        *            - right long operand
+        * @return <code>leftOperand</code> >> <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long leftOperand, long rightOperand) throws CoreException {
+               return leftOperand >> rightOperand;
+       }
+
+       /**
+        * Get BigInteger result of applying binary shift right ">>" to two
+        * BigIntegers
+        * 
+        * @param leftOperand
+        *            - left BigInteger operand
+        * @param rightOperand
+        *            - right BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return <code>leftOperand</code> >> <code>rightOperand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger leftOperand, BigInteger rightOperand, int length)
+                       throws CoreException {
+               return leftOperand.shiftRight(rightOperand.intValue());
+       }
+
+       /**
+        * Get float result of applying binary shift right ">>" to two floats
+        * 
+        * @param leftOperand
+        *            - left float operand
+        * @param rightOperand
+        *            - right float operand
+        * @return 0
+        */
+       @Override
+       protected float getFloatResult(float leftOperand, float rightOperand) {
+               return 0;
+       }
+
+       /**
+        * Get double result of applying binary shift right ">>" to two doubles
+        * 
+        * @param leftOperand
+        *            - left double operand
+        * @param rightOperand
+        *            - right double operand
+        * @return 0
+        */
+       @Override
+       protected double getDoubleResult(double leftOperand, double rightOperand) {
+               return 0;
+       }
+
+       /**
+        * Get boolean result of applying binary shift right ">>" to two booleans
+        * 
+        * @param leftOperand
+        *            - left boolean operand
+        * @param rightOperand
+        *            - right boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean leftOperand, boolean rightOperand) {
+               return false;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorUnaryMinus.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorUnaryMinus.java
new file mode 100644 (file)
index 0000000..14c5e39
--- /dev/null
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Unary minus operation "-"
+ */
+public class OperatorUnaryMinus extends UnaryOperator {
+
+       /**
+        * Constructor for a unary minus operation "-"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public OperatorUnaryMinus(int start) {
+               super(start);
+       }
+
+       /**
+        * Constructor for a unary minus operation "-"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       public OperatorUnaryMinus(int resultId, boolean isAssignmentOperator, int start) {
+               super(start);
+       }
+
+       /**
+        * Get int result of applying unary minus "-" to an int
+        * 
+        * @param operand
+        *            - int operand
+        * @return -<code>operand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int operand) throws CoreException {
+               return -operand;
+       }
+
+       /**
+        * Get long result of applying unary minus "-" to a long
+        * 
+        * @param operand
+        *            - long operand
+        * @return -<code>operand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long operand) throws CoreException {
+               return -operand;
+       }
+
+       /**
+        * Get BigInteger result of applying unary minus "-" to a BigInteger
+        * 
+        * @param operand
+        *            - BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return -<code>operand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger operand, int length) throws CoreException {
+               return operand.negate();
+       }
+
+       /**
+        * Get float result of applying unary minus "-" to a float
+        * 
+        * @param operand
+        *            - float operand
+        * @return -<code>operand</code>
+        */
+       @Override
+       protected float getFloatResult(float operand) {
+               return -operand;
+       }
+
+       /**
+        * Get double result of applying unary minus "-" to a double
+        * 
+        * @param operand
+        *            - double operand
+        * @return -<code>operand</code>
+        */
+       @Override
+       protected double getDoubleResult(double operand) {
+               return -operand;
+       }
+
+       /**
+        * Get boolean result of applying unary minus "-" to a boolean
+        * 
+        * @param operand
+        *            - boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean operand) {
+               return false;
+       }
+
+       /**
+        * Get string result of applying unary minus "-" to a string
+        * 
+        * @param operand
+        *            - string operand
+        * @return <code>null</code>
+        * @throws CoreException
+        */
+       @Override
+       protected String getStringResult(String operand) throws CoreException {
+               throw EDCDebugger.newCoreException(ASTEvalMessages.UnsupportedStringOperation);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorUnaryPlus.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/OperatorUnaryPlus.java
new file mode 100644 (file)
index 0000000..295ff1d
--- /dev/null
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Unary plus operation "+"
+ */
+public class OperatorUnaryPlus extends UnaryOperator {
+
+       /**
+        * Constructor for unary plus operator "+"
+        * 
+        * @param start
+        */
+       public OperatorUnaryPlus(int start) {
+               super(start);
+       }
+
+       /**
+        * Constructor for a unary plus operation "+"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       public OperatorUnaryPlus(int resultId, boolean isAssignmentOperator, int start) {
+               super(start);
+       }
+
+       /**
+        * Get int result of applying unary plus "+" to an int
+        * 
+        * @param operand
+        *            - int operand
+        * @return <code>operand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected int getIntResult(int operand) throws CoreException {
+               return operand;
+       }
+
+       /**
+        * Get long result of applying unary plus "+" to a long
+        * 
+        * @param operand
+        *            - long operand
+        * @return <code>operand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected long getLongResult(long operand) throws CoreException {
+               return operand;
+       }
+
+       /**
+        * Get BigInteger result of applying unary plus "+" to a BigInteger
+        * 
+        * @param operand
+        *            - BigInteger operand
+        * @param length
+        *            - length in bytes of result
+        * @return <code>operand</code>
+        * @throws CoreException
+        */
+       @Override
+       protected BigInteger getBigIntegerResult(BigInteger operand, int length) throws CoreException {
+               return operand;
+       }
+
+       /**
+        * Get float result of applying unary plus "+" to a float
+        * 
+        * @param operand
+        *            - float operand
+        * @return <code>operand</code>
+        */
+       @Override
+       protected float getFloatResult(float operand) {
+               return operand;
+       }
+
+       /**
+        * Get double result of applying unary plus "+" to a double
+        * 
+        * @param operand
+        *            - double operand
+        * @return <code>operand</code>
+        */
+       @Override
+       protected double getDoubleResult(double operand) {
+               return operand;
+       }
+
+       /**
+        * Get boolean result of applying unary plus "+" to a boolean
+        * 
+        * @param operand
+        *            - boolean operand
+        * @return <code>false</code>
+        */
+       @Override
+       protected boolean getBooleanResult(boolean operand) {
+               return false;
+       }
+
+       /**
+        * Get string result of applying unary plus "+" to a string
+        * 
+        * @param operand
+        *            - string operand
+        * @return <code>null</code>
+        * @throws CoreException
+        */
+       @Override
+       protected String getStringResult(String operand) throws CoreException {
+               throw EDCDebugger.newCoreException(ASTEvalMessages.UnsupportedStringOperation);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushBoolean.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushBoolean.java
new file mode 100644 (file)
index 0000000..5db6420
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Push a boolean on the instruction stack
+ */
+public class PushBoolean extends SimpleInstruction {
+       private boolean fValue;
+
+       /**
+        * Constructor for pushing a boolean on the stack
+        * 
+        * @param value
+        *            - boolean value
+        */
+       public PushBoolean(boolean value) {
+               fValue = value;
+       }
+
+       /**
+        * Execute pushing a boolean on the stack
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() {
+               pushNewValue(fInterpreter.getTypeEngine().getBooleanType(4), fValue);
+       }
+
+       /**
+        * Show a boolean value as a string
+        * 
+        * @return string version of a boolean
+        */
+       @Override
+       public String toString() {
+               return Boolean.toString(fValue);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushChar.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushChar.java
new file mode 100644 (file)
index 0000000..e043669
--- /dev/null
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Push a character on the instruction stack
+ * 
+ * Note: if the character does not fit in a byte, it is represented by the low 4 bytes of a Java long */
+public class PushChar extends SimpleInstruction {
+
+       static private final char BELL = '\u0007';
+       static private final char VERTICAL_TAB = '\u000B';
+
+       // character value
+       private long fValue;
+       // is wchar_t?
+       private boolean isWide;
+       // if true, the value is multiple characters (e.g. 'AB' or 'CWIE')
+       private boolean multiChar;
+       
+       /**
+        * Constructor for pushing a char on the stack
+        * 
+        * @param value
+        *            - char value
+        */
+       public PushChar(char value) {
+               fValue = (short) value;
+       }
+
+       /**
+        * Constructor for pushing a char on the stack
+        * 
+        * @param value
+        *            - string value of form 'X' to convert to char X
+        * @throws NumberFormatException
+        */
+       public PushChar(String value) throws NumberFormatException {
+               parseCharValue(value);
+       }
+
+       /**
+        * Execute pushing a char on the stack
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() {
+               if (multiChar) {
+                       pushNewValue(fInterpreter.getTypeEngine().getIntegerTypeOfSize(4, false), fValue);
+                       return;
+               }
+               
+               if (!isWide) {
+                       // TODO: truncate to size of this type
+                       pushNewValue(fInterpreter.getTypeEngine().getCharacterType(
+                                       fInterpreter.getTypeEngine().getTypeSize(TypeUtils.BASIC_TYPE_CHAR)), fValue);
+               } else {
+                       pushNewValue(fInterpreter.getTypeEngine().getCharacterType(
+                                       fInterpreter.getTypeEngine().getTypeSize(TypeUtils.BASIC_TYPE_WCHAR_T)), fValue);
+               }
+       }
+
+       /**
+        * Show a char value as a string
+        * 
+        * @return string version of a char
+        */
+       @Override
+       public String toString() {
+               if (fValue < 65536)
+                       return "" + ((char) fValue); //$NON-NLS-1$
+               char[] surrogate = { (char)(fValue >> 16), (char)(fValue & 0xffff) };
+               return new String(surrogate);
+       }
+
+       /**
+        * Convert string value of form 'X' to char X.  This may be either a single
+        * character (char or wchar_t) or a multi-character constant, which is treated
+        * as an integer.
+        * 
+        * @param value
+        *            - string of form 'X'
+        * @throws NumberFormatException
+        */
+       private void parseCharValue(String value) throws NumberFormatException {
+               if (value.startsWith("L")) { //$NON-NLS-1$
+                       isWide = true;
+                       value = value.substring(1);
+               }
+               if (value.length() < 3 || value.charAt(0) != '\'' || !value.endsWith("'")) //$NON-NLS-1$
+                       throw new NumberFormatException();
+
+               value = value.substring(1, value.length() - 1);
+
+               if (value.startsWith("\\u")) { //$NON-NLS-1$
+                       // hex representation
+                       if (value.length() < 3)
+                               throw new NumberFormatException();
+
+                       fValue = Long.parseLong(value.substring(2), 16);
+                       return;
+               }
+
+               // escape character
+               if (value.startsWith("\\")) { //$NON-NLS-1$
+                       if (value.length() < 2)
+                               throw new NumberFormatException();
+
+                       if (value.charAt(1) >= '0' && value.charAt(1) <= '7') {
+                               // octal representation
+                               if (value.length() > 4)
+                                       throw new NumberFormatException();
+
+                               fValue = Long.parseLong(value.substring(1), 8);
+                               return;
+                       }
+
+                       if (value.length() > 2)
+                               throw new NumberFormatException();
+
+                       switch (value.charAt(1)) {
+                       case 'n':
+                               fValue = '\n'; break;
+                       case 't':
+                               fValue = '\t'; break;
+                       case 'v':
+                               fValue = VERTICAL_TAB; break;
+                       case 'b':
+                               fValue = '\b'; break;
+                       case 'r':
+                               fValue = '\r'; break;
+                       case 'f':
+                               fValue = '\f'; break;
+                       case 'a':
+                               fValue = BELL; break;
+                       case '\\':
+                               fValue = '\\'; break;
+                       case '?':
+                               fValue = '?'; break;
+                       case '\'':
+                               fValue = '\''; break;
+                       case '"':
+                               fValue = '"'; break;
+                       default:
+                               fValue = value.charAt(1); break;
+                       }
+                       return;
+               }
+
+               multiChar = (value.length() > 1);
+               
+               fValue = 0;
+               for (int i = 0; i < value.length(); i++) {
+                       fValue = (fValue << 8) + value.charAt(i);
+               }
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushDouble.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushDouble.java
new file mode 100644 (file)
index 0000000..161481e
--- /dev/null
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Push a double value on the instruction stack
+ */
+public class PushDouble extends SimpleInstruction {
+
+       private double fValue;
+       private boolean isLong;
+       
+       /**
+        * Constructor for pushing a double value on the stack
+        * 
+        * @param value
+        *            - double value
+        */
+       public PushDouble(double value) {
+               fValue = value;
+       }
+
+       /**
+        * Constructor for pushing a double value on the stack
+        * 
+        * @param value
+        *            - string version of a double
+        * @throws NumberFormatException
+        */
+       public PushDouble(String value) throws NumberFormatException {
+               if (value.toLowerCase().endsWith("l")) { //$NON-NLS-1$
+                       isLong = true;
+                       value = value.substring(0, value.length() - 1);
+               }
+               fValue = Double.valueOf(value).doubleValue();
+       }
+
+       /**
+        * Execute pushing a double value on the stack
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() {
+               int size;
+               if (isLong) {
+                       size = fInterpreter.getTypeEngine().getTypeSize(TypeUtils.BASIC_TYPE_LONG_DOUBLE);
+                       pushNewValue(fInterpreter.getTypeEngine().getBasicType(ICPPBasicType.t_double, ICPPBasicType.IS_LONG, size), fValue);
+               }
+               else {
+                       size = fInterpreter.getTypeEngine().getTypeSize(TypeUtils.BASIC_TYPE_DOUBLE);
+                       pushNewValue(fInterpreter.getTypeEngine().getBasicType(ICPPBasicType.t_double, 0, size), fValue);
+               }
+                       
+       }
+
+       /**
+        * Show a double value as a string
+        * 
+        * @return string version of a double
+        */
+       @Override
+       public String toString() {
+               return Double.toString(fValue);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushFloat.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushFloat.java
new file mode 100644 (file)
index 0000000..8e441f3
--- /dev/null
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Push a float on the instruction stack
+ */
+public class PushFloat extends SimpleInstruction {
+
+       private float fValue;
+
+       /**
+        * Constructor for pushing a float on the stack
+        * 
+        * @param value
+        *            - float value
+        */
+       public PushFloat(float value) {
+               fValue = value;
+       }
+
+       /**
+        * Constructor for pushing a float on the stack
+        * 
+        * @param value
+        *            - string version of a float
+        * @throws NumberFormatException
+        */
+       public PushFloat(String value) throws NumberFormatException {
+               fValue = Float.valueOf(value).floatValue();
+       }
+
+       /**
+        * Execute pushing a float on the stack
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() {
+               pushNewValue(fInterpreter.getTypeEngine().getFloatTypeOfSize(4), fValue);
+       }
+
+       /**
+        * Show a float value as a string
+        * 
+        * @return string version of a float
+        */
+       @Override
+       public String toString() {
+               return Float.toString(fValue);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushLongOrBigInteger.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushLongOrBigInteger.java
new file mode 100644 (file)
index 0000000..494f210
--- /dev/null
@@ -0,0 +1,347 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Push a long on the instruction stack
+ */
+public class PushLongOrBigInteger extends SimpleInstruction {
+
+       // if true, suffix had 'u'
+       private boolean isUnsigned;
+       // if true, suffix had 'l' (but not 'll')
+       private boolean isLong;
+       // if true, suffix had 'll' (but not 'l')
+       private boolean isLongLong;
+       
+       // if true, the original number was a hex or octal string
+       private boolean isHexOrOctal;
+       
+       // if not null, a big integer 
+       private BigInteger fBigInteger;
+       // otherwise, this is the value
+       private long fLong;
+       private IType type;
+
+       /**
+        * Constructor for pushing a long on the stack
+        * 
+        * @param value
+        *            - long value
+        */
+       public PushLongOrBigInteger(long value) {
+               isLong = true;
+               fLong = value;
+       }
+
+       /**
+        * Constructor for pushing a long on the stack
+        * 
+        * @param value
+        *            - string version of a long
+        * @throws NumberFormatException
+        */
+       public PushLongOrBigInteger(String value) throws NumberFormatException {
+               parseLongOrBigInteger(value);
+       }
+
+       /**
+        */
+       public long getLong() {
+               return fLong;
+       }
+       
+       /**
+        * Execute pushing a long on the stack
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() {
+               Number number = fBigInteger;
+               if (number == null)
+                       number = fLong;
+               
+               // TODO: Handle 8-byte long and >8-byte long long
+
+               int intSize  = fInterpreter.getTypeEngine().getTypeSize(TypeUtils.BASIC_TYPE_INT);
+               int longSize = fInterpreter.getTypeEngine().getTypeSize(TypeUtils.BASIC_TYPE_LONG);
+               int longLongSize = fInterpreter.getTypeEngine().getTypeSize(TypeUtils.BASIC_TYPE_LONG_LONG);
+
+               // promote constant type based on the size of C/C++ int, long, and long long types.
+               // this cannot be done at parse time because the type engine is not known then
+               correctIntegerType(intSize * 8, longSize * 8, longLongSize * 8);
+
+               if (type == null) {
+                       int flags = isLongLong ? ICPPBasicType.IS_LONG_LONG : isLong ?  ICPPBasicType.IS_LONG : 0;
+                       
+                       if (isUnsigned)
+                               flags |= ICPPBasicType.IS_UNSIGNED;
+                       else
+                               flags |= ICPPBasicType.IS_SIGNED;
+       
+                       int size;
+                       if (isLongLong)
+                               size = longLongSize;
+                       else if (isLong)
+                               size = longSize;
+                       else
+                               size = intSize;
+                       
+                       type = fInterpreter.getTypeEngine().getBasicType(ICPPBasicType.t_int, flags, size);
+               }
+               
+               pushNewValue(type, number);
+       }
+
+       /**
+        *      Fix type of constant based on C++ promotion rules, which depend on the size of
+        *  int, long, and long long types.
+        *
+        * @param intBitSize
+        * @param longBitSize
+        * @param longLongBitSize
+        */
+       private void correctIntegerType(int intBitSize, int longBitSize, int longLongBitSize) {
+               if (    fBigInteger == null
+                               // check if it fits in signed long (but maybe not an unsigned int)
+                       && (   (fLong >= 0 && (fLong >> (intBitSize - 1)) == 0)
+                               || (fLong <  0 && (fLong >> (intBitSize - 1)) < -1)))
+                               return;
+
+               // at execute() time, isUnsigned means explicit unsigned, isLong means explicit long,
+               // and isLongLong means explicit long long
+               if (fBigInteger == null) {
+                       // it fits in a 64-bit signed Java long
+                       if (isUnsigned) {
+                               // explicit unsigned decimal, hex, or octal constant
+                               if (isLong) {
+                                       // explicit unsigned long may change to unsigned long long
+                                       if ((fLong >> longBitSize) > 0) {
+                                               isLong = false;
+                                               isLongLong = true;
+                                       }
+                               } else if (!isLongLong) {
+                                       // not declared long long - may be int, long, or long long
+                                       if ((fLong >> (intBitSize - 1)) <= 1) {
+                                               // fits in an unsigned int
+                                       } else if ((fLong >> (longBitSize - 1)) <= 1) {
+                                               // fits in an unsigned long
+                                               isLong = true;
+                                       } else {
+                                               // fits in an unsigned longLong
+                                               isLongLong = true;
+                                       }
+                               }
+                       } else {
+                               // signed decimal, hex, or octal constant
+                               if (!isHexOrOctal) {
+                                       // decimal constant
+                                       if (!isLong && !isLongLong){
+                                               // signed decimal constant, not declared long or long long
+                                               if (   (fLong >= 0 && (fLong >> (longBitSize - 1)) == 0)
+                                                       || (fLong <  0 && (fLong >> (longBitSize - 1)) < -1)) {
+                                                       // fits in signed long
+                                                       isLong = true;
+                                               } else {
+                                                       // fits in signed long long
+                                                       isLongLong = true;
+                                               }
+                                       } else if (isLong) {
+                                               // explicit long may change to long long
+                                               if (!(   (fLong >= 0 && (fLong >> (longLongBitSize - 1)) == 0)
+                                                         || (fLong <  0 && (fLong >> (longLongBitSize - 1)) < -1))) {
+                                                       isLong = false;
+                                                       isLongLong = true;
+                                               }
+                                       }
+                               } else {
+                                       // hex or octal constant
+                                       if (!isLong && !isLongLong){
+                                               // signed hex or octal constant, not declared long or long long
+                                               // may be int, unsigned int, long, unsigned long, long long, or unsigned long long
+                                               if (fLong >> (intBitSize - 1) == 1) {
+                                                       // fits in unsigned int
+                                                       isUnsigned = true;
+                                               } else if (   (fLong >= 0 && (fLong >> (longBitSize - 1)) == 0)
+                                                                  || (fLong <  0 && (fLong >> (longBitSize - 1)) < -1)) {
+                                                       // fits in signed long
+                                                       isLong = true;
+                                               } else if (fLong >> (longBitSize - 1) == 1) {
+                                                       // fits in unsigned long
+                                                       isLong = true;
+                                                       isUnsigned = true; 
+                                               } else if (   (fLong >= 0 && (fLong >> (longLongBitSize - 1)) == 0)
+                                                                  || (fLong <  0 && (fLong >> (longLongBitSize - 1)) < -1)) {
+                                                       // fits in signed long long
+                                                       isLongLong = true;
+                                               } else {
+                                                       // fits in unsigned long long
+                                                       isLongLong = true;
+                                                       isUnsigned = true;
+                                               }
+                                       } else if (isLong) {
+                                               // explicit long hex or octal may change to unsigned long, long long, or unsigned long long
+                                               if (   (fLong >= 0 && (fLong >> (longBitSize - 1)) == 0)
+                                                       || (fLong <  0 && (fLong >> (longBitSize - 1)) < -1)) {
+                                                       // fits in signed long
+                                               } else if (fLong >> (longBitSize - 1) == 1) {
+                                                       // fits in unsigned long
+                                                       isUnsigned = true; 
+                                               } else if (   (fLong >= 0 && (fLong >> (longLongBitSize - 1)) == 0)
+                                                                  || (fLong <  0 && (fLong >> (longLongBitSize - 1)) < -1)) {
+                                                       // fits in signed long long
+                                                       isLong = false;
+                                                       isLongLong = true;
+                                               } else {
+                                                       // fits in unsigned long long
+                                                       isLong = false;
+                                                       isLongLong = true;
+                                                       isUnsigned = true;
+                                               }
+                                       } else {
+                                               // explicit long long may change to unsigned long long
+                                               if (fLong >> (longLongBitSize - 1) > 0)
+                                                       isUnsigned = true;
+                                       }
+                               }
+                       }
+               } else {
+                       // BigInteger, which does not fit in a Java long
+                       isLongLong = true;
+                       isLong = false;
+                       if (!isUnsigned) {
+                               // signed decimal, hex, or octal long long constant
+                               if (isHexOrOctal) {
+                                       // for hex or octal constant, long long may change to unsigned long long
+                                       if (fBigInteger.bitLength() > (longLongBitSize - 1))
+                                               isUnsigned = true;
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Show a long or BigInteger value as a string
+        * 
+        * @return string version of a long or BigInteger
+        */
+       @Override
+       public String toString() {
+               if (isLong)
+                       return Long.toString(fLong);
+               else
+                       return fBigInteger.toString();
+       }
+
+       /**
+        * Convert a string to a long or BigInteger
+        * 
+        * @param value
+        *            - string version of a long
+        * @throws NumberFormatException
+        */
+       public void parseLongOrBigInteger(String value) throws NumberFormatException {
+               isUnsigned = false;
+               isHexOrOctal = false;
+
+               String val = value.toLowerCase();
+               int length = value.length();
+
+               if (val.endsWith("ull") || val.endsWith("llu")) { //$NON-NLS-1$ //$NON-NLS-2$
+                       isUnsigned = true;
+                       isLongLong = true;
+                       isLong = false;
+                       val = val.substring(0, val.length() - 3);
+                       length -= 3;
+               } else if (val.endsWith("ll")) { //$NON-NLS-1$
+                       isLong = false;
+                       isLongLong = true;
+                       val = val.substring(0, val.length() - 2);
+                       length -= 2;
+               } else if (val.endsWith("ul") || val.endsWith("lu")) { //$NON-NLS-1$ //$NON-NLS-2$
+                       isUnsigned = true;
+                       isLong = true;
+                       val = val.substring(0, val.length() - 2);
+                       length -= 2;
+               } else if (val.endsWith("l")) { //$NON-NLS-1$
+                       isLong = true;
+                       val = val.substring(0, val.length() - 1);
+                       length -= 1;
+               } else if (val.endsWith("u")) { //$NON-NLS-1$
+                       isUnsigned = true;
+                       val = val.substring(0, val.length() - 1);
+                       length -= 1;
+               }
+
+               // if conversion to BigInteger fails, the string is invalid
+               // if after BigInteger conversion, Long conversion fails, the value is
+               // too large or small
+               if (val.startsWith("0x")) { //$NON-NLS-1$
+                       isHexOrOctal = true;
+                       try {
+                               fLong = Long.valueOf(val.substring(2), 16);
+                       } catch (NumberFormatException nfe) {
+                               fBigInteger = new BigInteger(val.substring(2), 16);
+                               fBigInteger.and(Instruction.Mask8Bytes);
+                               return;
+                       }
+                       length -= 2;
+               } else if (length > 1 && val.startsWith("0")) { //$NON-NLS-1$
+                       isHexOrOctal = true;
+
+                       try {
+                               fLong = Long.valueOf(val.substring(1), 8);
+                       } catch (NumberFormatException nfe) {
+                               fBigInteger = new BigInteger(val.substring(1), 8);
+                               fBigInteger.and(Instruction.Mask8Bytes);
+                               return;
+                       }
+                       length -= 1;
+               } else {
+
+                       try {
+                               fLong = Long.valueOf(val);
+                       } catch (NumberFormatException nfe) {
+                               fBigInteger = new BigInteger(val);
+                               fBigInteger.and(Instruction.Mask8Bytes);
+                               return;
+                       }
+               }
+
+               if (length == 0) {
+                       fLong = 0;
+                       return;
+               }
+
+               if (isUnsigned) {
+                       if (fBigInteger != null) {
+                               if (fBigInteger.bitLength() < 64) {
+                                       // unsigned will fit in a Java long
+                                       fLong = fBigInteger.longValue();
+                                       fBigInteger = null;
+                                       return;
+                               }
+                               // keep it a BigInteger
+                               // TODO: Allow bigger than 8 bytes
+                               fBigInteger.and(Instruction.Mask8Bytes);
+                       }
+               }
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushString.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/PushString.java
new file mode 100644 (file)
index 0000000..c5d0a33
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Push a string on the instruction stack
+ */
+public class PushString extends SimpleInstruction {
+
+       private String fValue;
+       private boolean isWide;
+       private IType stringType;
+
+       /**
+        * Constructor for pushing a string on the stack
+        * 
+        * @param value
+        *            - string value in format "..." or L"..."
+        */
+       public PushString(String value) {
+               if (value.startsWith("L")) { //$NON-NLS-1$
+                       isWide = true;
+                       value = value.substring(1);
+               }
+               
+               fValue = value.substring(1, value.length() - 1);
+       }
+
+       /**
+        * Execute pushing a string on the stack
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() {
+               if (stringType == null) {
+                       int size = fInterpreter.getTypeEngine().getTypeSize(isWide ? TypeUtils.BASIC_TYPE_WCHAR_T : TypeUtils.BASIC_TYPE_CHAR);
+                       IType charType = fInterpreter.getTypeEngine().getBasicType(ICPPBasicType.t_char, 0, size);
+                       stringType = fInterpreter.getTypeEngine().getCharArrayType(charType, fValue.length() + 1);
+               }
+               pushNewValue(stringType, fValue);
+       }
+
+       /**
+        * Show a string value
+        * 
+        * @return string
+        */
+       @Override
+       public String toString() {
+               return fValue;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/SimpleInstruction.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/SimpleInstruction.java
new file mode 100644 (file)
index 0000000..aa08a80
--- /dev/null
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+public abstract class SimpleInstruction extends Instruction {
+
+       /**
+        * Constructor for a simple instruction
+        */
+       protected SimpleInstruction() {
+               super();
+       }
+
+       /**
+        * Get simple instruction size
+        * 
+        * @return 1
+        */
+       @Override
+       public int getSize() {
+               return 1;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/UnaryLogicalOperator.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/UnaryLogicalOperator.java
new file mode 100644 (file)
index 0000000..1552729
--- /dev/null
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Unary logical operator, such as "!"
+ */
+public abstract class UnaryLogicalOperator extends CompoundInstruction {
+
+       /**
+        * Constructor for a unary logical operator, such as "!"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public UnaryLogicalOperator(int start) {
+               super(start);
+       }
+
+       /**
+        * Constructor for a unary logical operator, such as "!"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       public UnaryLogicalOperator(int resultId, boolean isAssignmentOperator, int start) {
+               super(start);
+       }
+
+       /**
+        * Resolve a unary logical expression
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() throws CoreException {
+               OperandValue operand = popValue();
+
+               operand = convertForPromotion(operand);
+
+               // change chars/shorts to int, etc.
+               int resultType = getJavaBinaryPromotionType(operand, operand);
+               IType type = fInterpreter.getTypeEngine().getBooleanType(1);
+               
+               switch (resultType) {
+               case T_String:
+                       pushNewValue(type, getStringResult(GetValue.getStringValue(operand)));
+                       break;
+               case T_double:
+                       pushNewValue(type, getDoubleResult(GetValue.getDoubleValue(operand)));
+                       break;
+               case T_float:
+                       pushNewValue(type, getFloatResult(GetValue.getFloatValue(operand)));
+                       break;
+               case T_long:
+                       pushNewValue(type, getLongResult(GetValue.getLongValue(operand)));
+                       break;
+               case T_int:
+                       pushNewValue(type, getIntResult(GetValue.getIntValue(operand)));
+                       break;
+               case T_boolean:
+                       pushNewValue(type, getBooleanResult(GetValue.getBooleanValue(operand)));
+                       break;
+               case T_BigInt:
+                       pushNewValue(type, getBigIntegerResult(GetValue.getBigIntegerValue(operand)));
+                       break;
+               default:
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.UnhandledTypeCode + resultType);
+
+               }
+       }
+
+       /**
+        * Get boolean result of applying a unary logical operation to an int
+        * 
+        * @param operand
+        *            - int operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract boolean getIntResult(int operand) throws CoreException;
+
+       /**
+        * Get boolean result of applying a unary logical operation to a long
+        * 
+        * @param operand
+        *            - long operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract boolean getLongResult(long operand) throws CoreException;
+
+       /**
+        * Get boolean result of applying a unary logical operation to a BigInteger
+        * 
+        * @param operand
+        *            - BigInteger operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract boolean getBigIntegerResult(BigInteger operand) throws CoreException;
+
+       /**
+        * Get boolean result of applying a unary logical operation to a float
+        * 
+        * @param operand
+        *            - float operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract boolean getFloatResult(float operand);
+
+       /**
+        * Get boolean result of applying a unary logical operation to a double
+        * 
+        * @param operand
+        *            - double operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract boolean getDoubleResult(double operand);
+
+       /**
+        * Get boolean result of applying a unary logical operation to a boolean
+        * 
+        * @param operand
+        *            - boolean operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract boolean getBooleanResult(boolean operand);
+
+       /**
+        * Get boolean result of applying a unary logical operation to a string
+        * 
+        * @param operand
+        *            - string operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract boolean getStringResult(String operand) throws CoreException;
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/UnaryOperator.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/UnaryOperator.java
new file mode 100644 (file)
index 0000000..ebe5ba0
--- /dev/null
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.core.runtime.CoreException;
+
+/*
+ * Unary arithmetic operator, such as "~"
+ */
+public abstract class UnaryOperator extends CompoundInstruction {
+
+       /**
+        * Constructor for a unary arithmetic operator, such as "~"
+        * 
+        * @param start
+        *            - instruction start
+        */
+       public UnaryOperator(int start) {
+               super(start);
+       }
+
+       /**
+        * Constructor for a unary arithmetic operator, such as "~"
+        * 
+        * @param resultId
+        *            - for assignment, variable ID of the result
+        * @param isAssignmentOperator
+        *            - whether the result is assigned
+        * @param start
+        *            - instruction start
+        */
+       public UnaryOperator(int resultId, boolean isAssignmentOperator, int start) {
+               super(start);
+       }
+
+       /**
+        * Resolve a unary arithmetic expression
+        * 
+        * @throws CoreException
+        */
+       @Override
+       public void execute() throws CoreException {
+               OperandValue operand = popValue();
+
+               operand = convertForPromotion(operand);
+
+               // change chars/shorts to int, etc.
+               
+               int resultType = getJavaBinaryPromotionType(operand, operand);
+               IType type = getBinaryPromotionType(operand, operand);
+               
+               // non-logical operations on booleans are int results
+               if ((type instanceof ICPPBasicType) && ((ICPPBasicType) type).getBaseType() == ICPPBasicType.t_bool) {
+                       type = fInterpreter.getTypeEngine().getIntegerTypeFor(TypeUtils.BASIC_TYPE_INT, true);
+               }
+               
+               switch (resultType) {
+               case T_String:
+                       pushNewValue(type, getStringResult(GetValue.getStringValue(operand)));
+                       break;
+               case T_double:
+                       pushNewValue(type, getDoubleResult(GetValue.getDoubleValue(operand)));
+                       break;
+               case T_float:
+                       pushNewValue(type, getFloatResult(GetValue.getFloatValue(operand)));
+                       break;
+               case T_long:
+                       pushNewValue(type, getLongResult(GetValue.getLongValue(operand)));
+                       break;
+               case T_int:
+                       pushNewValue(type, getIntResult(GetValue.getIntValue(operand)));
+                       break;
+               case T_boolean:
+                       pushNewValue(type, getBooleanResult(GetValue.getBooleanValue(operand)));
+                       break;
+               default:
+                       throw EDCDebugger.newCoreException(ASTEvalMessages.UnhandledTypeCode + resultType);
+               }
+       }
+
+       /**
+        * Get int result of applying a unary operation to an int
+        * 
+        * @param operand
+        *            - int operand
+        * @return int result of the operation if possible, or an operation-specific
+        *         default
+        * @throws CoreException
+        */
+       protected abstract int getIntResult(int operand) throws CoreException;
+
+       /**
+        * Get long result of applying a unary operation to a long
+        * 
+        * @param operand
+        *            - long operand
+        * @return long result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract long getLongResult(long operand) throws CoreException;
+
+       /**
+        * Get BigInteger result of applying a unary operation to a BigInteger
+        * 
+        * @param operand
+        *            - long operand
+        * @param length
+        *            - length in bytes of the result
+        * @return long result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract BigInteger getBigIntegerResult(BigInteger operand, int length) throws CoreException;
+
+       /**
+        * Get float result of applying a unary operation to a float
+        * 
+        * @param operand
+        *            - float operand
+        * @return float result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract float getFloatResult(float operand);
+
+       /**
+        * Get double result of applying a unary operation to a double
+        * 
+        * @param operand
+        *            - double operand
+        * @return double result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract double getDoubleResult(double operand);
+
+       /**
+        * Get boolean result of applying a unary operation to a boolean
+        * 
+        * @param operand
+        *            - boolean operand
+        * @return boolean result of the operation if possible, or an
+        *         operation-specific default
+        */
+       protected abstract boolean getBooleanResult(boolean operand);
+
+       /**
+        * Get string result of applying a unary operation to a string
+        * 
+        * @param operand
+        *            - string operand
+        * @return string result of the operation if possible, or an
+        *         operation-specific default
+        * @throws CoreException
+        */
+       protected abstract String getStringResult(String operand) throws CoreException;
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/VariableWithValue.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/VariableWithValue.java
new file mode 100644 (file)
index 0000000..61fe7f4
--- /dev/null
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+
+
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
+import org.eclipse.cdt.debug.edc.internal.symbols.InvalidVariableLocation;
+import org.eclipse.cdt.debug.edc.services.IEDCModuleDMContext;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.core.runtime.CoreException;
+
+public class VariableWithValue extends OperandValue {
+       final IVariable variable;
+       private final EDCServicesTracker servicesTracker;
+       private final StackFrameDMC frame;
+
+       public VariableWithValue(EDCServicesTracker servicesTracker, StackFrameDMC frame, IVariable variable) {
+               this(servicesTracker, frame, variable, false);
+       }
+
+       public VariableWithValue(EDCServicesTracker servicesTracker, StackFrameDMC frame, IVariable variable,
+                       boolean isBitField) {
+               super(variable.getType(), isBitField);
+               this.servicesTracker = servicesTracker;
+               this.frame = frame;
+               this.variable = variable;
+       }
+       
+       public VariableWithValue(EDCServicesTracker servicesTracker, StackFrameDMC frame, IVariable variable, IType otherType) {
+               super(otherType, false);
+               this.servicesTracker = servicesTracker;
+               this.frame = frame;
+               this.variable = variable;
+       }
+       /**
+        * @return the servicesTracker
+        */
+       public EDCServicesTracker getServicesTracker() {
+               return servicesTracker;
+       }
+       /**
+        * @return the frame
+        */
+       public StackFrameDMC getFrame() {
+               return frame;
+       }
+       public IVariable getVariable() {
+               return variable;
+       }
+
+       public Number getValue() throws CoreException {
+               if (value == null) {
+                       IVariableLocation location = getValueLocation();
+                       IType varType = type;
+                       if (varType != null) {
+                               value = getValueByType(varType, location);
+                       } else {
+                               assert false;
+                       }
+               }
+               return value;
+       }
+
+       public IVariableLocation getValueLocation() {
+               if (valueLocation == null) {
+                       ILocationProvider provider = variable.getLocationProvider();
+                       if (provider == null) {
+                               // ERROR
+                               valueLocation = new InvalidVariableLocation(ASTEvalMessages.VariableWithValue_CannotLocateVariable);
+                               return valueLocation;
+                       }
+                       IEDCModuleDMContext module = frame.getModule();
+                       valueLocation = provider.getLocation(servicesTracker, frame, module.toLinkAddress(frame.getInstructionPtrAddress()),
+                                       TypeUtils.isConstType(variable.getType()));
+                       if (valueLocation == null) {
+                               // unhandled
+                               valueLocation = new InvalidVariableLocation(ASTEvalMessages.VariableWithValue_CannotLocateVariable);
+                       }
+               }
+               return valueLocation;
+       }
+       
+       public OperandValue copyWithType(IType otherType) {
+               OperandValue value = new VariableWithValue(servicesTracker, frame, variable, otherType);
+               value.stringValue = this.stringValue;
+               value.valueLocation = this.valueLocation;
+               return value;
+       }
+       
+       public void setType(IType type) {
+               this.type = type;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/formatter/FormatExtensionManager.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/formatter/FormatExtensionManager.java
new file mode 100644 (file)
index 0000000..f18648f
--- /dev/null
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.formatter;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.cdt.debug.edc.formatter.ITypeContentProvider;
+import org.eclipse.cdt.debug.edc.formatter.IVariableFormatProvider;
+import org.eclipse.cdt.debug.edc.formatter.IVariableValueConverter;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+
+/**
+ * Manages format extensions
+ */
+public class FormatExtensionManager implements IVariableFormatManager {
+       
+       // Preferences
+       public static final String VARIABLE_FORMATS_ENABLED = "variable_formats_enabled";
+       public static final boolean VARIABLE_FORMATS_ENABLED_DEFAULT = true;
+
+       /**
+        * A chooser implementation that always defers to any formatter that is not one of the default formatters
+        */
+       private static final class DefaultFormatProviderChooser implements IVariableFormatProviderChooser {     
+               private static final String DEFAULT_COMPOSITE = 
+                       "org.eclipse.cdt.debug.edc.formatter.default.composite"; //$NON-NLS-1$
+               private static final String DEFAULT_ARRAY = 
+                       "org.eclipse.cdt.debug.edc.formatter.default.array"; //$NON-NLS-1$
+               
+               public String chooseDetailValueConverter(IType type, Collection<String> ids) {
+                       return chooseAnyBeforeDefault(ids);
+               }
+
+               public String chooseTypeContentProvider(IType type, Collection<String> ids) {
+                       return chooseAnyBeforeDefault(ids);
+               }
+
+               public String chooseVariableValueConverter(IType type, Collection<String> ids) {
+                       return chooseAnyBeforeDefault(ids);
+               }
+
+               private String chooseAnyBeforeDefault(Collection<String> ids) {
+                       if (ids.size() > 1) {
+                               for (String id : ids) {
+                                       if (!id.equals(DEFAULT_COMPOSITE) && !id.equals(DEFAULT_ARRAY))
+                                               return id;
+                               }
+                       }
+                       else if (ids.size() == 1)
+                               return ids.iterator().next();
+                       
+                       return null;
+               }
+       }
+       
+       public class FormatProviderExtension {
+               private String label;
+               private IVariableFormatProvider formatProvider;
+
+               public FormatProviderExtension(String label, IVariableFormatProvider formatProvider) {
+                       this.label = label;
+                       this.formatProvider = formatProvider;
+               }
+
+               public String getLabel() {
+                       return label;
+               }
+
+               public IVariableFormatProvider getFormatProvider() {
+                       return formatProvider;
+               }
+       }
+
+       private static IVariableFormatManager instance = 
+               new FormatExtensionManager(new DefaultFormatProviderChooser());
+       
+       private Map<String, FormatProviderExtension> formatProviders;
+       private IVariableFormatProviderChooser chooser;
+       private boolean enabled = FormatExtensionManager.VARIABLE_FORMATS_ENABLED_DEFAULT;
+
+       public static IVariableFormatManager instance() {
+               return instance;
+       }
+       
+       private FormatExtensionManager(IVariableFormatProviderChooser chooser) {
+               readProviders();
+               setFormatProviderChooser(chooser);
+               IEclipsePreferences scope = InstanceScope.INSTANCE.getNode(EDCDebugger.PLUGIN_ID);
+               enabled = scope.getBoolean(VARIABLE_FORMATS_ENABLED, FormatExtensionManager.VARIABLE_FORMATS_ENABLED_DEFAULT);
+       }
+
+       private void readProviders() {
+               if (formatProviders != null)
+                       return;
+               IConfigurationElement[] elements = 
+                       Platform.getExtensionRegistry().getConfigurationElementsFor(EDCDebugger.PLUGIN_ID + ".variableFormatProvider"); //$NON-NLS-1$
+               for (IConfigurationElement element : elements) {
+                       try {
+                               String id = element.getAttribute("id"); //$NON-NLS-1$
+                               String label = element.getAttribute("label"); //$NON-NLS-1$
+                               IVariableFormatProvider formatProvider = 
+                                       (IVariableFormatProvider) element.createExecutableExtension("class"); //$NON-NLS-1$
+                               if (formatProviders == null)
+                                       formatProviders = new HashMap<String, FormatProviderExtension>();
+                               formatProviders.put(id, new FormatProviderExtension(label, formatProvider));
+                       } catch (Exception e) {
+                               EDCDebugger.getMessageLogger().logError("Could not create formatting extension", e);
+                       }
+               }
+       }
+       
+       private interface Getter <T> {
+               T get(IVariableFormatProvider fp, IType type);
+               String choose(IType type, Collection<String> ids);
+       }
+       
+       private<T> T getProvider(IType type, Getter<T> getter) {
+               if (!enabled)
+                       return null;
+               Map<String, T> providers = new HashMap<String, T>();
+               for (Entry<String, FormatProviderExtension> entry : formatProviders.entrySet()) {
+                       IVariableFormatProvider fp = entry.getValue().getFormatProvider();
+                       T t = getter.get(fp, type);
+                       if (t != null)
+                               providers.put(entry.getKey(), t);
+               }
+               String id = getter.choose(type, providers.keySet());
+               return providers.get(id);
+       }
+       
+       
+       public ITypeContentProvider getTypeContentProvider(IType type) {
+               return getProvider(type, new Getter<ITypeContentProvider>() {
+                       public ITypeContentProvider get(IVariableFormatProvider fp, IType type) {
+                               return fp.getTypeContentProvider(type);
+                       }
+                       public String choose(IType type, Collection<String> ids) {
+                               return chooser.chooseTypeContentProvider(type, ids);
+                       }
+               });
+       }
+       
+       public IVariableValueConverter getVariableValueConverter(IType type) {
+               return getProvider(type, new Getter<IVariableValueConverter>() {
+                       public IVariableValueConverter get(IVariableFormatProvider fp, IType type) {
+                               return fp.getVariableValueConverter(type);
+                       }
+                       public String choose(IType type, Collection<String> ids) {
+                               return chooser.chooseVariableValueConverter(type, ids);
+                       }
+               });
+       }
+       
+       public IVariableValueConverter getDetailValueConverter(IType type) {
+               return getProvider(type, new Getter<IVariableValueConverter>() {
+                       public IVariableValueConverter get(IVariableFormatProvider fp, IType type) {
+                               return fp.getDetailValueConverter(type);
+                       }
+                       public String choose(IType type, Collection<String> ids) {
+                               return chooser.chooseDetailValueConverter(type, ids);
+                       }
+               });
+       }
+
+       public void setFormatProviderChooser(IVariableFormatProviderChooser chooser) {
+               this.chooser = chooser;
+       }
+
+       public String[] getVariableFormatProviderIds() {
+               Set<String> keySet = formatProviders.keySet();
+               return keySet.toArray(new String[keySet.size()]);
+       }
+       
+       public String getFormatProviderLabel(String id) {
+               return formatProviders.get(id).getLabel();
+       }
+       
+       public void setEnabled(boolean enabled) {
+               this.enabled = enabled;
+       }
+
+       public boolean isEnabled() {
+               return enabled;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/formatter/IVariableFormatManager.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/formatter/IVariableFormatManager.java
new file mode 100644 (file)
index 0000000..2f6640c
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.formatter;
+
+import org.eclipse.cdt.debug.edc.formatter.IVariableFormatProvider;
+
+/**
+ * An interface to the variable format provider manager singleton
+ */
+public interface IVariableFormatManager extends IVariableFormatProvider {
+
+       void setFormatProviderChooser(IVariableFormatProviderChooser chooser);
+       
+       String[] getVariableFormatProviderIds();
+       
+       String getFormatProviderLabel(String id);
+       
+       void setEnabled(boolean enabled);
+
+       boolean isEnabled();
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/formatter/IVariableFormatProviderChooser.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/formatter/IVariableFormatProviderChooser.java
new file mode 100644 (file)
index 0000000..9047349
--- /dev/null
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.formatter;
+
+import java.util.Collection;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+/**
+ * An object that allows choosing between format providers
+ */
+public interface IVariableFormatProviderChooser {
+       
+       String chooseTypeContentProvider(IType type, Collection<String> ids);
+
+       String chooseVariableValueConverter(IType type, Collection<String> ids);
+
+       String chooseDetailValueConverter(IType type, Collection<String> ids);
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/CSourceLookup.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/CSourceLookup.java
new file mode 100644 (file)
index 0000000..4973671
--- /dev/null
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.launch;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.service.ISourceLookup;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.osgi.framework.BundleContext;
+
+/**
+ * ISourceLookup service implementation based on the CDT CSourceLookupDirector.
+ * Supports multiple source lookup directors.
+ */
+public class CSourceLookup extends AbstractDsfService implements ISourceLookup {
+
+       private final Map<ISourceLookupDMContext, List<CSourceLookupDirector>> directors = new HashMap<ISourceLookupDMContext, List<CSourceLookupDirector>>();
+
+       public CSourceLookup(DsfSession session) {
+               super(session);
+       }
+
+       @Override
+       protected BundleContext getBundleContext() {
+               return EDCDebugger.getBundleContext();
+       }
+
+       public void addSourceLookupDirector(ISourceLookupDMContext ctx, CSourceLookupDirector director) {
+               List<CSourceLookupDirector> directorsInContext = directors.get(ctx);
+               if (directorsInContext == null)
+                       directorsInContext = new ArrayList<CSourceLookupDirector>();
+               directorsInContext.add(director);
+               directors.put(ctx, directorsInContext);
+       }
+
+       public CSourceLookupDirector[] getSourceLookupDirectors(ISourceLookupDMContext ctx) {
+               List<CSourceLookupDirector> directorList = directors.get(ctx);
+               return directorList.toArray(new CSourceLookupDirector[directorList.size()]);
+       }
+
+       @Override
+       public void initialize(final RequestMonitor requestMonitor) {
+               super.initialize(new RequestMonitor(getExecutor(), requestMonitor) {
+                       @Override
+                       protected void handleSuccess() {
+                               doInitialize(requestMonitor);
+                       }
+               });
+       }
+
+       private void doInitialize(final RequestMonitor requestMonitor) {
+               // Register this service
+               register(new String[] { CSourceLookup.class.getName(), ISourceLookup.class.getName() },
+                               new Hashtable<String, String>());
+
+               requestMonitor.done();
+       }
+
+       @Override
+       public void shutdown(final RequestMonitor requestMonitor) {
+               unregister();
+               super.shutdown(requestMonitor);
+       }
+
+       public void getDebuggerPath(ISourceLookupDMContext sourceLookupCtx, Object source,
+                       final DataRequestMonitor<String> rm) {
+               if (!(source instanceof String)) {
+                       // In future if needed other elements such as URIs could be
+                       // supported.
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED,
+                                       "Only string source element is supported", null)); //$NON-NLS-1$);
+                       rm.done();
+                       return;
+               }
+               final String sourceString = (String) source;
+
+               if (!directors.containsKey(sourceLookupCtx)) {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE,
+                                       "No source director configured for given context", null)); //$NON-NLS-1$);
+                       rm.done();
+                       return;
+               }
+               final CSourceLookupDirector[] director = getSourceLookupDirectors(sourceLookupCtx);
+
+               new Job("Lookup Debugger Path") { //$NON-NLS-1$
+                       @Override
+                       protected IStatus run(IProgressMonitor monitor) {
+
+                               rm.setData(sourceString);
+
+                               for (CSourceLookupDirector cSourceLookupDirector : director) {
+                                       IPath debuggerPath = cSourceLookupDirector.getCompilationPath(sourceString);
+                                       if (debuggerPath != null) {
+                                               rm.setData(debuggerPath.toString());
+                                               break;
+                                       }
+                               }                       
+                               rm.done();
+
+                               return Status.OK_STATUS;
+                       }
+               }.schedule();
+
+       }
+
+       public void getSource(ISourceLookupDMContext sourceLookupCtx, final String debuggerPath,
+                       final DataRequestMonitor<Object> rm) {
+               if (!directors.containsKey(sourceLookupCtx)) {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE,
+                                       "No source director configured for given context", null)); //$NON-NLS-1$);
+                       rm.done();
+                       return;
+               }
+               final CSourceLookupDirector[] director = getSourceLookupDirectors(sourceLookupCtx);
+
+               new Job("Lookup Source") { //$NON-NLS-1$
+                       @Override
+                       protected IStatus run(IProgressMonitor monitor) {
+                               Object[] sources;
+                               try {
+                                       for (CSourceLookupDirector cSourceLookupDirector : director) {
+                                               sources = cSourceLookupDirector.findSourceElements(debuggerPath);
+                                               if (sources == null || sources.length == 0) {
+                                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID,
+                                                                       IDsfStatusConstants.REQUEST_FAILED, "No sources found", null)); //$NON-NLS-1$);
+                                               } else {
+                                                       rm.setData(sources[0]);
+                                                       break;
+                                               }
+                                       }
+                               } catch (CoreException e) {
+                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED,
+                                                       "Source lookup failed", e)); //$NON-NLS-1$);
+                               } finally {
+                                       rm.done();
+                               }
+
+                               return Status.OK_STATUS;
+                       }
+               }.schedule();
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/ServicesLaunchSequence.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/ServicesLaunchSequence.java
new file mode 100644 (file)
index 0000000..eeaeeec
--- /dev/null
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.launch;
+
+import org.eclipse.cdt.debug.edc.internal.services.dsf.BreakpointAttributeTranslator;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Breakpoints;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.INoop;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Snapshots;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Symbols;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
+import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator2;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
+import org.eclipse.cdt.dsf.debug.service.IDisassembly;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IModules;
+import org.eclipse.cdt.dsf.debug.service.IProcesses;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.ISourceLookup;
+import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.ISymbols;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class ServicesLaunchSequence extends Sequence {
+
+       Step[] fSteps = new Step[] {
+       /*
+        * create this service as the first one as it's needed when
+        * constructing/initializing other services.
+        */
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       launch.getServiceFactory().createService(ITargetEnvironment.class, session, launch).initialize(
+                                       requestMonitor);
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       launch.getServiceFactory().createService(IProcesses.class, session).initialize(requestMonitor);
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       runControlService = (RunControl) launch.getServiceFactory().createService(IRunControl.class, session);
+                       runControlService.initialize(requestMonitor);
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       launch.getServiceFactory().createService(IMemory.class, session).initialize(requestMonitor);
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       Modules modules = (Modules) launch.getServiceFactory().createService(IModules.class, session);
+                       modules.initialize(requestMonitor);
+                       modules.setSourceLocator(launch.getExecutableLocator());
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       launch.getServiceFactory().createService(IStack.class, session).initialize(requestMonitor);
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       Symbols symbols = (Symbols) launch.getServiceFactory().createService(ISymbols.class, session);
+                       symbols.initialize(requestMonitor);
+                       symbols.setSourceLocator(launch.getSourceLocator());
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       launch.getServiceFactory().createService(IExpressions.class, session).initialize(requestMonitor);
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       sourceLookup = (CSourceLookup) launch.getServiceFactory().createService(ISourceLookup.class, session);
+                       sourceLookup.initialize(requestMonitor);
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       ISourceLookupDMContext sourceLookupDmc = runControlService.getRootDMC();
+                       sourceLookup.addSourceLookupDirector(sourceLookupDmc, (CSourceLookupDirector) launch.getSourceLocator());
+                       requestMonitor.done();
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       Breakpoints breakpoints = (Breakpoints) launch.getServiceFactory().createService(IBreakpoints.class,
+                                       session);
+                       breakpoints.initialize(new RequestMonitor(getExecutor(), requestMonitor));
+                       breakpoints.setSourceLocator(launch.getSourceLocator());
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       final BreakpointsMediator2 bpmService = new BreakpointsMediator2(session, new BreakpointAttributeTranslator(
+                                       session));
+                       bpmService.initialize(requestMonitor);
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       launch.getServiceFactory().createService(IRegisters.class, session).initialize(requestMonitor);
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       launch.getServiceFactory().createService(IDisassembly.class, session).initialize(requestMonitor);
+               }
+       },
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       launch.getServiceFactory().createService(Snapshots.class, session).initialize(
+                                       requestMonitor);
+               }
+       },
+
+       // Used for testing
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       launch.getServiceFactory().createService(INoop.class, session).initialize(requestMonitor);
+               }
+       }};
+
+       DsfSession session;
+       EDCLaunch launch;
+       RunControl runControlService;
+       CSourceLookup sourceLookup;
+
+       public ServicesLaunchSequence(DsfSession session, EDCLaunch launch, IProgressMonitor pm) {
+               super(session.getExecutor(), pm, "Initializing debugger services", "Aborting debugger services initialization");
+               this.session = session;
+               this.launch = launch;
+       }
+
+       @Override
+       public Step[] getSteps() {
+               return fSteps;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/ShutdownSequence.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/ShutdownSequence.java
new file mode 100644 (file)
index 0000000..44ba7f8
--- /dev/null
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.launch;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.INoop;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Snapshots;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Symbols;
+import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator2;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
+import org.eclipse.cdt.dsf.debug.service.IDisassembly;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IModules;
+import org.eclipse.cdt.dsf.debug.service.IProcesses;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.ISourceLookup;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+public class ShutdownSequence extends Sequence {
+
+       String sessionId;
+
+       String applicationName;
+
+       String debugModelId;
+
+       DsfServicesTracker tracker;
+
+       public ShutdownSequence(DsfExecutor executor, String sessionId, RequestMonitor requestMonitor) {
+               super(executor, requestMonitor);
+               this.sessionId = sessionId;
+       }
+
+       @Override
+       public Step[] getSteps() {
+               return steps;
+       }
+
+       private final Step[] steps = new Step[] {
+
+       new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       assert EDCDebugger.getDefault().getBundle().getBundleContext() != null;
+                       tracker = new DsfServicesTracker(EDCDebugger.getDefault().getBundle().getBundleContext(), sessionId);
+                       requestMonitor.done();
+               }
+
+               @Override
+               public void rollBack(RequestMonitor requestMonitor) {
+                       tracker.dispose();
+                       tracker = null;
+                       requestMonitor.done();
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(Snapshots.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(IDisassembly.class, requestMonitor);
+               }
+       }, new Step() {
+               // Call this to make sure breakpoints are removed.
+               // Do this before we shutdown other services to ensure
+               // breakpoints can be removed.
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(BreakpointsMediator2.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(IRegisters.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(IBreakpoints.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(ISourceLookup.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(IExpressions.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(IStack.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(IModules.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(IMemory.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(IRunControl.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(IProcesses.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(ITargetEnvironment.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(Symbols.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       shutdownService(INoop.class, requestMonitor);
+               }
+       }, new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       tracker.dispose();
+                       tracker = null;
+                       requestMonitor.done();
+               }
+       } };
+
+       private <V> void shutdownService(Class<V> clazz, final RequestMonitor requestMonitor) {
+               IDsfService service = (IDsfService) tracker.getService(clazz);
+               if (service != null) {
+                       service.shutdown(new RequestMonitor(getExecutor(), requestMonitor) {
+                               @Override
+                               protected void handleCompleted() {
+                                       if (!isSuccess()) {
+
+                                       }
+                                       requestMonitor.done();
+                               }
+                       });
+               } else {
+                       requestMonitor
+                                       .setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+                                                       "AbstractEDCService '" + clazz.getName() + "' not found.", null)); //$NON-NLS-1$//$NON-NLS-2$
+                       requestMonitor.done();
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/SnapshotLaunch.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/SnapshotLaunch.java
new file mode 100644 (file)
index 0000000..91864d6
--- /dev/null
@@ -0,0 +1,14 @@
+package org.eclipse.cdt.debug.edc.internal.launch;
+
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.model.ISourceLocator;
+
+public class SnapshotLaunch extends EDCLaunch {
+
+       public SnapshotLaunch(ILaunchConfiguration launchConfiguration, String mode,
+                       ISourceLocator locator, String ownerID) {
+               super(launchConfiguration, mode, locator, ownerID);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/SnapshotLaunchDelegate.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/launch/SnapshotLaunchDelegate.java
new file mode 100644 (file)
index 0000000..9a7366a
--- /dev/null
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.launch;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.snapshot.Album;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunchDelegate;
+import org.eclipse.cdt.debug.edc.launch.IEDCLaunchConfigurationConstants;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.debug.service.IDsfDebugServicesFactory;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+
+public class SnapshotLaunchDelegate extends EDCLaunchDelegate {
+
+       public final static String SNAPSHOT_DEBUG_MODEL_ID = "org.eclipse.cdt.debug.edc.internal.snapshot"; //$NON-NLS-1$
+       private Album album;
+       private ILaunchConfiguration proxyLaunchConfig;
+
+       @Override
+       public boolean preLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor)
+                       throws CoreException {
+               String albumLocation = configuration.getAttribute(IEDCLaunchConfigurationConstants.ATTR_ALBUM_FILE, "");
+               IPath albumPath = new Path(albumLocation);
+               album = Album.getAlbumByLocation(albumPath);
+               if (album == null || !album.isLoaded()) {
+                       if (album == null) {
+                               album = new Album();
+                       }
+                       album.setLocation(albumPath);
+                       try {
+                               album.loadAlbum(false);
+                       } catch (Exception e) {
+                               EDCDebugger.getMessageLogger().logError(null, e);
+                               return false;
+                       }
+               }
+               ILaunchManager lm = DebugPlugin.getDefault().getLaunchManager();
+               String launchID = album.getLaunchTypeID();
+               ILaunchConfigurationType launchType = lm.getLaunchConfigurationType(launchID);
+               if (launchType == null) {
+                       throw new CoreException(new Status(Status.ERROR, EDCDebugger.PLUGIN_ID, "Can't launch this snapshot because the required debugger is not installed: " + launchID));
+               }
+               proxyLaunchConfig = findExistingLaunchForAlbum(albumLocation);
+               if (proxyLaunchConfig == null) {
+                       String lcName = lm.generateLaunchConfigurationName(album.getDisplayName());
+                       ILaunchConfigurationWorkingCopy proxyLaunchConfigWC = launchType.newInstance(null, lcName);
+
+                       proxyLaunchConfigWC.setAttributes(album.getLaunchProperties());
+                       proxyLaunchConfigWC.setAttribute(IEDCLaunchConfigurationConstants.ATTR_ALBUM_FILE, configuration
+                                       .getAttribute(IEDCLaunchConfigurationConstants.ATTR_ALBUM_FILE, ""));
+                       proxyLaunchConfig = proxyLaunchConfigWC.doSave();
+               }
+
+               Job launchJob = new Job("Launching " + configuration.getName()) {
+
+                       @Override
+                       protected IStatus run(IProgressMonitor monitor) {
+                               try {
+                                       proxyLaunchConfig.launch(ILaunchManager.DEBUG_MODE, new NullProgressMonitor(), false, true);
+                               } catch (CoreException e) {
+                                       EDCDebugger.getMessageLogger().logError(null, e);
+                                       return Status.CANCEL_STATUS;
+                               }
+                               return Status.OK_STATUS;
+                       }
+               };
+               launchJob.schedule();
+               return false;
+       }
+
+       private ILaunchConfiguration findExistingLaunchForAlbum(String albumLocation) {
+               ILaunchManager lm = DebugPlugin.getDefault().getLaunchManager();
+               ILaunchConfigurationType launchType = lm.getLaunchConfigurationType(album.getLaunchTypeID());
+
+               try {
+                       ILaunchConfiguration[] configurations = lm.getLaunchConfigurations(launchType);
+                       for (ILaunchConfiguration configuration : configurations) {
+                               if (albumLocation.equals(configuration.getAttribute(IEDCLaunchConfigurationConstants.ATTR_ALBUM_FILE,
+                                               "")))
+                                       return configuration;
+                       }
+               } catch (CoreException e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+               return null;
+       }
+
+       @Override
+       public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
+                       throws CoreException {
+               proxyLaunchConfig.launch(mode, new NullProgressMonitor(), false, true);
+       }
+
+       @Override
+       public String getDebugModelID() {
+               return SNAPSHOT_DEBUG_MODEL_ID;
+       }
+
+       @Override
+       protected Sequence getLiveLaunchSequence(DsfExecutor executor, EDCLaunch launch, IProgressMonitor pm) {
+               return null;
+       }
+
+       @Override
+       protected IDsfDebugServicesFactory newServiceFactory() {
+               return null;
+       }
+
+       @Override
+       protected String getPluginID() {
+               return EDCDebugger.getUniqueIdentifier();
+       }
+
+       @Override
+       protected boolean isSameTarget(EDCLaunch existingLaunch,
+                       ILaunchConfiguration configuration, String mode) {
+               return false;
+       }
+
+       @Override
+       public EDCLaunch createLaunch(ILaunchConfiguration configuration,
+                       String mode) {
+               return new SnapshotLaunch(configuration, mode, null, getDebugModelID());
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/BreakpointAttributeTranslator.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/BreakpointAttributeTranslator.java
new file mode 100644 (file)
index 0000000..0b7119b
--- /dev/null
@@ -0,0 +1,459 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.core.model.ICBreakpoint;
+import org.eclipse.cdt.debug.core.model.ICLineBreakpoint;
+import org.eclipse.cdt.debug.core.model.ICWatchpoint;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleDMC;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider.ILineAddresses;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator2;
+import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator2.BreakpointEventType;
+import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator2.ITargetBreakpointInfo;
+import org.eclipse.cdt.dsf.debug.service.IBreakpointAttributeTranslator2;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.model.IBreakpoint;
+
+public class BreakpointAttributeTranslator implements IBreakpointAttributeTranslator2 {
+
+       private DsfServicesTracker      dsfServicesTracker;
+       private DsfSession                      dsfSession;
+       private ITargetEnvironment      targetEnvService;
+       
+       public BreakpointAttributeTranslator(DsfSession dsfSession) {
+               super();
+               this.dsfSession = dsfSession;
+               
+               dsfServicesTracker = new DsfServicesTracker(EDCDebugger.getDefault().getBundle().getBundleContext(), dsfSession.getId());
+               targetEnvService = dsfServicesTracker.getService(ITargetEnvironment.class);
+               assert targetEnvService != null;
+       }
+
+       public boolean canUpdateAttributes(IBreakpointDMContext bp, Map<String, Object> delta) {
+               /*
+                * This method decides whether we need to re-install the breakpoint
+                * based on the attributes change (refer to caller in
+                * BreakpointsMediator). For EDC, following changed attributes justify
+                * re-installation.
+                */         
+        // Check if there is any modified attribute
+        if (delta == null || delta.size() == 0)
+            return true;
+
+        // Check the "critical" attributes
+        // TODO: threadID change
+        if (delta.containsKey(IMarker.LINE_NUMBER)     // Line number
+        ||  delta.containsKey(IBreakpoint.ENABLED)        // EDC don't handle enable/disable. TODO: ask ITargetEnvironment service if it can handle it. 
+        ||  delta.containsKey(ICLineBreakpoint.FUNCTION)        // Function name
+        ||  delta.containsKey(ICLineBreakpoint.ADDRESS)         // Absolute address
+        ||  delta.containsKey(ICWatchpoint.EXPRESSION)      // Watchpoint expression
+        ||  delta.containsKey(ICWatchpoint.READ)            // Watchpoint type
+        ||  delta.containsKey(ICWatchpoint.WRITE)) {        // Watchpoint type
+            return false;
+        }
+
+        // for other attrs (ICBreakpoint.INSTALL_COUNT, ICBreakpoint.IGNORE_COUNT,
+        // ICBreakpoint.CONDITION, etc), we can update by just copying.
+        return true;
+       }
+
+       public void dispose() {
+               if (dsfServicesTracker != null)
+                       dsfServicesTracker.dispose();
+               dsfSession = null;
+       }
+
+       public List<Map<String, Object>> getBreakpointAttributes(IBreakpoint bp, boolean bpManagerEnabled)
+                       throws CoreException {
+               // The breakpoint mediator allows for multiple target-side breakpoints
+               // to be created for each IDE breakpoint. But the API is not good enough.
+
+               // obsolete 
+               List<Map<String, Object>> retVal = new ArrayList<Map<String, Object>>(1);
+               return retVal;
+       }
+
+       public void initialize(BreakpointsMediator2 mediator) {
+
+       }
+
+       public boolean supportsBreakpoint(IBreakpoint bp) {
+               // We support only CDT breakpoints.
+               return bp instanceof ICBreakpoint;
+       }
+
+       public void updateBreakpointStatus(IBreakpoint bp) {
+               // obsolet, do nothing.
+       }
+
+       public void updateBreakpointsStatus(Map<IBreakpoint, Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]>> bpsInfo,
+                       BreakpointEventType eventType) {
+               for (IBreakpoint bp : bpsInfo.keySet()) {
+                       if (! (bp instanceof ICBreakpoint))     // not C breakpoints, bail out.
+                               return;
+                       
+                       final ICBreakpoint icbp = (ICBreakpoint) bp;
+
+                       Map<IBreakpointsTargetDMContext, ITargetBreakpointInfo[]> targetBpPerContext = bpsInfo.get(bp);
+                       
+                       switch (eventType) {
+                       case ADDED: {
+                               int installCountTotal = 0;
+                               for (ITargetBreakpointInfo[] tbpInfos : targetBpPerContext.values()) {
+                                       // For each BpTargetDMContext, we increment the installCount for each
+                                       // target BP that has been successfully installed.
+                                       int installCountPerContext = 0;
+                                       for (ITargetBreakpointInfo tbp : tbpInfos) {
+                                               if (tbp.getTargetBreakpoint() != null)
+                                                       installCountPerContext++;
+                                       }
+                                       installCountTotal += installCountPerContext;
+                               }
+
+                               for (int i=0; i < installCountTotal; i++)
+                                       try {
+                                               // this will eventually carried out in a workbench runnable.
+                                               icbp.incrementInstallCount();
+                                       } catch (CoreException e) {
+                                               EDCDebugger.getMessageLogger().log(e.getStatus());
+                                       }
+                               break;
+                               }
+                       case MODIFIED:
+                               break;
+
+                       case REMOVED: {
+                               int removeCountTotal = 0;
+                               for (ITargetBreakpointInfo[] tbpInfos : targetBpPerContext.values()) {
+                                       // For each BpTargetDMContext, we decrement the installCount for each
+                                       // target BP that we tried to remove, even if the removal failed. That's
+                                       // because I've not seen a way to tell platform that removal fails 
+                                       // and the BP should be kept in UI.
+                                       removeCountTotal += tbpInfos.length;
+                               }
+
+                               for (int i=0; i < removeCountTotal; i++)
+                                       try {
+                                               if (icbp.isRegistered())        // not deleted in UI
+                                                       icbp.decrementInstallCount();
+                                       } catch (CoreException e) {
+                                               EDCDebugger.getMessageLogger().log(e.getStatus());
+                                       }
+                               break;
+                               }
+                       }
+               }
+       }
+
+       public Map<String, Object> convertAttributes(Map<String, Object> platformBPAttrDelta) {
+               // For EDC, we don't need any conversion yet....11/08/09.
+               return new HashMap<String, Object>(platformBPAttrDelta);
+       }
+
+    public void resolveBreakpoint(IBreakpointsTargetDMContext context, IBreakpoint breakpoint, 
+               final Map<String, Object> attributes, final DataRequestMonitor<List<Map<String, Object>>> drm) {
+               
+       final List<Map<String, Object>> targetBPAttrs = new ArrayList<Map<String, Object>>(1);
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null,
+                               "Resolving breakpoint " + EDCTrace.fixArg(breakpoint) + " in context " + EDCTrace.fixArg(context)); }
+
+       if (dsfSession == null) {
+               // already disposed
+                       drm.setData(targetBPAttrs);
+                       drm.done();
+                       if (EDCTrace.BREAKPOINTS_TRACE_ON) {EDCTrace.getTrace().traceExit(null, "null session");}
+                       return;
+       }
+       
+       Map<String, Object> oneBPAttr;
+       
+               final ModuleDMC module = (ModuleDMC) context;
+
+               String bpType = (String)attributes.get(Breakpoints.BREAKPOINT_SUBTYPE);
+               
+               if (bpType.equals(Breakpoints.ADDRESS_BREAKPOINT)) {
+                       String addr = (String)attributes.get(ICLineBreakpoint.ADDRESS);
+                       // This is hex string with "0x".
+                       assert addr != null;
+                       
+                       oneBPAttr = new HashMap<String, Object>(attributes);
+                       String s = addr.toLowerCase().startsWith("0x") ? addr.substring(2) : addr;
+                       oneBPAttr.put(Breakpoints.RUNTIME_ADDRESS, s);
+                       targetBPAttrs.add(oneBPAttr);
+
+                       drm.setData(targetBPAttrs);
+                       drm.done();
+               }
+               else if (bpType.equals(Breakpoints.FUNCTION_BREAKPOINT)) {
+                       String function = (String) attributes.get(ICLineBreakpoint.FUNCTION);
+                       assert (function != null && function.length() > 0);
+                       
+                       // the point is a symbol
+                       Symbols symService = dsfServicesTracker.getService(Symbols.class);
+                       List<IAddress> addrs = symService.getFunctionAddress(module, function);
+                       for (IAddress a : addrs) {
+                               oneBPAttr = new HashMap<String, Object>(attributes);
+                               oneBPAttr.put(Breakpoints.RUNTIME_ADDRESS, a.toString(16));
+                               
+                               targetBPAttrs.add(oneBPAttr);
+                       }
+
+                       drm.setData(targetBPAttrs);
+                       drm.done();
+               }
+               else {
+                       assert bpType.equals(Breakpoints.LINE_BREAKPOINT);
+                       
+                       final String bpFile = (String) attributes.get(ICBreakpoint.SOURCE_HANDLE);
+                       final Integer line = (Integer) attributes.get(IMarker.LINE_NUMBER);
+
+                       final IExecutionDMContext exe_dmc = DMContexts.getAncestorOfType(context, IExecutionDMContext.class);
+
+                       final ICBreakpoint icBP = (ICBreakpoint)breakpoint;
+
+                       assert exe_dmc != null : "ExecutionDMContext is unknown in resolveBreakpoint().";
+
+                       Modules modulesService = dsfServicesTracker.getService(Modules.class);
+                       ISymbolDMContext sym_dmc = DMContexts.getAncestorOfType(context, ISymbolDMContext.class);
+
+                       String compileFile = EDCLaunch.getLaunchForSession(dsfSession.getId()).getCompilationPath(bpFile);
+                       if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null,
+                                       "BP file: " + bpFile + " Compile file: " + compileFile); }
+
+                       /*
+                        * Look for code lines within five lines above and below the line in
+                        * question as we don't want to move a breakpoint too far.
+                        */
+                       modulesService.findClosestLineWithCode(sym_dmc, compileFile, line, 5, 
+                                       new DataRequestMonitor<ILineAddresses>(dsfSession.getExecutor(), drm) {
+
+                               @Override
+                               protected void handleCompleted() {
+                                       if (! isSuccess()) {
+                                               drm.setStatus(getStatus());
+                                               drm.done();
+                                               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null,
+                                                               "findClosestLineWithCode failed: " + drm.getStatus()); }
+                                               return;
+                                       }
+                                       
+                                       ILineAddresses codeLine = getData();
+
+                                       /*
+                                        * there could be multiple address ranges for the same
+                                        * source line. e.g. for templates or inlined functions. if
+                                        * so, we need only set a breakpoint on the first location
+                                        */
+                                       IAddress[] addresses = codeLine.getAddress();
+                                       if (addresses.length > 0) {
+                                               IAddress address = addresses[0];
+                                               for (int i = 1; i < addresses.length; i++)
+                                                       if (addresses[i].getValue().longValue() < address.getValue().longValue())
+                                                               address = addresses[i];
+                                               Map<String, Object> targetAttr = new HashMap<String, Object>(attributes);
+                                               targetAttr.put(Breakpoints.RUNTIME_ADDRESS, address.toString(16));
+                                               targetBPAttrs.add(targetAttr);
+                                       }
+
+                                       drm.setData(targetBPAttrs);
+                                       
+                                       int actualCodeLine = codeLine.getLineNumber();
+                                       
+                                       if (actualCodeLine == line)
+                                               drm.done();
+                                       else {          
+                                               // breakpoint is resolved to a different line (the closest code line).
+                                               // If there is no user breakpoint at that line, we move the breakpoint there.
+                                               // Otherwise just mark this breakpoint as unresolved.
+                                               //
+                                               final int newLine = actualCodeLine;
+
+                                               /** 
+                                                * Move the breakpoint to the actual code line.
+                                                *  
+                                                * Should we run following code in another thread  ? Seems yes according to comment in 
+                                                * BreakpointsMediator2.startTrackingBreakpoints(). But that way we'll run into this 
+                                                * problem:
+                                                *    11  // blank line
+                                                *    12  // blank line
+                                                *    13  i = 2;
+                                                * set bp at line 11 & 12, start debugger, we'll get two resolved breakpoints on line 13 
+                                                * (check in Breakpoints view).
+                                                *       
+                                                * To fix that issue, I just run this in DSF executor thread. I don't see any problem
+                                                * in my test......... 01/03/11
+                                                */
+                                               if (null == findUserBreakpointAt(bpFile, newLine)) {
+                                                       // After we change the line number attribute, a breakpoint-change 
+                                                       // notification will come from platform through BreakpointsMediator2, 
+                                                       // resulting in installation of the changed bp and removal of the 
+                                                       // original bp.
+                                                       try {
+                                                               icBP.getMarker().setAttribute(IMarker.LINE_NUMBER, newLine);
+                                                       } catch (CoreException e) {
+                                                               // When will this happen ? ignore.
+                                                       }
+
+                                                       // At this point the "drm" contains a valid list of "targetBPAttrs", namely
+                                                       // we treat this BP as resolved. This is needed for such moved-BP to work 
+                                                       // on debugger start.
+                                                       drm.done();
+                                               }
+                                               else {
+                                                       targetBPAttrs.clear();  // mark the BP as unresolved by clearing the list.
+                                                       drm.done();
+                                               }
+                                       }
+                               }
+                       });
+               }
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) {EDCTrace.getTrace().traceExit(null);}
+       }
+
+       public Map<String, Object> getAllBreakpointAttributes(IBreakpoint platformBP, boolean bpManagerEnabled)
+                       throws CoreException {
+               // Check that the marker exists and retrieve its attributes.
+               // Due to accepted race conditions, the breakpoint marker may become
+               // null while this method is being invoked. In this case throw an exception
+               // and let the caller handle it.
+               IMarker marker = platformBP.getMarker();
+               if (marker == null || !marker.exists()) {
+                       throw new DebugException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, DebugException.REQUEST_FAILED,
+                                       "Breakpoint marker does not exist", null));
+               }
+               // Suppress cast warning: platform is still on Java 1.3
+               Map<String, Object> platformBpAttrs = marker.getAttributes();
+
+               // Just make a copy of the platform attributes.
+               // Add conversion or addition when needed.
+               Map<String, Object> attrs = new HashMap<String, Object>(platformBpAttrs);
+
+               if (platformBP instanceof ICWatchpoint) {
+                       attrs.put(Breakpoints.BREAKPOINT_TYPE, Breakpoints.WATCHPOINT);
+                       /*
+                        * Related Attributes attributes.get(ICWatchpoint.EXPRESSION));
+                        * attributes.get(ICWatchpoint.READ));
+                        * attributes.get(ICWatchpoint.WRITE));
+                        */
+               } else if (platformBP instanceof ICLineBreakpoint) {
+                       attrs.put(Breakpoints.BREAKPOINT_TYPE, Breakpoints.BREAKPOINT);
+
+                       String file = (String) attrs.get(ICBreakpoint.SOURCE_HANDLE);
+                       String address = (String) attrs.get(ICLineBreakpoint.ADDRESS);
+                       String function = (String) attrs.get(ICLineBreakpoint.FUNCTION);
+                       Integer line = (Integer) attrs.get(IMarker.LINE_NUMBER);
+
+                       if (address != null && address.length() > 0)
+                               attrs.put(Breakpoints.BREAKPOINT_SUBTYPE, Breakpoints.ADDRESS_BREAKPOINT);
+                       else if (function != null && function.length() > 0)
+                               attrs.put(Breakpoints.BREAKPOINT_SUBTYPE, Breakpoints.FUNCTION_BREAKPOINT);
+                       else {
+                               assert file != null && file.length() > 0 && line != null;
+                               attrs.put(Breakpoints.BREAKPOINT_SUBTYPE, Breakpoints.LINE_BREAKPOINT);
+                       }
+                       /*
+                        * Related attributes: String
+                        * attributes.get(ICBreakpoint.SOURCE_HANDLE)); Int
+                        * attributes.get(IMarker.LINE_NUMBER)); String
+                        * attributes.get(ICLineBreakpoint.FUNCTION)); String
+                        * attributes.get(ICLineBreakpoint.ADDRESS));
+                        */
+               } else {
+                       // catchpoint?
+               }
+
+               /*
+                * Common fields attributes.get(ICBreakpoint.CONDITION));
+                * attributes.get(ICBreakpoint.IGNORE_COUNT));
+                * attributes.get(ICBreakpoint.INSTALL_COUNT));
+                * attributes.get(ICBreakpoint.ENABLED));
+                * attributes.get(ATTR_THREAD_ID)); // TODO: check: gdb specific ?
+                */
+
+               // If the breakpoint manager is disabled, override the enabled
+               // attribute.
+               if (!bpManagerEnabled) {
+                       attrs.put(IBreakpoint.ENABLED, false);
+               }
+
+               return attrs;
+       }
+
+       public boolean canUpdateAttributes(IBreakpoint bp, IBreakpointsTargetDMContext context, Map<String, Object> attrDelta) {
+               // no special handling needed for EDC yet.
+               return canUpdateAttributes(null, attrDelta);
+       }
+
+    /**
+     * Find the CDT line breakpoint that exists at the given line of the 
+     * given file.
+     *  
+     * @param bpFile
+     * @param bpLine
+     * @return IBreakpoint if found, null otherwise.
+     */
+       static private IBreakpoint findUserBreakpointAt(
+                       String bpFile, int bpLine) {
+               IBreakpoint[] platformBPs = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints();
+               for (IBreakpoint pbp : platformBPs) {
+                       if (pbp instanceof ICLineBreakpoint) {
+                               // Check that the marker exists and retrieve its attributes.
+                               // Due to accepted race conditions, the breakpoint marker may become
+                               // null while this method is being invoked. In this case throw an exception
+                               // and let the caller handle it.
+                               IMarker marker = pbp.getMarker();
+                               if (marker == null || !marker.exists())
+                                       continue;
+
+                               // Suppress cast warning: platform is still on Java 1.3
+                               try {
+                                       Map<String, Object> attrs = marker.getAttributes();
+       
+                                       String file = (String) attrs.get(ICBreakpoint.SOURCE_HANDLE);
+                                       Integer line = (Integer) attrs.get(IMarker.LINE_NUMBER);
+                                       
+                                       if (bpFile.equals(file) && bpLine == line)
+                                               return pbp;
+                               }
+                               catch (Exception e) {
+                                       // ignore
+                               }
+                       }
+               }
+               
+               return null;
+       }
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Breakpoints.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Breakpoints.java
new file mode 100644 (file)
index 0000000..abfe6c0
--- /dev/null
@@ -0,0 +1,1207 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.IllegalFormatException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.core.model.ICBreakpoint;
+import org.eclipse.cdt.debug.core.model.ICLineBreakpoint;
+import org.eclipse.cdt.debug.core.model.ICWatchpoint;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleDMC;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleLoadedEvent;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleUnloadedEvent;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+import org.eclipse.cdt.debug.edc.services.DMContext;
+import org.eclipse.cdt.debug.edc.services.IDSFServiceUsingTCF;
+import org.eclipse.cdt.debug.edc.services.IEDCDMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCExpression;
+import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
+import org.eclipse.cdt.debug.edc.services.Stack;
+import org.eclipse.cdt.debug.edc.tcf.extension.ProtocolConstants.IModuleProperty;
+import org.eclipse.cdt.debug.internal.core.breakpoints.BreakpointProblems;
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator2;
+import org.eclipse.cdt.dsf.debug.service.IBreakpointAttributeTranslator;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules.ModuleLoadedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IModules.ModuleUnloadedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.utils.Addr32;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.ISourceLocator;
+import org.eclipse.debug.core.model.MemoryByte;
+import org.eclipse.tm.tcf.protocol.IService;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IBreakpoints.DoneCommand;
+
+public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDSFServiceUsingTCF {
+
+       /**
+        * Breakpoint attributes markers used in the map parameters of
+        * insert/updateBreakpoint(). All are optional with the possible exception
+        * of TYPE. It is the responsibility of the
+        * {@link IBreakpointAttributeTranslator} to ensure that the set of
+        * attributes provided is sufficient to create/update a valid breakpoint on
+        * the back-end.
+        */
+       public static final String PREFIX = "org.eclipse.cdt.debug.edc.breakpoint"; //$NON-NLS-1$
+
+       // Our own attribute keys.
+       //
+       /**
+        * Breakpoint type: value is string.
+        */
+       public static final String BREAKPOINT_TYPE = PREFIX + ".type"; //$NON-NLS-1$
+               // type values:
+               public static final String BREAKPOINT = "breakpoint"; //$NON-NLS-1$
+               public static final String WATCHPOINT = "watchpoint"; //$NON-NLS-1$
+               public static final String CATCHPOINT = "catchpoint"; //$NON-NLS-1$
+
+       /**
+        * breakponint sub-type: value is string.
+        */
+       public static final String BREAKPOINT_SUBTYPE = PREFIX + ".subtype"; //$NON-NLS-1$
+               // sub-type values:
+               public static final String LINE_BREAKPOINT = "line_bp"; //$NON-NLS-1$
+               public static final String FUNCTION_BREAKPOINT = "function_bp"; //$NON-NLS-1$
+               public static final String ADDRESS_BREAKPOINT = "address_bp"; //$NON-NLS-1$
+       
+       /**
+        * breakpoint runtime address: value is hex string with no preceding "0x". 
+        */
+       public static final String RUNTIME_ADDRESS = PREFIX + ".runtime_addr";
+
+       // Error messages
+       static final String NULL_STRING = ""; //$NON-NLS-1$
+       static final String UNKNOWN_EXECUTION_CONTEXT = "Unknown execution context"; //$NON-NLS-1$
+       static final String UNKNOWN_BREAKPOINT_CONTEXT = "Unknown breakpoint context"; //$NON-NLS-1$
+       static final String UNKNOWN_BREAKPOINT_TYPE = "Unknown breakpoint type"; //$NON-NLS-1$
+       static final String UNKNOWN_BREAKPOINT = "Unknown breakpoint"; //$NON-NLS-1$
+       static final String BREAKPOINT_INSERTION_FAILURE = "Breakpoint insertion failure"; //$NON-NLS-1$
+       static final String WATCHPOINT_INSERTION_FAILURE = "Watchpoint insertion failure"; //$NON-NLS-1$
+       static final String INVALID_CONDITION = "Invalid condition"; //$NON-NLS-1$
+
+       // User breakpoints (those from the IDE) currently installed.
+       private final Map<IBreakpointDMContext, BreakpointDMData> userBreakpoints = new HashMap<IBreakpointDMContext, BreakpointDMData>();
+
+       /**
+        * Internal temporary breakpoints set by debugger for stepping.
+        */
+       private final List<BreakpointDMData> tempBreakpoints = new ArrayList<BreakpointDMData>();
+
+       private org.eclipse.tm.tcf.services.IBreakpoints tcfBreakpointService;
+
+       // Module in which startup breakpoint is installed for the debug session.
+       private Map<ILaunchConfiguration, ModuleDMC> startupBreakpointModule = new HashMap<ILaunchConfiguration, ModuleDMC>();
+
+       private ISourceLocator sourceLocator;
+
+    private Map<ICBreakpoint, IMarker> fBreakpointMarkers = new HashMap<ICBreakpoint, IMarker>();
+
+       static private long nextBreakpointID = 1;
+
+       // /////////////////////////////////////////////////////////////////////////
+       // Breakpoint Events
+       // /////////////////////////////////////////////////////////////////////////
+
+       public class BreakpointsChangedEvent extends AbstractDMEvent<IBreakpointsTargetDMContext> implements
+                       IBreakpointsChangedEvent {
+               private IBreakpointDMContext[] eventBreakpoints;
+
+               public BreakpointsChangedEvent(IBreakpointDMContext bp) {
+                       super(DMContexts.getAncestorOfType(bp, IBreakpointsTargetDMContext.class));
+                       eventBreakpoints = new IBreakpointDMContext[] { bp };
+               }
+
+               public IBreakpointDMContext[] getBreakpoints() {
+                       return eventBreakpoints;
+               }
+       }
+
+       public class BreakpointAddedEvent extends BreakpointsChangedEvent implements IBreakpointsAddedEvent {
+               public BreakpointAddedEvent(IBreakpointDMContext context) {
+                       super(context);
+               }
+       }
+
+       public class BreakpointUpdatedEvent extends BreakpointsChangedEvent implements IBreakpointsUpdatedEvent {
+               public BreakpointUpdatedEvent(IBreakpointDMContext context) {
+                       super(context);
+               }
+       }
+
+       public class BreakpointRemovedEvent extends BreakpointsChangedEvent implements IBreakpointsRemovedEvent {
+               public BreakpointRemovedEvent(IBreakpointDMContext context) {
+                       super(context);
+               }
+       }
+
+       // /////////////////////////////////////////////////////////////////////////
+       // IBreakpointDMContext
+       // /////////////////////////////////////////////////////////////////////////
+       @Immutable
+       public static final class BreakpointDMContext extends DMContext implements IBreakpointDMContext {
+               public BreakpointDMContext(String sessionID, IDMContext[] parents, long id) {
+                       super(sessionID, parents, Long.toString(id));
+               }
+
+               @Override
+               public String toString() {
+                       return "BreakpointDMContext [id=" + getID() + "]";
+               }
+       }
+
+       public class BreakpointDMData implements IBreakpointDMData {
+
+               private final long id; // internal ID.
+               private final IBreakpointDMContext context;
+               private final IAddress[] addresses;
+               private final byte[] originalInstruction;
+               private Map<String, Object> properties;
+               private int hitCount;
+
+               public BreakpointDMData(long id, IBreakpointDMContext context, IAddress[] addresses,
+                               Map<String, Object> properties) {
+                       super();
+                       this.id = id;
+                       this.context = context;
+                       this.addresses = addresses;
+                       this.originalInstruction = null;
+                       this.properties = new HashMap<String, Object>(properties); // make a  copy
+               }
+
+               public BreakpointDMData(long id, IBreakpointDMContext context, IAddress[] addresses,
+                               byte[] fOriginalInstruction, Map<String, Object> properties) {
+                       super();
+                       this.id = id;
+                       this.context = context;
+                       this.addresses = addresses;
+                       this.originalInstruction = fOriginalInstruction;
+                       this.properties = new HashMap<String, Object>(properties);
+               }
+
+               public IAddress[] getAddresses() {
+                       return addresses;
+               }
+
+               public String getBreakpointType() {
+                       return (String) properties.get(BREAKPOINT_TYPE);
+               }
+
+               public String getCondition() {
+                       return (String) properties.get(ICBreakpoint.CONDITION);
+               }
+
+               public String getExpression() {
+                       return (String) properties.get(ICWatchpoint.EXPRESSION);
+               }
+
+               public String getFileName() {
+                       return (String) properties.get(ICBreakpoint.SOURCE_HANDLE);
+               }
+
+               public String getFunctionName() {
+                       return (String) properties.get(ICLineBreakpoint.FUNCTION);
+               }
+
+               public int getIgnoreCount() {
+                       return (Integer) properties.get(ICBreakpoint.IGNORE_COUNT);
+               }
+
+               public int getLineNumber() {
+                       return (Integer) properties.get(IMarker.LINE_NUMBER);
+               }
+
+               public boolean isEnabled() {
+                       return (Boolean) properties.get(IBreakpoint.ENABLED);
+               }
+
+               public long getID() {
+                       return id;
+               }
+
+               public byte[] getOriginalInstruction() {
+                       return originalInstruction;
+               }
+
+               /**
+                * @return reference to properties map of the bp.
+                */
+               public Map<String, Object> getProperties() {
+                       return properties;
+               }
+
+               public IBreakpointDMContext getContext() {
+                       return context;
+               }
+
+               public void setProperties(Map<String, Object> props) {
+                       properties = new HashMap<String, Object>(props);
+               }
+
+               @Override
+               public int hashCode() {
+                       final int prime = 31;
+                       int result = 1;
+                       result = prime * result + getOuterType().hashCode();
+                       result = prime * result + (int) (id ^ (id >>> 32));
+                       return result;
+               }
+
+               @Override
+               public boolean equals(Object obj) {
+                       if (this == obj)
+                               return true;
+                       if (obj == null)
+                               return false;
+                       if (getClass() != obj.getClass())
+                               return false;
+                       BreakpointDMData other = (BreakpointDMData) obj;
+                       if (!getOuterType().equals(other.getOuterType()))
+                               return false;
+                       if (id != other.id)
+                               return false;
+                       return true;
+               }
+
+               private Breakpoints getOuterType() {
+                       return Breakpoints.this;
+               }
+
+               @Override
+               public String toString() {
+                       String s = getFileName();
+                       if (s == null) // address breakpoint
+                               s = getAddresses()[0].toHexAddressString();
+                       else {
+                               if (getFunctionName() != null)
+                                       s += ": " + getFunctionName();
+                               else
+                                       s += ":line " + getLineNumber();
+                       }
+                       return "Breakpoint@" + s;
+               }
+
+               public void incrementHitCount() {
+                       hitCount++;
+               }
+               
+               public int getHitCount()
+               {
+                       return hitCount;
+               }
+       }
+
+       public Breakpoints(DsfSession session) {
+               super(session, new String[] { IBreakpoints.class.getName(), Breakpoints.class.getName() });
+       }
+
+       @Override
+       public void initialize(final RequestMonitor rm) {
+               super.initialize(new RequestMonitor(getExecutor(), rm) {
+                       @Override
+                       protected void handleSuccess() {
+                               // Register as event listener.
+                               getSession().addServiceEventListener(Breakpoints.this, null);
+                               rm.done();
+                       }
+               });
+       }
+
+       public void getBreakpointDMData(IBreakpointDMContext dmc, DataRequestMonitor<IBreakpointDMData> drm) {
+               if (!userBreakpoints.containsKey(dmc)) {
+                       drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, UNKNOWN_BREAKPOINT));
+               } else
+                       drm.setData(userBreakpoints.get(dmc));
+
+               drm.done();
+       }
+
+       public void getBreakpoints(IBreakpointsTargetDMContext context, DataRequestMonitor<IBreakpointDMContext[]> drm) {
+               Set<IBreakpointDMContext> breakpointIDs = userBreakpoints.keySet();
+               drm.setData(breakpointIDs.toArray(new IBreakpointDMContext[breakpointIDs.size()]));
+               drm.done();
+       }
+
+       /**
+        * Find breakpoint, either user-set or debugger internal temporary one, at
+        * the given address.
+        * 
+        * @param addr
+        *            - absolute runtime address.
+        * @return null if not found.
+        */
+       public BreakpointDMData findBreakpoint(IAddress addr) {
+               BreakpointDMData bp = findUserBreakpoint(addr);
+               if (bp == null)
+                       bp = findTempBreakpoint(addr);
+               return bp;
+       }
+
+       /**
+        * Find user breakpoint at the given address.
+        * 
+        * @param addr
+        *            - absolute runtime address.
+        * @return null if not found.
+        */
+       public BreakpointDMData findUserBreakpoint(IAddress addr) {
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "Find user breakpoint at " + addr.toHexAddressString()); }
+
+               for (BreakpointDMData bp : userBreakpoints.values())
+                       if (bp.getAddresses()[0].equals(addr)) {
+                               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(bp.toString())); }
+                               return bp;
+                       }
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) {EDCTrace.getTrace().traceExit(null, "not found.");}
+               return null;
+       }
+
+       /**
+        * Find a temporary breakpoint at the given address.
+        * 
+        * @param addr
+        *            - absolute runtime address.
+        * @return null if not found.
+        */
+       public BreakpointDMData findTempBreakpoint(IAddress addr) {
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "Find temp breakpoint at " + addr.toHexAddressString()); }
+
+               for (BreakpointDMData bp : tempBreakpoints) {
+                       if (bp.getAddresses()[0].equals(addr)) {
+                               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(bp.toString())); }
+                               return bp;
+                       }
+               }
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null, "not found."); }
+               return null;
+       }
+
+       /**
+        * Remove software breakpoints inserted in memory by debugger from the given
+        * memory buffer starting from given address.
+        * 
+        * @param startAddr
+        *            start address of the memory data.
+        * @param memBuffer
+        *            a buffer containing data from memory. Its content will be
+        *            changed by this method if a breakpoint falls in the address
+        *            range.
+        */
+       public void removeBreakpointFromMemoryBuffer(IAddress startAddr, MemoryByte[] memBuffer) {
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "remove bp in memory area:" + startAddr.toHexAddressString() + "," + memBuffer.length); }
+
+               // If the breakpoint is actually set by TCF agent, we have to assume
+               // that the TCF agent would do this breakpoint removing for us as
+               // we have no idea how the agent set the breakpoint (e.g. is it software
+               // breakpoint ? if yes, what breakpoint instruction is used ?)
+               //
+               if (usesTCFBreakpointService())
+                       return;
+
+               for (BreakpointDMData edcBp : userBreakpoints.values()) {
+                       // TODO: bail out if the bp is not software breakpoint.
+
+                       IAddress bpAddr = edcBp.getAddresses()[0];
+                       int bpOffset = (int) startAddr.distanceTo(bpAddr).longValue();
+                       if (bpOffset >= 0 && bpOffset < memBuffer.length) {
+                               // the breakpoint falls in the buffer. Restore the original
+                               // instruction.
+                               byte[] orgInst = edcBp.getOriginalInstruction();
+                               for (int i = 0; i < orgInst.length && i + bpOffset < memBuffer.length; i++) {
+                                       memBuffer[bpOffset + i].setValue(orgInst[i]);
+                               }
+
+                               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, "breakpoint removed at offset " + bpOffset); }
+                       }
+               }
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       public void insertBreakpoint(IBreakpointsTargetDMContext context, Map<String, Object> attributes,
+                       DataRequestMonitor<IBreakpointDMContext> drm) {
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { attributes })); }
+
+               // Validate the context
+               if (context == null) {
+                       drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT,
+                                       null));
+                       drm.done();
+                       return;
+               }
+
+               // Validate the breakpoint type
+               String type = (String) attributes.get(BREAKPOINT_TYPE);
+               if (type == null) {
+                       drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE,
+                                       null));
+                       drm.done();
+                       return;
+               }
+
+               // And go...
+               if (type.equals(BREAKPOINT)) {
+                       addBreakpoint(context, attributes, drm);
+               } else if (type.equals(WATCHPOINT)) {
+                       drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
+                                       "Watchpoint is not supported yet.", null));
+                       drm.done();
+               } else {
+                       drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE,
+                                       null));
+                       drm.done();
+               }
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       /**
+        * Set one target breakpoint.
+        * 
+        * @param context
+        * @param attributes
+        *            attributes for the target breakpoint. For EDC, it must contain
+        *            the RUNTIME_ADDRESS attribute.
+        * @param drm
+        */
+       private void addBreakpoint(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes,
+                       final DataRequestMonitor<IBreakpointDMContext> drm) {
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { attributes })); }
+
+               IExecutionDMContext exe_dmc = DMContexts.getAncestorOfType(context, IExecutionDMContext.class);
+               String bpAddr = (String)attributes.get(RUNTIME_ADDRESS);
+               
+               assert exe_dmc != null : "ExecutionDMContext is unknown in addBreakpoint().";
+               assert bpAddr != null;
+               
+               createBreakpoint(exe_dmc, new Addr64(bpAddr, 16), attributes, new DataRequestMonitor<BreakpointDMData>(
+                               getExecutor(), drm) {
+
+                       @Override
+                       protected void handleSuccess() {
+                               final BreakpointDMData bpd = getData();
+
+                               enableBreakpoint(bpd, new RequestMonitor(getExecutor(), drm) {
+
+                                       @Override
+                                       protected void handleSuccess() {
+                                               IBreakpointDMContext bp_dmc = bpd.getContext();
+                                               drm.setData(bp_dmc);
+
+                                               // Remember this in our global list.
+                                               userBreakpoints.put(bp_dmc, bpd);
+
+                                               drm.done();
+                                       }
+                               });
+                       }
+               });
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       public ISourceLocator getSourceLocator() {
+               return sourceLocator;
+       }
+
+       public void setSourceLocator(ISourceLocator sourceLocator) {
+               this.sourceLocator = sourceLocator;
+       }
+
+       /**
+        * Set temporary breakpoint at given address. This is for cases such as
+        * stepping and initial startup breakpoint (aka entry breakpoint).<br>
+        * If a user or temporary breakpoint already exists at the address, no
+        * temporary breakpoint will be set.
+        * 
+        * @param context
+        * @param address
+        * @param rm
+        */
+       public void setTempBreakpoint(final IExecutionDMContext context, final IAddress address, final RequestMonitor rm) {
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "set temp breakpoint at " + address.toHexAddressString()); }
+
+               // If a breakpoint (user-set or temp) exists at the address, we are
+               // done.
+               if (findBreakpoint(address) != null) {
+                       rm.done();
+                       if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null, "A breakpoint exists at " + address.toHexAddressString()); }
+                       return;
+               }
+
+               createBreakpoint(context, address, new HashMap<String, Object>(), new DataRequestMonitor<BreakpointDMData>(
+                               getExecutor(), rm) {
+                       @Override
+                       protected void handleSuccess() {
+                               final BreakpointDMData bp_data = getData();
+
+                               enableBreakpoint(bp_data, new RequestMonitor(getExecutor(), rm) {
+                                       @Override
+                                       protected void handleSuccess() {
+                                               // Remember this in our list.
+                                               tempBreakpoints.add(bp_data);
+                                               rm.done();
+
+                                               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg("A temp breakpoint successfully set at " + address.toHexAddressString())); }
+                                       }
+                               });
+                       }
+               });
+       }
+
+       /**
+        * Remove all temporary breakpoints set so far.
+        * 
+        * @param rm
+        */
+       public void removeAllTempBreakpoints(final RequestMonitor rm) {
+
+               int numTempBps = tempBreakpoints.size();
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "remove " + numTempBps + " temp breakpoint" + ((numTempBps == 1)?"":"s") + "."); }
+
+               if (numTempBps == 0) {
+                       rm.done();
+                       return;
+               }
+
+               CountingRequestMonitor crm = new CountingRequestMonitor(getExecutor(), rm) {
+                       @Override
+                       protected void handleCompleted() {
+                               if (getStatus().isOK()) {
+                                       tempBreakpoints.clear();
+                               }
+                               super.handleCompleted();
+                       }
+               };
+
+               crm.setDoneCount(tempBreakpoints.size());
+
+               for (BreakpointDMData bp : tempBreakpoints)
+                       disableBreakpoint(bp, crm);
+       }
+
+       private void createBreakpoint(final IExecutionDMContext exeDMC, final IAddress address, final Map<String, Object> props,
+                       final DataRequestMonitor<BreakpointDMData> drm) {
+
+               asyncExec(new Runnable() {
+                       public void run() {
+                               final long id = getNewBreakpointID();
+                               final IBreakpointDMContext bp_dmc = new BreakpointDMContext(getSession().getId(), new IDMContext[] { exeDMC },
+                                               id);
+                               final IAddress[] bp_addrs = new IAddress[] { address };
+                               final Map<String, Object> properties = new HashMap<String, Object>(props);
+
+                               if (usesTCFBreakpointService()) {
+                                       properties.put(org.eclipse.tm.tcf.services.IBreakpoints.PROP_ID, Long.toString(id));
+                                       properties.put(org.eclipse.tm.tcf.services.IBreakpoints.PROP_ENABLED, true);
+                                       properties.put(org.eclipse.tm.tcf.services.IBreakpoints.PROP_TYPE,
+                                                       org.eclipse.tm.tcf.services.IBreakpoints.TYPE_AUTO);
+                                       properties.put(org.eclipse.tm.tcf.services.IBreakpoints.PROP_LOCATION, address.toString());
+
+
+                                       // Pass "contexts" for which the BP is supposed to work.
+                                       // NOTE: EDC extension to TCF: 
+                                       //  TCF only define "IBreakpoints.PROP_CONTEXTIDS" as a array of IDs. 
+                                       //  In EDC, it's required the first element in the array be IBreakpointsTargetDMContext
+                                       //  which is usually (but not always) a process. This makes EDC backward compatible with
+                                       //  some existing TCF agents.
+                                       IBreakpointsTargetDMContext bpTargetDMC = DMContexts.getAncestorOfType(exeDMC, IBreakpointsTargetDMContext.class);
+                                       // pass "exeDMC" as a context if it's different from bpTargetDMC, say, if "exeDMC" is a thread and
+                                       // the "bpTargetDMC" is the owner process. This allows for thread-specific BP if agent supports it.
+                                       String[] contexts;
+                                       if (! exeDMC.equals(bpTargetDMC))
+                                               contexts = new String[] {((IEDCDMContext)bpTargetDMC).getID(), ((IEDCDMContext)exeDMC).getID()};
+                                       else 
+                                               contexts = new String[] {((IEDCDMContext)bpTargetDMC).getID()};
+                                       properties.put(org.eclipse.tm.tcf.services.IBreakpoints.PROP_CONTEXTIDS, contexts);
+
+                                       getTargetEnvironmentService().updateBreakpointProperties(exeDMC, address, properties);
+
+                                       drm.setData(new BreakpointDMData(id, bp_dmc, bp_addrs, properties));
+                                       drm.done();
+                               } else { // generic software breakpoint
+                                       final byte[] bpInstruction = getTargetEnvironmentService().getBreakpointInstruction(exeDMC, address);
+                                       final int inst_size = bpInstruction.length;
+
+                                       Memory memoryService = getService(Memory.class);
+                                       IMemoryDMContext mem_dmc = DMContexts.getAncestorOfType(exeDMC, IMemoryDMContext.class);
+
+                                       memoryService.getMemory(mem_dmc, address, 0, 1, inst_size, new DataRequestMonitor<MemoryByte[]>(
+                                                       getExecutor(), drm) {
+                                               @Override
+                                               protected void handleSuccess() {
+                                                       MemoryByte[] org_inst = getData();
+                                                       final byte[] org_inst_bytes = new byte[org_inst.length];
+                                                       for (int i = 0; i < org_inst.length; i++) {
+                                                               // make sure each byte is okay
+                                                               if (!org_inst[i].isReadable()) {
+                                                                       drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
+                                                                                               ("Cannot read memory at 0x" + address.add(i).getValue().toString(16)),
+                                                                                               null));
+                                                                       drm.done();
+                                                                       return;
+                                                               }
+                                                               org_inst_bytes[i] = org_inst[i].getValue();
+                                                       }
+
+                                                       drm.setData(new BreakpointDMData(id, bp_dmc, bp_addrs, org_inst_bytes, properties));
+                                                       drm.done();
+                                               }
+                                       });
+                               }
+                       }
+                       
+               }, drm);
+
+       }
+
+       /**
+        * Install the breakpoint in the target process.
+        * 
+        * @param bp
+        * @param rm
+        */
+       public void enableBreakpoint(final BreakpointDMData bp, final RequestMonitor rm) {
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(bp)); }
+               
+               if (usesTCFBreakpointService()) {
+                       Protocol.invokeLater(new Runnable() {
+                               public void run() {
+                                       tcfBreakpointService.add(bp.getProperties(), new DoneCommand() {
+
+                                               public void doneCommand(IToken token, Exception error) {
+                                                       if (error != null) {
+                                                               // Make sure "done()" is called for the rm.
+                                                               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
+                                                                               "TCF agent fails to install " + bp + " because:\n"
+                                                                                               + error.getLocalizedMessage(), error));
+                                                               rm.done();
+                                                       } else {
+                                                               getSession().dispatchEvent(new BreakpointAddedEvent(bp.getContext()),
+                                                                               new Hashtable<String, Object>(bp.getProperties()));
+
+                                                               rm.done();
+                                                       }
+                                               }
+                                       });
+                               }
+                       });
+               } else {
+                       IAddress bp_addr = bp.getAddresses()[0];
+                       IExecutionDMContext exe_dmc = DMContexts.getAncestorOfType(bp.getContext(), IExecutionDMContext.class);
+                       byte[] bpInstruction = getTargetEnvironmentService().getBreakpointInstruction(exe_dmc, bp_addr);
+
+                       Memory memoryService = getService(Memory.class);
+                       IMemoryDMContext mem_dmc = DMContexts.getAncestorOfType(bp.getContext(), IMemoryDMContext.class);
+
+                       memoryService.setMemory(mem_dmc, bp_addr, 0, 1, bpInstruction.length, bpInstruction, rm);
+                       getSession().dispatchEvent(new BreakpointAddedEvent(bp.getContext()),
+                                       new Hashtable<String, Object>(bp.getProperties()));
+               }
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       private synchronized long getNewBreakpointID() {
+               return nextBreakpointID++;
+       }
+
+       public void removeBreakpoint(final IBreakpointDMContext dmc, RequestMonitor rm) {
+               // Remove user breakpoint.
+               //
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { dmc })); }
+
+               if (!(dmc instanceof BreakpointDMContext)) {
+                       // not our breakpoint, should not happen
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, "Unrecognized breakpoint context."));
+                       rm.done();
+                       return;
+               }
+
+               if (!userBreakpoints.containsKey(dmc)) {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, UNKNOWN_BREAKPOINT));
+                       rm.done();
+                       return;
+               }
+
+               disableBreakpoint(userBreakpoints.get(dmc), new RequestMonitor(getExecutor(), rm) {
+
+                       @Override
+                       protected void handleSuccess() {
+                               // Remove it from our record.
+                               userBreakpoints.remove(dmc);
+
+                               super.handleSuccess();
+                       }
+               });
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       /**
+        * Remove the breakpoint from the target process.
+        * 
+        * @param bp
+        * @param rm
+        */
+       public void disableBreakpoint(final BreakpointDMData bp, final RequestMonitor rm) {
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { bp })); } 
+
+               if (!usesTCFBreakpointService()) {
+                       final Memory memoryService = getService(Memory.class);
+                       IMemoryDMContext mem_dmc = DMContexts.getAncestorOfType(bp.getContext(), IMemoryDMContext.class);
+                       byte[] orgInst = bp.getOriginalInstruction();
+                       memoryService.setMemory(mem_dmc, bp.getAddresses()[0], 0, 1, orgInst.length, orgInst, rm);
+               } else {
+                       Protocol.invokeLater(new Runnable() {
+                               public void run() {
+                                       Map<String, Object> properties = bp.getProperties();
+                                       String id = (String) properties.get(org.eclipse.tm.tcf.services.IBreakpoints.PROP_ID);
+                                       tcfBreakpointService.remove(new String[] { id }, new DoneCommand() {
+
+                                               public void doneCommand(IToken token, Exception error) {
+                                                       rm.done();
+                                               }
+                                       });
+                               }
+                       });
+               }
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       public void updateBreakpoint(IBreakpointDMContext dmc, Map<String, Object> delta, RequestMonitor rm) {
+               /*
+                * For EDC, we don't need to do any update on non-significant attribute
+                * change, e.g. change of Install_count, ignore_count. For significant
+                * change, the breakpoint will just be re-installed. 
+                * See canUpdateAttributes().
+                */
+               BreakpointDMData bp = userBreakpoints.get(dmc);
+               if (bp == null)
+                       assert false : "Fail to find BreakpointDMData linked with the IBreakpointDMContext:" + dmc;
+               else {
+                       Map<String, Object> existingProps = bp.getProperties();
+                       for (String key : delta.keySet())
+                               existingProps.put(key, delta.get(key));
+               }
+               rm.done();
+       }
+
+       public boolean usesTCFBreakpointService() {
+               return tcfBreakpointService != null;
+       }
+
+       public void tcfServiceReady(IService service) {
+               tcfBreakpointService = (org.eclipse.tm.tcf.services.IBreakpoints) service;
+       }
+
+       @DsfServiceEventHandler
+       public void eventHandler_installBreakpointsForModule(ModuleLoadedDMEvent e) {
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { e })); }
+
+               // A new module (including main exe) is loaded. Install breakpoints for
+               // it.
+               ModuleLoadedEvent event = (ModuleLoadedEvent) e;
+               final IExecutionDMContext executionDMC = event.getExecutionDMC();
+               final ModuleDMC module = (ModuleDMC) e.getLoadedModuleContext();
+               BreakpointsMediator2 bm = getService(BreakpointsMediator2.class);
+               if (bm == null) {
+                       EDCDebugger.getMessageLogger().logError("Fail to get BreakpointsMediator service to install breakpoints for loaded module "+module, null);
+                       assert false;
+                       return;
+               }
+               
+               final boolean requireResume     = requireResume(module);
+       
+               IBreakpointsTargetDMContext bt_dmc = DMContexts.getAncestorOfType(module, IBreakpointsTargetDMContext.class);
+               bm.startTrackingBreakpoints(bt_dmc, new RequestMonitor(getExecutor(), null) {
+
+                       @Override
+                       protected void handleCompleted() {
+                               if (!isSuccess()) {
+                                       // do we want to display a dialog for user ?
+                                       // No, as it's expected not all breakpoints can be resolved
+                                       // in the module.
+
+                                       // Form readable message and log it.
+                                       IStatus status = getStatus();
+                                       String msg = MessageFormat.format(
+                                                       "Failed to install some breakpoints in the module [{0}]. Errors: \n", module.getName());
+                                       if (status.isMultiStatus()) {
+                                               for (IStatus s : ((MultiStatus) status).getChildren())
+                                                       msg += s.getMessage() + "\n";
+                                       } else
+                                               msg += status.getMessage();
+
+                                       if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, msg); }
+                               }
+
+                               // We should do these regardless of whether installing
+                               // breakpoints succeeded or not.
+                               setStartupBreakpoint(module, new RequestMonitor(getExecutor(), null) {
+
+                                       @Override
+                                       protected void handleCompleted() {
+                                               // do this regardless of status of installing entry
+                                               // breakpoint
+                                               // as it's expected the startup bp not resolvable in all
+                                               // modules.
+                                               //
+                                               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, "resume process after module load event ..."); }
+                                               if (requireResume)
+                                                       ((ExecutionDMC) executionDMC).resume(new RequestMonitor(getExecutor(), null));
+                                       }
+                               });
+                       }
+               });
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       /**
+        * Check if resume is required after handling load/unload of the given module.
+        * 
+        * @param module
+        * @return
+        */
+       private boolean requireResume(ModuleDMC module) {
+               boolean requireResume = true;
+               Object propvalue = module.getProperties().get(IModuleProperty.PROP_RESUME);
+               if (propvalue != null)
+                       if (propvalue instanceof Boolean)
+                               requireResume = (Boolean) propvalue;
+
+               return requireResume;
+       }
+
+       /**
+        * Set breakpoint at startup point specified by user.
+        * 
+        * @param module
+        * @param rm
+        */
+       protected void setStartupBreakpoint(ModuleDMC module, RequestMonitor rm) {
+               EDCLaunch launch = EDCLaunch.getLaunchForSession(getSession().getId());
+               ILaunchConfiguration launchConfig = launch.getLaunchConfiguration();
+               if (startupBreakpointModule.get(launchConfig) != null) {
+                       // already set in a module for this launch configuration, no need to try it for any other module
+                       rm.done();
+                       return;
+               }
+
+               String startupStopAt = launch.getStartupStopAtPoint();
+               // Is this even requested by user ?
+               if (startupStopAt == null) {
+                       rm.done();
+                       return;
+               }
+
+               // Ask target environment whether it wants us to try installing
+               // startup breakpoint in the module.
+               ITargetEnvironment te = getTargetEnvironmentService();
+               if (! te.needStartupBreakpointInExecutable(module.getName())) {
+                       rm.done();
+                       return;
+               }
+
+               IAddress iaddr = null;
+               long address = 0;
+
+               // Check if the point is absolute runtime address.
+               //
+               try {
+                       // first check if it's decimal number
+                       address = Long.parseLong(startupStopAt);
+               } catch (NumberFormatException e) {
+                       // then check if it's hex
+                       if (startupStopAt.toLowerCase().startsWith("0x")) {
+                               try {
+                                       address = Long.parseLong(startupStopAt.substring(2), 16);
+                               } catch (IllegalFormatException e1) {
+                                       // ignore
+                               }
+                       }
+               }
+
+               if (address != 0) {
+                       iaddr = new Addr32(address);
+                       
+                       // Assume it is a link-time address first.  Run-time addresses are not predictable across launches.
+                       IAddress runAddr = module.toRuntimeAddress(iaddr);
+                       if (module.containsAddress(runAddr)) {
+                               iaddr = runAddr;
+                       } else {
+                               // Try for a runtime address.
+                               if (!module.containsAddress(iaddr)) {
+                                       // address not in the module, don't bother.
+                                       // This is to ensure the address breakpoint is installed
+                                       // after the container module is loaded. 
+                                       iaddr = null;
+                               }
+                       }
+               } else {
+                       // the point is a symbol
+                       Symbols symService = getService(Symbols.class);
+                       List<IAddress> addrs = symService.getFunctionAddress(module, startupStopAt);
+                       
+                       if (addrs.size() > 0)
+                               // just choose the first one
+                               iaddr = addrs.get(0);
+               }
+
+               if (iaddr == null) {
+                       EDCDebugger.getMessageLogger().logError(
+                                       "Could not resolve startup breakpoint: "+ startupStopAt, null);
+                       rm.done();
+               } else {
+                       // The breakpoint is resolved in the module.
+                       startupBreakpointModule.put(launchConfig, module);
+
+                       IExecutionDMContext exe_dmc = DMContexts.getAncestorOfType(module, IExecutionDMContext.class);
+                       setTempBreakpoint(exe_dmc, iaddr, rm);
+               }
+       }
+
+       @DsfServiceEventHandler
+       public void eventHandler_uninstallBreakpointsForModule(ModuleUnloadedDMEvent e) {
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { e.getClass().getName(), e })); }
+
+               // An existing module (including main exe) is unloaded. Uninstall
+               // breakpoints for it.
+               ModuleUnloadedEvent event = (ModuleUnloadedEvent) e;
+               final ExecutionDMC executionDMC = (ExecutionDMC)event.getExecutionDMC();
+               final ModuleDMC module = (ModuleDMC) e.getUnloadedModuleContext();
+
+               /*
+                * If module containing startup break is unloaded, mark the startup
+                * break as gone so that we can reinstall it the next time the module is
+                * loaded again in the same debug session.
+                */
+               if (startupBreakpointModule != null &&
+                       startupBreakpointModule.equals(module))
+                       startupBreakpointModule = null;
+               
+               final boolean requireResume     = requireResume(module);
+               
+               BreakpointsMediator2 bm = getService(BreakpointsMediator2.class);
+               IBreakpointsTargetDMContext bt_dmc = DMContexts.getAncestorOfType(e.getUnloadedModuleContext(),
+                               IBreakpointsTargetDMContext.class);
+               bm.stopTrackingBreakpoints(bt_dmc, new RequestMonitor(getExecutor(), null) {
+                       @Override
+                       protected void handleFailure() {
+                               // super will just log the error.
+                               super.handleFailure();
+                               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, "uninstalling breakpoints failed"); }
+                       }
+
+                       @Override
+                       protected void handleSuccess() {
+                               super.handleSuccess();
+                               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, "breakpoints uninstalled and resume process..."); }
+                               if (requireResume)
+                                       executionDMC.resume(new RequestMonitor(getExecutor(), null));
+                       }
+               });
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       protected void addBreakpointProblemMarker(final ICBreakpoint breakpoint, final String description, final int severity) {
+        if (! (breakpoint instanceof ICLineBreakpoint))
+               return;
+
+        new Job("Add Breakpoint Problem Marker") { //$NON-NLS-1$
+            @Override
+            protected IStatus run(IProgressMonitor monitor) {
+               // If we have already have a problem marker on this breakpoint
+               // we should remove it first.
+                IMarker marker = fBreakpointMarkers.remove(breakpoint);
+                if (marker != null) {
+                    try {
+                        marker.delete();
+                    } catch (CoreException e) {
+                    }
+               }
+
+                ICLineBreakpoint lineBreakpoint = (ICLineBreakpoint) breakpoint;
+                try {
+                    // Locate the workspace resource via the breakpoint marker
+                    IMarker breakpoint_marker = lineBreakpoint.getMarker();
+                    IResource resource = breakpoint_marker.getResource();
+
+                    // Add a problem marker to the resource
+                    IMarker problem_marker = resource.createMarker(BreakpointProblems.BREAKPOINT_PROBLEM_MARKER_ID);
+                    int line_number = lineBreakpoint.getLineNumber();
+                    problem_marker.setAttribute(IMarker.LOCATION,    String.valueOf(line_number));
+                    problem_marker.setAttribute(IMarker.MESSAGE,     description);
+                    problem_marker.setAttribute(IMarker.SEVERITY,    severity);
+                    problem_marker.setAttribute(IMarker.LINE_NUMBER, line_number);
+
+                    // And save the baby
+                    fBreakpointMarkers.put(breakpoint, problem_marker);
+                } catch (CoreException e) {
+                }
+                
+                return Status.OK_STATUS;
+            }
+        }.schedule();
+    }
+
+    protected void removeBreakpointProblemMarker(final ICBreakpoint breakpoint) {
+
+        final IMarker marker = fBreakpointMarkers.remove(breakpoint);
+        if (marker == null)
+               return;
+        
+        new Job("Remove Breakpoint Problem Marker") { //$NON-NLS-1$
+            @Override
+            protected IStatus run(IProgressMonitor monitor) {
+                try {
+                    marker.delete();
+                } catch (CoreException e) {
+                }
+
+                return Status.OK_STATUS;
+            }
+        }.schedule();
+    }
+
+       /**
+        * Evaluate condition of given breakpoint, if any.
+        * 
+        * @param context 
+        *                        execution context in which to evaluate the condition.
+        * @param bp
+        *            the breakpoint.
+        * @param drm
+        *            DataRequestMonitor that contains result indicating whether
+        *            to stop execution of debugged program. The result value is
+        *            true if <br>
+        *            1. the breakpoint has no condition, or <br>
+        *            2. the breakpoint condition is invalid in syntax, or <br>
+        *            3. the breakpoint condition cannot be resolved, or <br>
+        *            4. the breakpoint condition is true.<br>
+        *            Otherwise the result in the drm is false.
+        * 
+        */
+       public void evaluateBreakpointCondition(IExecutionDMContext context, final BreakpointDMData bp, final DataRequestMonitor<Boolean> drm) {
+               final String expr = bp.getCondition();
+               if (expr == null || expr.length() == 0) {
+                       bp.incrementHitCount();
+                       drm.setData(bp.getHitCount() > bp.getIgnoreCount());
+                       drm.done();
+                       return;
+               }
+
+               Stack stackService = getService(Stack.class);
+
+               stackService.getTopFrame(context, new DataRequestMonitor<IFrameDMContext>(getExecutor(), drm) {
+
+                       @Override
+                       protected void handleCompleted() {
+                               if (!isSuccess()) { // fail to get frame, namely cannot
+                                                                       // evaluate the condition
+                                       bp.incrementHitCount();
+                                       drm.setData(bp.getHitCount() > bp.getIgnoreCount());
+                                       drm.done();
+                               } else {
+                                       Expressions exprService = getService(Expressions.class);
+                                       IEDCExpression expression = (IEDCExpression) exprService.createExpression(getData(), expr);
+                                       FormattedValueDMContext fvc = exprService.getFormattedValueContext(expression,
+                                                       IFormattedValues.NATURAL_FORMAT);
+                                       FormattedValueDMData value = expression.getFormattedValue(fvc);
+                                       /*
+                                        * honor the breakpoint if the condition is true or
+                                        * invalid.
+                                        */
+                                       String vstr = value.getFormattedValue();
+                                       if (! vstr.equals("true") && ! vstr.equals("false")) //$NON-NLS-1$ //$NON-NLS-2$
+                                               reportBreakpointProblem(bp.getContext(), "Breakpoint condition failed to resolve to boolean: " + vstr);
+                                       else // remove any problem marker
+                                               reportBreakpointProblem(bp.getContext(), "");
+                                       
+                                       if (!vstr.equals("false"))
+                                       {
+                                               bp.incrementHitCount();
+                                               drm.setData(bp.getHitCount() > bp.getIgnoreCount());
+                                       }
+                                       else
+                                               drm.setData(false); //$NON-NLS-1$
+
+                                       drm.done();
+                               }
+                       }
+               });
+       }
+
+       /**
+        * Report breakpoint problem in breakpoint marker.
+        * 
+        * @param targetBP
+        * @param description - empty string indicates removing problem marker. 
+        */
+       protected void reportBreakpointProblem(IBreakpointDMContext targetBP, String description) {
+               BreakpointsMediator2 bmService = getService(BreakpointsMediator2.class);
+               if (bmService == null) {
+                       assert false;
+                       return;
+               }
+               IBreakpoint platformBP = bmService.getPlatformBreakpoint(null, targetBP);
+               if (platformBP == null)
+                       return;
+               
+               if (description.length() > 0)
+                       addBreakpointProblemMarker((ICBreakpoint)platformBP, description, IMarker.SEVERITY_WARNING);
+               else
+                       removeBreakpointProblemMarker((ICBreakpoint)platformBP);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/EDCServicesMessages.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/EDCServicesMessages.java
new file mode 100644 (file)
index 0000000..1a90b90
--- /dev/null
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import org.eclipse.osgi.util.NLS;
+
+public class EDCServicesMessages extends NLS {
+       private static final String BUNDLE_NAME = "org.eclipse.cdt.debug.edc.internal.services.dsf.EDCServicesMessages"; //$NON-NLS-1$
+
+       public static String Expressions_CannotCastOutsideFrame;
+
+       public static String Expressions_CannotModifyCompositeValue;
+
+       public static String Expressions_CannotParseExpression;
+
+       public static String Expressions_ErrorInVariableFormatter;
+
+       public static String Expressions_ExpressionNoLocation;
+
+       public static String Expressions_SyntaxError;
+
+       public static String Disassembly_CannotReadMemoryAt;
+       
+       public static String Disassembly_NoDisassemblerYet;
+
+       static {
+               // initialize resource bundle
+               NLS.initializeMessages(BUNDLE_NAME, EDCServicesMessages.class);
+       }
+
+       private EDCServicesMessages() {
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/EDCServicesMessages.properties b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/EDCServicesMessages.properties
new file mode 100644 (file)
index 0000000..7618d6e
--- /dev/null
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright (c) 2009, 2010 Nokia and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Nokia - Initial API and implementation
+###############################################################################
+Expressions_CannotCastOutsideFrame=cannot cast expressions outside stack frame
+Expressions_CannotModifyCompositeValue=Cannot modify the value of a composite type
+Expressions_CannotParseExpression=cannot parse expression
+Expressions_SyntaxError=syntax error
+Expressions_ErrorInVariableFormatter=Error in variable formatter: 
+Expressions_ExpressionNoLocation=expression has no location
+Disassembly_CannotReadMemoryAt=Cannot read memory at {0} (length {1})
+Disassembly_NoDisassemblerYet=No disassembler is available yet.
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Expressions.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Expressions.java
new file mode 100644 (file)
index 0000000..5e1a6ca
--- /dev/null
@@ -0,0 +1,1428 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.core.dom.ast.IASTTypeId;
+import org.eclipse.cdt.core.dom.ast.IBasicType;
+import org.eclipse.cdt.debug.edc.MemoryUtils;
+import org.eclipse.cdt.debug.edc.formatter.ITypeContentProvider;
+import org.eclipse.cdt.debug.edc.formatter.IVariableValueConverter;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.internal.NumberFormatUtils;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvaluationEngine;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.IArrayDimensionType;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.InstructionSequence;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.Interpreter;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.OperandValue;
+import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager;
+import org.eclipse.cdt.debug.edc.internal.symbols.IAggregate;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICompositeType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IEnumeration;
+import org.eclipse.cdt.debug.edc.internal.symbols.IField;
+import org.eclipse.cdt.debug.edc.internal.symbols.IInheritance;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IReferenceType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISubroutineType;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+import org.eclipse.cdt.debug.edc.services.DMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCDMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCExpression;
+import org.eclipse.cdt.debug.edc.services.IEDCExpressions;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.symbols.IEnumerator;
+import org.eclipse.cdt.debug.edc.symbols.IInvalidVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IExpressions2;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+public class Expressions extends AbstractEDCService implements IEDCExpressions {
+
+       public abstract class BaseEDCExpressionDMC extends DMContext implements IEDCExpression {
+               protected String expression;
+               private InstructionSequence parsedExpression;
+               private final ASTEvaluationEngine engine;
+               private final StackFrameDMC frame;
+               protected Number value;
+               protected IStatus valueError;
+               private IVariableLocation valueLocation;
+               private IType valueType;
+               private boolean hasChildren = false;
+               private String valueString;
+
+               public BaseEDCExpressionDMC(IDMContext parent, String expression, String name) {
+                       super(Expressions.this, new IDMContext[] { parent }, name, ((IEDCDMContext)parent).getID() + "." + name); //$NON-NLS-1$
+                       this.expression = expression;
+                       this.frame = DMContexts.getAncestorOfType(parent, StackFrameDMC.class);
+                       engine = new ASTEvaluationEngine(getEDCServicesTracker(), frame, frame.getTypeEngine());
+               }
+               
+               public BaseEDCExpressionDMC(IDMContext parent, String expression) {
+                       this(parent, expression, expression);
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.services.DMContext#toString()
+                */
+               @Override
+               public String toString() {
+                       return getExpression();
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#getFrame()
+                */
+               public IFrameDMContext getFrame() {
+                       return frame;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#getExpression()
+                */
+               public String getExpression() {
+                       return expression;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#evaluateExpression()
+                */
+               public synchronized void evaluateExpression() {
+                       if (value != null || valueError != null)
+                               return;
+                       
+                       String expression = getExpression();
+
+                       if (parsedExpression == null) {
+                               try {
+                                       parsedExpression = engine.getCompiledExpression(expression);
+                               } catch (CoreException e) {
+                                       value = null;
+                                       valueError = e.getStatus();
+                                       valueLocation = null;
+                                       valueType = null;
+                                       return;
+                               }
+                       }
+
+                       if (parsedExpression.getInstructions().length == 0) {
+                               value = null;
+                               valueError = new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID,
+                                               EDCServicesMessages.Expressions_SyntaxError);
+                               valueLocation = null;
+                               valueType = null;
+                               return;
+                       }
+
+                       Interpreter interpreter;
+                       try {
+                               interpreter = engine.evaluateCompiledExpression(parsedExpression);
+                       } catch (CoreException e) {
+                               value = null;
+                               valueError = e.getStatus();
+                               valueLocation = null;
+                               valueType = null;
+                               return;
+                       }
+                       
+                       OperandValue variableValue = interpreter.getResult();
+                       if (variableValue == null) {
+                               value = null;
+                               valueError = null;
+                               valueLocation = null;
+                               valueType = null;
+                               return;
+                       }
+
+                       valueLocation = variableValue.getValueLocation();
+                       valueType = variableValue.getValueType();
+                       try {
+                               value = variableValue.getValue();
+                               valueString = variableValue.getStringValue();
+                       } catch (CoreException e1) {
+                               value = null;
+                               valueError = e1.getStatus();
+                               return;
+                       }
+
+                       // for a structured type or array, return the location and note
+                       // that it has children
+                       if (valueType instanceof IAggregate && valueLocation != null) {
+                               // TODO
+                               try {
+                                       value = variableValue.getValueLocationAddress();
+                               } catch (CoreException e) {
+                                       value = null;
+                                       valueError = e.getStatus();
+                               }
+                               if (!(value instanceof IInvalidVariableLocation))
+                                       hasChildren = true;
+                       }
+
+                       // if the location evaluates to NotLive, the types and values do
+                       // not matter
+                       if (valueLocation instanceof IInvalidVariableLocation) {
+                               value = null;
+                               valueError = new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID,
+                                               ((IInvalidVariableLocation) valueLocation).getMessage());
+                               valueLocation = null; //$NON-NLS-1$
+                               return;
+                       }
+
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#getFormattedValue(org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext)
+                */
+               public FormattedValueDMData getFormattedValue(FormattedValueDMContext dmc) {
+                       if (EDCTrace.VARIABLE_VALUE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(dmc)); }
+                       evaluateExpression();
+                       String result = ""; //$NON-NLS-1$
+
+                       if (valueError != null) {
+                               result = valueError.getMessage();
+                       } else if (value != null) {
+                               result = value.toString();
+                               
+                               IType unqualifiedType = TypeUtils.getUnRefStrippedType(valueType);
+                               
+                               String temp = null;
+                               String formatID = dmc.getFormatID();
+                               
+                               // the non-natural formats have expected representations in other
+                               // parts of DSF, so be strict about what we return
+                               if (formatID.equals(IFormattedValues.HEX_FORMAT)) {
+                                       temp = NumberFormatUtils.toHexString(value);
+                               } else if (formatID.equals(IFormattedValues.OCTAL_FORMAT)) {
+                                       temp = NumberFormatUtils.toOctalString(value);
+                               } else if (formatID.equals(IFormattedValues.BINARY_FORMAT)) {
+                                       temp = NumberFormatUtils.asBinary(value);
+                               } else if (formatID.equals(IFormattedValues.NATURAL_FORMAT)) {
+                                       // convert non-integer types to original representation
+                                       if (unqualifiedType instanceof ICPPBasicType) {
+                                               ICPPBasicType basicType = (ICPPBasicType) unqualifiedType;
+                                               switch (basicType.getBaseType()) {
+                                               case ICPPBasicType.t_char:
+                                                       temp = NumberFormatUtils.toCharString(value, valueType);
+                                                       break;
+                                               case ICPPBasicType.t_wchar_t:
+                                                       temp = NumberFormatUtils.toCharString(value, valueType);
+                                                       break;
+                                               case ICPPBasicType.t_bool:
+                                                       temp = Boolean.toString(value.longValue() != 0);
+                                                       break;
+                                               default:
+                                                       // account for other debug formats
+                                                       if (basicType.getName().equals("wchar_t")) { //$NON-NLS-1$
+                                                               temp = NumberFormatUtils.toCharString(value, valueType);
+                                                       }
+                                                       break;
+                                               }
+                                       } else if (unqualifiedType instanceof IAggregate || unqualifiedType instanceof IPointerType) {
+                                               // show addresses for aggregates and pointers as hex in natural format
+                                               temp = NumberFormatUtils.toHexString(value);
+                                       } 
+                                       
+                                       // TODO: add type suffix if the value cannot fit in
+                                       // the ordinary range of the base type.
+                                       // E.g., for an unsigned int, 0xFFFFFFFF should usually be 0xFFFFFFFFU,
+                                       // and for a long double, 1.E1000 should be 1.E1000L.
+                                       /*
+                                       // apply required integer and float suffixes
+                                       IType unqualifiedType = TypeUtils.getStrippedType(valueType);
+                                       if (unqualifiedType instanceof ICPPBasicType) {
+                                               ICPPBasicType basicType = (ICPPBasicType) unqualifiedType;
+                                               
+                                               if (basicType.getBaseType() == ICPPBasicType.t_float) {
+                                                       //result += "F"; // no
+                                               } else if (basicType.getBaseType() == ICPPBasicType.t_double) {
+                                                       if (basicType.isLong() AND actual value does not fit in a double)
+                                                               result += "L";
+                                               } else if (basicType.getBaseType() == ICPPBasicType.t_int) {
+                                                       if (basicType.isUnsigned() AND actual value does not fit in a signed int)
+                                                               result += "U";
+                                                       if (basicType.isLongLong() AND actual value does not fit in a signed int)
+                                                               result += "LL";
+                                                       else if (basicType.isLong() AND actual value does not fit in a signed int)
+                                                               result += "L";
+                                               }
+                                       }
+                                        */
+                                       
+                                       // for an enumerator, return the name, if any
+                                       if (unqualifiedType instanceof IEnumeration) {
+                                               long enumeratorValue = value.longValue();
+
+                                               IEnumerator enumerator = ((IEnumeration) unqualifiedType).getEnumeratorByValue(enumeratorValue);
+                                               if (enumerator != null) {
+                                                       if (temp == null)
+                                                               temp = result;
+                                                       
+                                                       temp = enumerator.getName() + " [" + temp + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+                                               }
+                                       }
+                               }
+                               if (temp != null)
+                                       result = temp; 
+                               
+                               // otherwise, leave value as is
+                               
+                               
+                       }
+                       if (EDCTrace.VARIABLE_VALUE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(result)); }
+                       return new FormattedValueDMData(result);
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#getValueLocation()
+                */
+               public IVariableLocation getValueLocation() {
+                       evaluateExpression();
+                       return getEvaluatedLocation();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.services.IEDCExpression#getEvaluationError()
+                */
+               public IStatus getEvaluationError() {
+                       return valueError;
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#getEvaluatedValue()
+                */
+               public Number getEvaluatedValue() {
+                       return value;
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.services.IEDCExpression#getEvaluatedValueString()
+                */
+               public String getEvaluatedValueString() {
+                       if (valueError != null)
+                               return valueError.getMessage();
+                       
+                       if (valueString != null)
+                               return valueString;
+                       
+                       valueString = value != null ? value.toString() : ""; //$NON-NLS-1$
+                       return valueString;
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.services.IEDCExpression#setEvaluatedValueString(java.lang.String)
+                */
+               public void setEvaluatedValueString(String string) {
+                       this.valueString = string;
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#setEvaluatedValue(java.lang.Object)
+                */
+               public void setEvaluatedValue(Number value) {
+                       this.value = value;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#getEvaluatedLocation()
+                */
+               public IVariableLocation getEvaluatedLocation() {
+                       return valueLocation;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#getEvaluatedType()
+                */
+               public IType getEvaluatedType() {
+                       return valueType;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#getTypeName()
+                */
+               public String getTypeName() {
+                       evaluateExpression();
+                       if (valueType == null)
+                               if (valueError != null)
+                                       return ""; //$NON-NLS-1$
+                               else
+                                       return ASTEvaluationEngine.UNKNOWN_TYPE;
+                       return engine.getTypeEngine().getTypeName(valueType);
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#hasChildren()
+                */
+               public boolean hasChildren() {
+                       return this.hasChildren;
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#getService()
+                */
+               public Expressions getExpressionsService() {
+                       return Expressions.this;
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.services.IEDCExpression#getExecutor()
+                */
+               public Executor getExecutor() {
+                       return getSession().getExecutor();
+               }
+       
+       }
+
+       /** A basic expression.  */
+       private class ExpressionDMC extends BaseEDCExpressionDMC {
+
+               public ExpressionDMC(IDMContext parent, String expression) {
+                       super(parent, expression);
+               }
+               
+               
+               public ExpressionDMC(IDMContext parent, String expression, String name) {
+                       super(parent, expression, name);
+               }
+               
+               /**
+                * There is no casting on a vanilla expression.
+                * @return <code>null</code>
+                */
+               public CastInfo getCastInfo() {
+                       return null;
+               }
+
+               
+       }
+
+       /** A casted or array-displayed expression.  */
+       private class CastedExpressionDMC extends BaseEDCExpressionDMC implements ICastedExpressionDMContext {
+
+               private final CastInfo castInfo;
+               /** if non-null, interpret result as this type rather than the raw expression's type */
+               private IType castType = null;
+               private IStatus castError;
+
+               public CastedExpressionDMC(IEDCExpression exprDMC, String expression, String name, CastInfo castInfo) {
+                       super(exprDMC, name);
+                       this.castInfo = castInfo;
+                       
+                       String castType = castInfo.getTypeString();
+                       
+                       String castExpression = expression;
+                       
+                       // If changing type, assume it's reinterpret_cast<>. 
+                       // Once we support RTTI, this should be dynamic_cast<> when casting
+                       // class pointers to class pointers.
+                       if (castType != null) {
+                               if (castInfo.getArrayCount() > 0) {
+                                       castType += "[]"; //$NON-NLS-1$
+                                       // Force non-pointer expressions to be pointers.
+                                       exprDMC.evaluateExpression();
+                                       IType exprType = TypeUtils.getStrippedType(exprDMC.getEvaluatedType());
+                                       if (exprType != null) {
+                                               if (!(exprType instanceof IPointerType || exprType instanceof IArrayType)) {
+                                                       expression = "&" + expression; //$NON-NLS-1$
+                                               }
+                                       }
+                               }
+                               castExpression = "reinterpret_cast<" + castType +">(" + expression + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                       } else if (castInfo.getArrayCount() > 0) {
+                               // For arrays, be sure the OperatorSubscript accepts the base type.
+                               // Force non-pointer expressions to be pointers.
+                               exprDMC.evaluateExpression();
+                               IType exprType = TypeUtils.getStrippedType(exprDMC.getEvaluatedType());
+                               if (exprType != null) {
+                                       if (!(exprType instanceof IPointerType || exprType instanceof IArrayType)) {
+                                               // cast to pointer if not already one (cast to array is not valid C/C++ but we support it)
+                                               castExpression = "("  + exprDMC.getTypeName() + "[])&" + expression; //$NON-NLS-1$ //$NON-NLS-2$
+                                       }
+                               }
+                       }
+                       this.expression = castExpression;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#evaluateExpression()
+                */
+               public void evaluateExpression() {
+                       if (castError != null) {
+                               return;
+                       }
+                       
+                       super.evaluateExpression();
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCExpression#getEvaluatedType()
+                */
+               public IType getEvaluatedType() {
+                       if (castType != null)
+                               return castType;
+                       return super.getEvaluatedType();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.debug.service.IExpressions2.ICastedExpressionDMContext#getCastInfo()
+                */
+               public CastInfo getCastInfo() {
+                       return castInfo;
+               }
+       }
+
+       public class ExpressionData implements IExpressionDMData {
+
+               private final IEDCExpression dmc;
+               private String typeName = "";
+
+               public ExpressionData(IEDCExpression dmc) {
+                       this.dmc = dmc;
+                       if (dmc != null)
+                               this.typeName = dmc.getTypeName();
+               }
+
+               public BasicType getBasicType() {
+                       BasicType basicType = BasicType.unknown;
+                       if (dmc == null)
+                               return basicType;
+                       
+                       IType type = dmc.getEvaluatedType();
+                       type = TypeUtils.getStrippedType(type);
+                       if (type instanceof IArrayType) {
+                               basicType = BasicType.array;
+                       }
+                       else if (type instanceof IBasicType) {
+                               basicType = BasicType.basic;
+                       }
+                       else if (type instanceof ICompositeType) {
+                               basicType = BasicType.composite;
+                       }
+                       else if (type instanceof IEnumeration) {
+                               basicType = BasicType.enumeration;
+                       }
+                       else if (type instanceof IPointerType) {
+                               basicType = BasicType.pointer;
+                       }
+                       else if (type instanceof ISubroutineType) {
+                               basicType = BasicType.function;
+                       }
+                       return basicType;
+               }
+
+               public String getEncoding() {
+                       return null;
+               }
+
+               public Map<String, Integer> getEnumerations() {
+                       return null;
+               }
+
+               public String getName() {
+                       if (dmc != null)
+                               return dmc.getName();
+                       else
+                               return ""; //$NON-NLS-1$
+               }
+
+               public IRegisterDMContext getRegister() {
+                       return null;
+               }
+
+               public String getTypeId() {
+                       return TYPEID_INTEGER;
+               }
+
+               public String getTypeName() {
+                       return typeName;
+               }
+
+       }
+
+       protected static class InvalidContextExpressionDMC extends AbstractDMContext implements IExpressionDMContext {
+               private final String expression;
+
+               public InvalidContextExpressionDMC(String sessionId, String expr, IDMContext parent) {
+                       super(sessionId, new IDMContext[] { parent });
+                       expression = expr;
+               }
+
+               @Override
+               public boolean equals(Object other) {
+                       return super.baseEquals(other) && expression == null ? ((InvalidContextExpressionDMC) other)
+                                       .getExpression() == null : expression.equals(((InvalidContextExpressionDMC) other).getExpression());
+               }
+
+               @Override
+               public int hashCode() {
+                       return expression == null ? super.baseHashCode() : super.baseHashCode() ^ expression.hashCode();
+               }
+
+               @Override
+               public String toString() {
+                       return baseToString() + ".invalid_expr[" + expression + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+               }
+
+               public String getExpression() {
+                       return expression;
+               }
+       }
+
+       public class ExpressionDMAddress implements IExpressionDMLocation {
+
+               private final IVariableLocation valueLocation;
+
+               public ExpressionDMAddress(IExpressionDMContext exprContext) {
+                       if (exprContext instanceof IEDCExpression)
+                               valueLocation = ((IEDCExpression) exprContext).getValueLocation();
+                       else
+                               valueLocation = null;
+               }
+
+               public IAddress getAddress() {
+                       if (valueLocation != null) {
+                               IAddress address = valueLocation.getAddress();
+                               if (address != null)
+                                       return address;
+                       }
+                       return new Addr64(BigInteger.ZERO);
+               }
+
+               public int getSize() {
+                       return 4;
+               }
+
+               public String getLocation() {
+                       if (valueLocation instanceof IInvalidVariableLocation) {
+                               return ((IInvalidVariableLocation)valueLocation).getMessage();
+                       }
+                       if (valueLocation == null)
+                               return ""; //$NON-NLS-1$
+                       return valueLocation.getLocationName();
+               }
+
+       }
+
+       public Expressions(DsfSession session) {
+               super(session, new String[] { IExpressions.class.getName(), Expressions.class.getName(), IExpressions2.class.getName() });
+       }
+       
+       public boolean canWriteExpression(IEDCExpression expressionDMC) {
+               EDCLaunch launch = EDCLaunch.getLaunchForSession(getSession().getId());
+               if (launch.isSnapshotLaunch())
+                       return false;
+               IVariableValueConverter converter = getCustomValueConverter(expressionDMC);
+               if (converter != null)
+                       return converter.canEditValue();
+               
+               return !isComposite(expressionDMC);
+       }
+
+       public void canWriteExpression(IExpressionDMContext exprContext, DataRequestMonitor<Boolean> rm) {
+               IEDCExpression expressionDMC = (IEDCExpression) exprContext;
+               rm.setData(canWriteExpression(expressionDMC));
+               rm.done();
+       }
+
+       private boolean isComposite(IEDCExpression expressionDMC) {
+               IType exprType = TypeUtils.getStrippedType(expressionDMC.getEvaluatedType());
+               return exprType instanceof ICompositeType;
+       }
+
+       public IExpressionDMContext createExpression(IDMContext context, String expression) {
+               StackFrameDMC frameDmc = DMContexts.getAncestorOfType(context, StackFrameDMC.class);
+
+               if (frameDmc != null) {
+                       return new ExpressionDMC(frameDmc, expression);
+               }
+               return new InvalidContextExpressionDMC(getSession().getId(), expression, context);
+       }
+       
+       class CastInfoCachedData  {
+
+               private CastInfo info;
+
+               private IType type;
+               private IStatus error;
+               private StackFrameDMC frameDmc;
+
+               public CastInfoCachedData(ExpressionDMC exprDMC, CastInfo info) {
+                       this.info = info;
+                       this.frameDmc = DMContexts.getAncestorOfType(exprDMC, StackFrameDMC.class);
+               }
+               
+               public String getTypeString() {
+                       return info.getTypeString();
+               }
+               
+               public int getArrayStartIndex() {
+                       return info.getArrayStartIndex();
+               }
+               
+               public int getArrayCount() {
+                       return info.getArrayCount();
+               }
+               
+               /**
+                * Get the compiled type
+                * @return the type
+                */
+               public IType getType() {
+                       if (info.getTypeString() == null)
+                               return null;
+                       
+                       if (type == null && error == null) {
+                               if (frameDmc != null) {
+                                       ASTEvaluationEngine engine = new ASTEvaluationEngine(getEDCServicesTracker(), frameDmc, frameDmc.getTypeEngine());
+                                       try {
+                                               IASTTypeId typeId = engine.getCompiledType(info.getTypeString());
+                                               type = engine.getTypeEngine().getTypeForTypeId(typeId);
+                                       } catch (CoreException e) {
+                                               error = e.getStatus();
+                                       }
+                               } else {
+                                       error = EDCDebugger.dsfRequestFailedStatus(EDCServicesMessages.Expressions_CannotCastOutsideFrame, null); 
+                               }
+                       }
+                       return type;
+               }
+               
+               /**
+                * @return the error
+                */
+               public IStatus getError() {
+                       if (type == null && error == null) {
+                               getType();
+                       }
+                       return error;
+               }
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IExpressions2#createCastedExpression(org.eclipse.cdt.dsf.datamodel.IDMContext, java.lang.String, org.eclipse.cdt.dsf.debug.service.IExpressions2.ICastedExpressionDMContext)
+        */
+       public ICastedExpressionDMContext createCastedExpression(IExpressionDMContext exprDMC,
+                       CastInfo castInfo) {
+               
+               // then apply the casting stuff
+               if (exprDMC instanceof IEDCExpression) {
+                       CastedExpressionDMC castedDMC = new CastedExpressionDMC((IEDCExpression) exprDMC, 
+                                       exprDMC.getExpression(), ((IEDCExpression) exprDMC).getName(), castInfo);
+                       return castedDMC;
+               } else {
+                       assert false;
+                       return null;
+               }
+       }
+
+       /*
+       public void createCastedExpression(IDMContext context, String expression, 
+                       ICastedExpressionDMContext castDMC, IArrayCastedExpressionDMContext arrayCastDMC,
+                       DataRequestMonitor<IExpressionDMContext> rm) {
+               
+               // create an ordinary expression...
+               IExpressionDMContext exprDMC = createExpression(context, expression);
+               
+               // then apply the casting stuff
+               if (exprDMC instanceof ExpressionDMC 
+                               && (castDMC == null || castDMC instanceof CastedExpressionDMContext)
+                               && (arrayCastDMC == null || arrayCastDMC instanceof ArrayCastedExpressionDMContext)) {
+                       ExpressionDMC expressionDMC = ((ExpressionDMC) exprDMC);
+                       if (castDMC != null)
+                               expressionDMC.setCastToType((CastedExpressionDMContext) castDMC);
+                       if (arrayCastDMC != null)
+                               expressionDMC.setArrayCast((ArrayCastedExpressionDMContext) arrayCastDMC);
+                       rm.setData(expressionDMC);
+                       rm.done();
+               } else {
+                       assert false;
+                       rm.setStatus(EDCDebugger.dsfRequestFailedStatus("unexpected cast information", null));
+                       rm.done();
+               }
+       }
+       */
+       
+       public void getBaseExpressions(IExpressionDMContext exprContext, DataRequestMonitor<IExpressionDMContext[]> rm) {
+               rm.setData(new IEDCExpression[0]);
+               rm.done();
+       }
+
+       public void getExpressionAddressData(final IExpressionDMContext exprContext, final DataRequestMonitor<IExpressionDMAddress> rm) {
+               asyncExec(new Runnable() {
+                       public void run() {
+                               if (exprContext instanceof IEDCExpression)
+                                       rm.setData(new ExpressionDMAddress(exprContext));
+                               else
+                                       rm.setData(new ExpressionDMAddress(null));
+                               rm.done();
+                       }
+               }, rm);
+       }
+
+       public void getExpressionData(final IExpressionDMContext exprContext, final DataRequestMonitor<IExpressionDMData> rm) {
+               asyncExec(new Runnable() {
+                       public void run() {
+                               if (exprContext instanceof IEDCExpression)
+                                       rm.setData(new ExpressionData((IEDCExpression) exprContext));
+                               else
+                                       rm.setData(new ExpressionData(null));
+                               rm.done();
+                       }
+               }, rm);
+       }
+
+       public void getSubExpressionCount(final IExpressionDMContext exprContext, final DataRequestMonitor<Integer> rm) {
+               asyncExec(new Runnable() {
+                       public void run() {
+                               // handle array casts
+                               CastInfo cast = null;
+                               if (exprContext instanceof IEDCExpression && (cast = ((IEDCExpression) exprContext).getCastInfo()) != null) { 
+                                       if (cast.getArrayCount() > 0) {
+                                               if (((IEDCExpression)exprContext).getEvaluationError() != null) {
+                                                       rm.setData(0);
+                                                       rm.done();
+                                                       return;
+                                               }
+                                               rm.setData(cast.getArrayCount());
+                                               rm.done();
+                                               return;
+                                       }
+                               }
+
+                               if (!(exprContext instanceof IEDCExpression)) {
+                                       rm.setData(0);
+                                       rm.done();
+                                       return;
+                               }
+
+                               IEDCExpression expr = (IEDCExpression) exprContext;
+
+                               // if expression has no evaluated value, then it has not yet been evaluated
+                               if (expr.getEvaluatedValue() == null && expr.getEvaluatedValueString() != null) {
+                                       expr.evaluateExpression();
+                               }
+
+                               IType exprType = TypeUtils.getStrippedType(expr.getEvaluatedType());
+                               
+                               // to expand it, it must either be a pointer, a reference to an aggregate,
+                               // or an aggregate
+                               boolean pointerType = exprType instanceof IPointerType;
+                               boolean referenceType = exprType instanceof IReferenceType;
+                               IType pointedTo = null;
+                               if (referenceType)
+                                       pointedTo = TypeUtils.getStrippedType(((IReferenceType) exprType).getType());
+                               
+                               if (!(exprType instanceof IAggregate) && !pointerType &&
+                                       !(referenceType && (pointedTo instanceof IAggregate || pointedTo instanceof IPointerType))) {
+                                       rm.setData(0);
+                                       rm.done();
+                                       return;
+                               }
+                               
+                               ITypeContentProvider customProvider = 
+                                       FormatExtensionManager.instance().getTypeContentProvider(exprType);
+                               if (customProvider != null) {
+                                       try {
+                                               rm.setData(customProvider.getChildCount(expr));
+                                               rm.done();
+                                               return;
+                                       } catch (Throwable e) {
+                                       }
+                               }
+
+                               // TODO: maybe cache these subexpressions; they are just requested again in #getSubExpressions()
+                               getSubExpressions(exprContext, new DataRequestMonitor<IExpressions.IExpressionDMContext[]>(
+                                               getExecutor(), rm) {
+                                       /* (non-Javadoc)
+                                        * @see org.eclipse.cdt.dsf.concurrent.RequestMonitor#handleSuccess()
+                                        */
+                                       @Override
+                                       protected void handleSuccess() {
+                                               rm.setData(getData().length);
+                                               rm.done();
+                                       }
+                               });
+                       }
+               }, rm);
+       }
+
+       public void getSubExpressions(final IExpressionDMContext exprContext, final DataRequestMonitor<IExpressionDMContext[]> rm) {
+               asyncExec(new Runnable() {
+                       public void run() {
+                               if (!(exprContext instanceof IEDCExpression) || ((IEDCExpression) exprContext).getFrame() == null) {
+                                       rm.setData(new IEDCExpression[0]);
+                                       rm.done();
+                                       return;
+                               }
+
+                               IEDCExpression expr = (IEDCExpression) exprContext;
+
+                               // if expression has no evaluated value, then it has not yet been evaluated
+                               if (expr.getEvaluatedValue() == null && expr.getEvaluatedValueString() != null) {
+                                       expr.evaluateExpression();
+                               }
+
+                               StackFrameDMC frame = (StackFrameDMC) expr.getFrame();
+                               IType exprType = TypeUtils.getStrippedType(expr.getEvaluatedType());
+
+                               // if casted to an array, convert thusly
+                       CastInfo castInfo = expr.getCastInfo();
+                       if (castInfo != null && castInfo.getArrayCount() > 0) {
+                               try {
+                                       exprType = frame.getTypeEngine().convertToArrayType(exprType, castInfo.getArrayCount());
+                               } catch (CoreException e) {
+                                       rm.setStatus(e.getStatus());
+                                       rm.done();
+                                       return;
+                               }
+                       }
+                       
+                               
+                               // to expand it, it must either be a pointer, a reference to an aggregate,
+                               // or an aggregate
+                               boolean pointerType = exprType instanceof IPointerType;
+                               boolean referenceType = exprType instanceof IReferenceType;
+                               IType pointedTo = null;
+                               if (referenceType) {
+                                       pointedTo = TypeUtils.getStrippedType(((IReferenceType) exprType).getType());
+                                       exprType = pointedTo;
+                               }
+                               
+                               if (!(exprType instanceof IAggregate) && !pointerType &&
+                                       !(referenceType && (pointedTo instanceof IAggregate || pointedTo instanceof IPointerType))) {
+                                       rm.setData(new IEDCExpression[0]);
+                                       rm.done();
+                                       return;
+                               }
+                               
+                               ITypeContentProvider customProvider = 
+                                       FormatExtensionManager.instance().getTypeContentProvider(exprType);
+                               if (customProvider != null) {
+                                       getSubExpressions(expr, frame, exprType, customProvider, rm);
+                               }
+                               else
+                                       getSubExpressions(expr, rm);
+                       }
+               }, rm);
+       }
+
+       public void getSubExpressions(final IExpressionDMContext exprContext, final int startIndex_, final int length_,
+                       final DataRequestMonitor<IExpressionDMContext[]> rm) {
+               asyncExec(new Runnable() {
+                       public void run() {
+                               getSubExpressions(exprContext, new DataRequestMonitor<IExpressionDMContext[]>(getExecutor(), rm) {
+                                       @Override
+                                       protected void handleSuccess() {
+                                               IExpressionDMContext[] allExprs = getData();
+                                               if (startIndex_ == 0 && length_ >= allExprs.length) {
+                                                       rm.setData(allExprs);
+                                                       rm.done();
+                                               } else {
+                                                       int startIndex = startIndex_, length = length_;
+                                                       if (startIndex > allExprs.length) {
+                                                               startIndex = allExprs.length;
+                                                               length = 0;
+                                                       } else if (startIndex + length > allExprs.length) {
+                                                               length = allExprs.length - startIndex;
+                                                               if (length < 0)
+                                                                       length = 0;
+                                                       }
+                                                               
+                                                       IExpressionDMContext[] result = new IExpressionDMContext[length];
+                                                       System.arraycopy(allExprs, startIndex, result, 0, length);
+                                                       rm.setData(result);
+                                                       rm.done();
+                                               }
+                                       }
+                               });
+                       }
+               }, rm);
+       }
+
+       private void getSubExpressions(final IEDCExpression expr, final StackFrameDMC frame, 
+                       final IType exprType, final ITypeContentProvider customProvider,
+                       final DataRequestMonitor<IExpressionDMContext[]> rm) {
+
+               List<IExpressionDMContext> children = new ArrayList<IExpressionDMContext>();
+               Iterator<IExpressionDMContext> childIterator;
+               try {
+                       childIterator = customProvider.getChildIterator(expr);
+                       while (childIterator.hasNext() && !rm.isCanceled()) {
+                               children.add(childIterator.next());
+                       }
+                       rm.setData(children.toArray(new IExpressionDMContext[children.size()]));
+                       rm.done();
+               } catch (CoreException e) {
+                       // Checked exception. But we don't want to pass the error up as it
+                       // would make the variable (say, a structure) not expandable on UI. 
+                       // Just resort to the normal formatting.  
+                       getSubExpressions(expr, rm);
+               } catch (Throwable e) {
+                       // unexpected error. log it.
+                       EDCDebugger.getMessageLogger().logError(
+                                       EDCServicesMessages.Expressions_ErrorInVariableFormatter + customProvider.getClass().getName(), e);
+                       
+                       // default to normal formatting
+                       getSubExpressions(expr, rm);
+               }
+       }
+
+       private void getSubExpressions(final IEDCExpression expr, 
+                       final DataRequestMonitor<IExpressionDMContext[]> rm) {
+               rm.setData(getLogicalSubExpressions(expr));
+               rm.done();
+       }
+       
+       /**
+        * Get the logical subexpressions for the given expression context.  We want
+        * to skip unnecessary nodes, e.g., a pointer to a composite, and directly
+        * show the object contents.
+        * @param expr the expression from which to start
+        * @return array of children
+        */
+       public IEDCExpression[] getLogicalSubExpressions(IEDCExpression expr) {
+
+               IType exprType = TypeUtils.getUnRefStrippedType(expr.getEvaluatedType());
+               
+               // cast to array?
+               CastInfo castInfo = expr.getCastInfo();
+               if (castInfo != null && castInfo.getArrayCount() > 0) {
+                       
+                       String exprName = expr.getExpression();
+                       
+                       // in case of casts, need to resolve that before dereferencing, so be safe
+                       if (exprName.contains("(")) //$NON-NLS-1$
+                               exprName = '(' + exprName + ')';
+
+                       long lowerBound = castInfo.getArrayStartIndex();
+                       long count = castInfo.getArrayCount();
+                       
+                       List<IEDCExpression> arrayChildren = new ArrayList<IEDCExpression>();
+                       for (int i = 0; i < count; i++) {
+                               String arrayElement = "[" + (i + lowerBound) + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+                               IEDCExpression newExpr = new ExpressionDMC(expr.getFrame(), (exprName + arrayElement),
+                                               expr.getName() + arrayElement);
+                               IEDCExpression exprChild = newExpr; //$NON-NLS-1$ //$NON-NLS-2$
+                               if (exprChild != null) {
+                                       arrayChildren.add(exprChild);
+                               }
+                       }
+
+                       return arrayChildren.toArray(new IEDCExpression[arrayChildren.size()]);
+               } 
+               
+               if (exprType instanceof IPointerType) {
+                       // automatically dereference a pointer
+                       String exprName = expr.getExpression();
+                       IType typePointedTo = TypeUtils.getStrippedType(exprType.getType());
+
+                       // If expression name already starts with "&" (e.g. "&struct"), indirect it first
+                       boolean indirected = false;
+                       
+                       IEDCExpression exprChild;
+                       
+                       if (exprName.startsWith("&")) { //$NON-NLS-1$
+                               exprName = exprName.substring(1);
+                               IEDCExpression newExpr = new ExpressionDMC(expr.getFrame(), exprName);
+                               exprChild = newExpr;
+                               indirected = true;
+                       } 
+                       else {
+                               // avoid dereferencing void pointer
+                               if (typePointedTo instanceof ICPPBasicType 
+                                               && ((ICPPBasicType) typePointedTo).getBaseType() == ICPPBasicType.t_void) {
+                                       return new IEDCExpression[0];
+                               }
+                               
+                               // do not dereference null either
+                               if (expr.getEvaluatedValue() != null && expr.getEvaluatedValue().intValue() == 0)
+                                       return new IEDCExpression[0];
+                               IEDCExpression newExpr = new ExpressionDMC(expr.getFrame(), ("*" + exprName), "*" + expr.getName()); //$NON-NLS-1$ //$NON-NLS-2$
+                                       
+                               // a pointer type has one child
+                               exprChild = newExpr; //$NON-NLS-1$
+                       }
+                       
+                       return doGetLogicalSubExpressions(exprChild, typePointedTo, indirected);
+               } 
+               else if (exprType instanceof IReferenceType) {
+                       // and bypass a reference
+                       
+                       IType typePointedTo = TypeUtils.getStrippedType(exprType.getType());
+                       return doGetLogicalSubExpressions(expr, typePointedTo, false);
+               }else {
+                       // normal aggregate, just do it
+                       return doGetLogicalSubExpressions(expr, exprType, false);
+               }
+               
+       }
+
+       /**
+        * Get the logical subexpressions for the given expression context and string 
+        * @param expr the expression from which to start
+        * @param exprType the type in which to consider the expression
+        * @param indirected if true, the expression was already indirected, as opposed to what the expression says
+        * @return
+        */
+       private IEDCExpression[] doGetLogicalSubExpressions(IEDCExpression expr, IType exprType, boolean indirected) {
+               ArrayList<IEDCExpression> exprList = new ArrayList<IEDCExpression>();
+               IEDCExpression exprChild;
+
+               String expression = expr.getExpression();
+               
+               // in case of casts, need to resolve that before dereferencing, so be safe
+               if (expression.contains("(")) //$NON-NLS-1$
+                       expression = '(' + expression + ')';
+
+               /*
+               // cast to array?
+               CastInfo castInfo = expr.getCastInfo();
+               if (castInfo != null && castInfo.getArrayCount() > 0) {
+                       long lowerBound = castInfo.getArrayStartIndex();
+                       long count = castInfo.getArrayCount();
+                       for (int i = 0; i < count; i++) {
+                               exprChild = createDerivedExpression(expr, exprName + "[" + (i + lowerBound) + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+                               if (exprChild != null) {
+                                       exprList.add(exprChild);
+                               }
+                       }
+               
+               } 
+               else*/ if (exprType instanceof ICompositeType) {
+                       // an artifact of following a pointer to a structure is that the
+                       // name starts with '*'
+                       if (expression.startsWith("*")) { //$NON-NLS-1$
+                               if (expression.startsWith("**"))
+                                       expression = "(" + expression.substring(1) + ")->"; //$NON-NLS-1$
+                               else
+                                       expression = expression.substring(1) + "->"; //$NON-NLS-1$
+                       } else {
+                               expression = expression + '.'; //$NON-NLS-1$
+                       }
+
+                       // for each field, evaluate an expression, then shorten the name
+                       ICompositeType compositeType = (ICompositeType) exprType;
+
+                       for (IField field : compositeType.getFields()) {
+                               String fieldName = field.getName();
+                               if (fieldName.length() == 0) {
+                                       // This makes an invalid expression
+                                       // The debug info provider should have filtered out or renamed such fields
+                                       assert false;
+                                       continue;
+                               }
+                               exprChild = new ExpressionDMC(expr.getFrame(), expression + fieldName, fieldName);
+                               if (exprChild != null) {
+                                       exprList.add(exprChild);
+                               }
+                       }
+
+                       for (IInheritance inherited : compositeType.getInheritances()) {
+                               String inheritedName = inherited.getName();
+                               if (inheritedName.length() == 0) {
+                                       // This makes an invalid expression
+                                       // The debug info provider should have filtered out or renamed such fields
+                                       assert false;   // couldn't this be the case for an anonymous member, like a union?
+                               } else if (!inheritedName.contains("<")) {
+                                       exprChild = new ExpressionDMC(expr.getFrame(), expression + inheritedName, inheritedName);
+                                       if (exprChild != null) {
+                                               exprList.add(exprChild);
+                                       }
+                               } else {
+                                       IType inheritedType = inherited.getType(); 
+                                       if (inheritedType instanceof ICompositeType) {
+                                               for (IField field : ((ICompositeType)inheritedType).getFields()) {
+                                                       String fieldName = field.getName();
+                                                       if (fieldName.length() == 0) {
+                                                               // This makes an invalid expression
+                                                               // The debug info provider should have filtered out or renamed such fields
+                                                               assert false;
+                                                               continue;
+                                                       }
+                                                       exprChild = new ExpressionDMC(expr.getFrame(), expression + fieldName, fieldName);
+                                                       if (exprChild != null) {
+                                                               exprList.add(exprChild);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       
+               } 
+               else if (exprType instanceof IArrayType) {
+                       IArrayType arrayType = (IArrayType) exprType;
+
+                       if (arrayType.getBoundsCount() > 0) {
+                               long lowerBound = expr.getCastInfo() != null && expr.getCastInfo().getArrayCount() > 0 
+                                       ? expr.getCastInfo().getArrayStartIndex() : 0;
+                               long upperBound = arrayType.getBound(0).getBoundCount();
+                               if (upperBound == 0)
+                                       upperBound = 1;
+                               for (int i = 0; i < upperBound; i++) {
+                                       String arrayElementName = "[" + (i + lowerBound) + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+                                       IEDCExpression newExpr = new ExpressionDMC(expr.getFrame(), expression + arrayElementName,
+                                                       expr.getName() + arrayElementName); 
+                                       exprChild = newExpr;
+                                       if (exprChild != null) {
+                                               exprList.add(exprChild);
+                                       }
+                               }
+                       }
+               } 
+               else if (exprType instanceof IArrayDimensionType) {
+                       IArrayDimensionType arrayDimensionType = (IArrayDimensionType) exprType;
+                       IArrayType arrayType = arrayDimensionType.getArrayType();
+
+                       if (arrayType.getBoundsCount() > arrayDimensionType.getDimensionCount()) {
+                               long lowerBound = expr.getCastInfo() != null && expr.getCastInfo().getArrayCount() > 0 
+                               ? expr.getCastInfo().getArrayStartIndex() : 0;
+                               long upperBound = arrayType.getBound(arrayDimensionType.getDimensionCount()).getBoundCount();
+                               for (int i = 0; i < upperBound; i++) {
+                                       String arrayElement = "[" + (i + lowerBound) + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+                                       IEDCExpression newExpr = new ExpressionDMC(expr.getFrame(), expression + arrayElement,
+                                                       expr.getName() + arrayElement); 
+                                       exprChild = newExpr;
+                                       if (exprChild != null) {
+                                               exprList.add(exprChild);
+                                       }
+                               }
+                       }
+               } 
+               else {
+                       // nothing interesting
+                       exprList.add(expr);
+               }
+
+               return exprList.toArray(new IEDCExpression[exprList.size()]);
+       }
+
+       @Immutable
+    private static class ExpressionChangedDMEvent extends AbstractDMEvent<IExpressionDMContext> implements IExpressionChangedDMEvent {
+        ExpressionChangedDMEvent(IExpressionDMContext expression) {
+            super(expression);
+        }
+    }
+
+       public void writeExpression(final IExpressionDMContext exprContext, final String expressionValue, final String formatId, final RequestMonitor rm) {
+
+               asyncExec(new Runnable() {
+                       public void run() {
+                               IEDCExpression expressionDMC = (IEDCExpression) exprContext;
+                               if (isComposite(expressionDMC)) {
+                                       rm.setStatus(EDCDebugger.dsfRequestFailedStatus(EDCServicesMessages.Expressions_CannotModifyCompositeValue, null));
+                                       rm.done();
+                                       return;
+                               }
+
+                               IType exprType = TypeUtils.getStrippedType(expressionDMC.getEvaluatedType());
+
+                               // first try to get value by format as BigInteger
+                               Number number = NumberFormatUtils.parseIntegerByFormat(expressionValue, formatId);
+                       if (number == null) {
+                               IEDCExpression temp = (IEDCExpression) createExpression(expressionDMC.getFrame(), expressionValue);
+                               temp.evaluateExpression();
+                                       number = temp.getEvaluatedValue();
+
+                               if (number == null) {
+                                       rm.setStatus(EDCDebugger.dsfRequestFailedStatus(EDCServicesMessages.Expressions_CannotParseExpression, null));
+                                       rm.done();
+                                       return;
+                               }
+                       }
+                       
+                       BigInteger value = null;
+                               try {
+                                       value = MemoryUtils.convertValueToMemory(exprType, number);
+                               } catch (CoreException e) {
+                                       rm.setStatus(e.getStatus());
+                                       rm.done();
+                                       return;
+                               }
+                       
+                       IVariableLocation variableLocation = expressionDMC.getValueLocation();
+                       if (variableLocation == null) {
+                               rm.setStatus(EDCDebugger.dsfRequestFailedStatus(EDCServicesMessages.Expressions_ExpressionNoLocation, null));
+                                       rm.done();
+                                       return;
+                       }
+                               
+                       try {
+                               variableLocation.writeValue(exprType.getByteSize(), value);
+                               getSession().dispatchEvent(new ExpressionChangedDMEvent(exprContext), getProperties());
+                               } catch (CoreException e) {
+                                       rm.setStatus(e.getStatus());
+                               }
+                       
+                               rm.done();
+                       }
+               }, rm);
+
+       }
+
+       public void getAvailableFormats(IFormattedDataDMContext formattedDataContext, DataRequestMonitor<String[]> rm) {
+               rm.setData(new String[] { IFormattedValues.NATURAL_FORMAT, IFormattedValues.DECIMAL_FORMAT, 
+                               IFormattedValues.HEX_FORMAT, IFormattedValues.OCTAL_FORMAT, IFormattedValues.BINARY_FORMAT });
+               rm.done();
+       }
+
+       public void getFormattedExpressionValue(final FormattedValueDMContext formattedDataContext,
+                       final DataRequestMonitor<FormattedValueDMData> rm) {
+               asyncExec(new Runnable() {
+                       public void run() {
+                               try {
+                                       rm.setData(getFormattedExpressionValue(formattedDataContext));
+                                       rm.done();
+                               } catch (CoreException ce) {
+                                       rm.setStatus(ce.getStatus());
+                                       rm.done();
+                                       return;
+                               }
+                       }
+               }, rm);
+       }
+
+       public String getExpressionValueString(IExpressionDMContext expression, String format) throws CoreException {
+               FormattedValueDMContext formattedDataContext = getFormattedValueContext(expression, format);
+               FormattedValueDMData formattedValue = getFormattedExpressionValue(formattedDataContext);
+               
+               return formattedValue != null ? formattedValue.getFormattedValue() : "";
+       }
+
+       public FormattedValueDMData getFormattedExpressionValue(FormattedValueDMContext formattedDataContext) throws CoreException {
+               IDMContext idmContext = formattedDataContext.getParents()[0];
+               FormattedValueDMData formattedValue = null;
+               IEDCExpression exprDMC = null;
+
+               if (idmContext instanceof IEDCExpression) {
+                       exprDMC = (IEDCExpression) formattedDataContext.getParents()[0];
+
+                       exprDMC.evaluateExpression();
+                       
+                       if (exprDMC != null && exprDMC.getEvaluationError() != null) {
+                               throw new CoreException(exprDMC.getEvaluationError());
+                       }
+                       
+                       formattedValue = exprDMC.getFormattedValue(formattedDataContext); // must call this to get type
+                       
+                       if (formattedDataContext.getFormatID().equals(IFormattedValues.NATURAL_FORMAT))
+                       {
+                               IVariableValueConverter customConverter = getCustomValueConverter(exprDMC);
+                               if (customConverter != null) {
+                                       FormattedValueDMData customFormattedValue = null;
+                                       try {
+                                               customFormattedValue = new FormattedValueDMData(customConverter.getValue(exprDMC));
+                                               formattedValue = customFormattedValue;
+                                       }
+                                       catch (Throwable t) {
+                                               // CoreExeception will just propagate out, so this is for
+                                               // other unexpected errors, usually bug in the formatter. Log it 
+                                               // so that user will be able to see and report the bug. 
+                                               // Meanwhile, default to normal formatting so that user won't see 
+                                               // such error in Variable UI.
+                                               EDCDebugger.getMessageLogger().logError(
+                                                               EDCServicesMessages.Expressions_ErrorInVariableFormatter + customConverter.getClass().getName(), t);
+                                       }
+                               }
+                       }
+               } else
+                       formattedValue = new FormattedValueDMData(""); //$NON-NLS-1$
+               
+               return formattedValue;
+       }
+
+       private IVariableValueConverter getCustomValueConverter(IEDCExpression exprDMC) {
+               IType exprType = TypeUtils.getUnRefStrippedType(exprDMC.getEvaluatedType());
+               return FormatExtensionManager.instance().getVariableValueConverter(exprType);
+       }
+
+       public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext formattedDataContext,
+                       String formatId) {
+               return new FormattedValueDMContext(this, formattedDataContext, formatId);
+       }
+
+       public void getModelData(IDMContext context, DataRequestMonitor<?> rm) {
+       }
+
+       public String getExpressionValue(IExpressionDMContext expression)
+       {
+               final StringBuffer holder = new StringBuffer();
+               FormattedValueDMContext formattedValueContext = getFormattedValueContext(expression, IFormattedValues.NATURAL_FORMAT);                                  
+               getFormattedExpressionValue(formattedValueContext, new DataRequestMonitor<FormattedValueDMData>(ImmediateExecutor.getInstance(), null) {
+                       @Override
+                       protected void handleSuccess() {
+                               holder.append(this.getData().getFormattedValue());
+                       }
+
+                       @Override
+                       protected void handleFailure() {
+                               // RequestMonitor would by default log any error if it's not explicitly 
+                               // handled. But we don't want to log those expected errors (checked exceptions)
+                               // in such case as creating snapshot. Hence this dummy handler...02/17/10
+                               
+                               // DO nothing.
+                       }
+                       
+                       
+               });
+               return holder.toString();
+       }
+
+       public void loadExpressionValues(IExpressionDMContext expression, int depth)
+       {
+               loadExpressionValues(expression, new Integer[] {depth});
+       }
+
+       private void loadExpressionValues(IExpressionDMContext expression, final Integer[] depth)
+       {
+               getExpressionValue(expression);
+               if (depth[0] > 0)
+               {
+                       getSubExpressions(expression, new DataRequestMonitor<IExpressions.IExpressionDMContext[]>(ImmediateExecutor.getInstance(), null) {
+
+                               @Override
+                               protected void handleSuccess() {
+                                       depth[0] = depth[0] - 1;
+                                       IExpressions.IExpressionDMContext[] subExpressions = getData();
+                                       for (IExpressionDMContext iExpressionDMContext : subExpressions) {
+                                               loadExpressionValues(iExpressionDMContext, depth);
+                                       }
+                               }});
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/INoop.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/INoop.java
new file mode 100644 (file)
index 0000000..0d48b35
--- /dev/null
@@ -0,0 +1,36 @@
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import org.eclipse.cdt.debug.edc.services.IEDCService;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+
+/**
+ * A dummy DSF service used for testing.
+ */
+public interface INoop extends IEDCService {
+       /** Simply sticks a boolean in the given RM */
+       void noop(IDMContext whatever, DataRequestMonitor<Boolean> rm);
+       
+       /**
+        * Simply sticks a boolean in the given RM after 10 seconds have elapsed.
+        * The sleep is not done on the DSF executor thread, of course
+        */
+       void longNoop(IDMContext whatever, DataRequestMonitor<Boolean> rm);
+
+       /**
+        * This service simply loops for [duration] seconds, asking for the service
+        * tracker every second and trying to use it to get a service. It's used in
+        * a shutdown test to validate that threads in the EDC thread pool are given
+        * a chance to complete before the DSF session moves forward with its
+        * shutdown. If session shutdown didn't wait, then this service would end up
+        * encountering either a null pointer exception or an exception due to the
+        * attempted use of a disposed tracker.
+        * 
+        * @param duration
+        *            the number of seconds to loop
+        * @param rm
+        *            not used but included for consistency
+        */
+       void longNoopUsingServiceTracker(int duration, RequestMonitor rm);
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/LineEntryMapper.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/LineEntryMapper.java
new file mode 100644 (file)
index 0000000..932041d
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.EDCAddressRange;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider;
+import org.eclipse.cdt.debug.edc.symbols.IModuleLineEntryProvider;
+import org.eclipse.cdt.dsf.debug.service.IModules.AddressRange;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Utilities for mapping source to addresses and vice versa.
+ */
+public class LineEntryMapper {
+
+       private static final int toEOF = -1;
+
+       /**
+        * Get the link-time address ranges starting at the given source location.  
+        * There may be more than one, e.g., in template expansions, static functions
+        * declared in headers, inlined functions, etc.  Or, of course, someone may
+        * declare multiple functions on one line.
+        * @path sourceFile the absolute path to the source file
+        * @param line the line number (1-based) 
+        * @return the unmodifiable list of link-time addresses which start at the given line, possibly empty,
+        * will be null if the source file is not used by this module.
+        */
+       public static Collection<AddressRange> getAddressRangesAtSource(
+                       IModuleLineEntryProvider moduleLineEntryProvider,
+                       IPath sourceFile,
+                       int line) {
+               Collection<AddressRange> range = getAddressRangesAtSource(moduleLineEntryProvider, sourceFile, line, line);
+               if (range != null && range.isEmpty()) {
+                       range = getAddressRangesAtSource(moduleLineEntryProvider, sourceFile, line, toEOF);
+               }
+               return range;
+       }
+
+       /**
+        * The public version of this function acts as a wrapper, allowing the original algorithm
+        * to try all fileProviders first, and if that fails, to try to find the next line.
+        * The use case in the original case is to be precise about inline/template situations.
+        * The use case in the new version of the call is to set a breakpoint on first available line
+        * in case the user has chosen to set a breakpoint on a line without LNT information.
+        * @path sourceFile the absolute path to the source file
+        * @param startLine the line number (1-based) 
+        * @param endLine the line number (1-based) 
+        * @return the unmodifiable list of link-time addresses which start at the given line, possibly empty,
+        * will be null if the source file is not used by this module.
+        */
+       private static Collection<AddressRange> getAddressRangesAtSource(
+                       IModuleLineEntryProvider moduleLineEntryProvider,
+                       IPath sourceFile,
+                       int startLine,
+                       int endLine) {
+               Collection<? extends ILineEntryProvider> fileProviders = 
+                       moduleLineEntryProvider.getLineEntryProvidersForFile(sourceFile);
+               if (fileProviders.isEmpty())
+                       return null;
+
+               int lastColumn = -1;
+               IPath lastFile = null;
+               int bestLine = endLine;
+
+               List<EDCAddressRange> addrRanges = null;
+               for (ILineEntryProvider fileProvider : fileProviders) {
+                       
+                       Collection<ILineEntry> entries = fileProvider.getLineEntriesForLines(sourceFile, startLine, endLine);
+                       if (addrRanges == null && !entries.isEmpty())
+                               addrRanges = new ArrayList<EDCAddressRange>();
+                       
+                       for (ILineEntry entry : entries) {
+
+                               int entryLine = entry.getLineNumber();
+
+                               if (entryLine < bestLine && addrRanges != null) {
+                                       addrRanges.clear();
+                                       bestLine = entryLine;
+                               } 
+                               else if (bestLine == toEOF) {
+                                       bestLine = entryLine;
+                               }
+                               else if (entryLine > bestLine) {
+                                       break;  // assume entries sorted; go onto the next fileProvider
+                               }
+                               // else (entryLine == bestLine) // implied
+
+                               /*
+                                * when there is more than one line mapping for the source line,
+                                * see if it makes sense to merge the line entries into the same
+                                * address range, or keep different address ranges. examples of
+                                * when this might happen are when there are multiple logical
+                                * code segments for the same source line, but in different
+                                * columns. in this case it makes sense to merge these into one
+                                * address range. for templates and inline functions however,
+                                * the column will be the same. for these cases it makes sense
+                                * to keep the address ranges separate.
+                                */
+                               IPath entryPath = entry.getFilePath();
+                               int entryColumn = entry.getColumnNumber();
+                               if (addrRanges != null)
+                               {
+                                       if (addrRanges.isEmpty() || !entryPath.equals(lastFile) || lastColumn == entryColumn) {
+                                               addrRanges.add(new EDCAddressRange(entry.getLowAddress(), entry.getHighAddress()));
+                                       } else {
+                                               EDCAddressRange range = addrRanges.remove(addrRanges.size() - 1);
+                                               range.setEndAddress(entry.getHighAddress());
+                                               addrRanges.add(range);
+                                       }
+                               }
+                               lastColumn = entryColumn;
+                               lastFile = entryPath;
+                       }
+               }
+               
+               if (addrRanges == null)
+                       return Collections.emptyList();
+               
+               List<? extends AddressRange> returnRanges = addrRanges;
+               return Collections.unmodifiableCollection(returnRanges);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Memory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Memory.java
new file mode 100644 (file)
index 0000000..5c0dffa
--- /dev/null
@@ -0,0 +1,471 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+import org.eclipse.cdt.debug.edc.services.IDSFServiceUsingTCF;
+import org.eclipse.cdt.debug.edc.services.IEDCDMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCExecutionDMC;
+import org.eclipse.cdt.debug.edc.services.IEDCMemory;
+import org.eclipse.cdt.debug.edc.snapshot.IAlbum;
+import org.eclipse.cdt.debug.edc.snapshot.ISnapshotContributor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionChangedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.debug.core.model.MemoryByte;
+import org.eclipse.tm.tcf.protocol.IService;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class Memory extends AbstractEDCService implements IEDCMemory, ICachingService, ISnapshotContributor,
+               IDSFServiceUsingTCF  {
+
+       private org.eclipse.tm.tcf.services.IMemory tcfMemoryService;
+       private Map<String, MemoryCache> memoryCaches;
+       private long tcfTimeout;
+
+       private class MemoryChangedEvent extends AbstractDMEvent<IMemoryDMContext> implements IMemoryChangedEvent {
+               IAddress[] addresses;
+
+               public MemoryChangedEvent(IMemoryDMContext context, IAddress[] addresses) {
+                       super(context);
+                       this.addresses = addresses;
+               }
+
+               public IAddress[] getAddresses() {
+                       return addresses;
+               }
+       }
+
+       public Memory(DsfSession session) {
+               super(session, new String[] { IEDCMemory.class.getName(), IMemory.class.getName(), Memory.class.getName(),
+                               ISnapshotContributor.class.getName() });
+               setTCFTimeout(15 * 1000); // Fifteen seconds
+       }
+
+       private MemoryCache getMemoryCache(IMemoryDMContext memoryDMC) {
+               assert memoryDMC instanceof IEDCDMContext;
+               MemoryCache cache = memoryCaches.get(((IEDCDMContext) memoryDMC).getID());
+               if (cache == null) {
+                       cache = new MemoryCache(getTargetEnvironmentService().getMemoryCacheMinimumBlockSize());
+                       memoryCaches.put(((IEDCDMContext) memoryDMC).getID(), cache);
+               }
+               return cache;
+       }
+
+       @Override
+       protected void doInitialize(RequestMonitor requestMonitor) {
+               super.doInitialize(requestMonitor);
+
+               // create memory cache
+               memoryCaches = new HashMap<String, MemoryCache>();
+
+               getSession().addServiceEventListener(this, null);
+       }
+
+       public MemoryByte[] getMemory(final IMemoryDMContext context, final IAddress address, final long offset,
+                       final int word_size, final int count) throws CoreException {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { address.toHexAddressString(), offset, word_size, count })); }
+
+               // Validate the context
+               if (context == null) {
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INTERNAL_ERROR,
+                                                       "Unknown context type", null)); //$NON-NLS-1$);
+               }
+
+               // Validate the word size
+               if (word_size < 1) {
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, NOT_SUPPORTED,
+                                       "Word size not supported (< 1)", null)); //$NON-NLS-1$
+               }
+
+               // Validate the byte count
+               if (count < 0) {
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+                                       "Invalid word count (< 0)", null)); //$NON-NLS-1$
+               }
+
+               // everything OK
+
+               // NOTE: We normalize word_size and count to read 1-byte words for this implementation
+               MemoryByte[] memoryBytes = getMemoryCache(context).getMemory(tcfMemoryService, context, address.add(offset), 1, count * word_size,
+                               getTCFTimeout());
+               // hide breakpoints inserted in the memory by debugger
+               Breakpoints bpService = getService(Breakpoints.class);
+               bpService.removeBreakpointFromMemoryBuffer(address.add(offset), memoryBytes);
+               if (RunControl.timeStepping())
+                       System.out.println("Time since stepping start: " + 
+                               ((System.currentTimeMillis() - RunControl.getSteppingStartTime()) / 1000.0));
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               return memoryBytes;
+       }
+
+       public IStatus getMemory(IEDCExecutionDMC context, IAddress address,
+                       ArrayList<MemoryByte> memBuffer, int count, int word_size) {
+               try {
+                       MemoryByte[] memArray = getMemory(context, address, 0, count, word_size);
+                       memBuffer.addAll(Arrays.asList(memArray));
+               } catch (CoreException e) {
+                       return new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INTERNAL_ERROR,
+                                       "Error reading memory from: " + address.toHexAddressString(), null);
+               }
+               return Status.OK_STATUS;
+       }
+
+       public void flushCache(IDMContext context) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { context })); }
+
+               if (isSnapshot())
+                       return;
+
+               if (context == null) {
+                       // reset every cache in each context
+                       for (String key : memoryCaches.keySet()) {
+                               memoryCaches.get(key).reset();
+                       }
+               } else {
+                       IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(context, IMemoryDMContext.class);
+                       if (memoryCaches.containsKey(((IEDCDMContext) memoryDMC).getID())) {
+                               // We do not want to use the call to getMemoryCache() here.
+                               // This is because:
+                               // 1- if there is not an entry already , we do not want to
+                               // automatically
+                               // create one, just to call reset() on it.
+                               // 2- if memoryDMC == null, we do not want to create a cache
+                               // entry for which the key is 'null'
+                               memoryCaches.get(((IEDCDMContext) memoryDMC).getID()).reset();
+                       }
+               }
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       public IStatus setMemory(IMemoryDMContext context, IAddress address, int word_size, int count, byte[] buffer) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { address.toHexAddressString(), count })); }
+
+               final IStatus[] ret = new IStatus[] { Status.OK_STATUS };
+
+               setMemory(context, address, 0, word_size, count, buffer, new RequestMonitor(ImmediateExecutor
+                               .getInstance(), null) {
+
+                       @Override
+                       protected void handleFailure() {
+                               ret[0] = getStatus();
+                       }
+               });
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(ret[0])); }
+               return ret[0];
+       }
+
+       public void tcfServiceReady(IService service) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { service })); }
+               tcfMemoryService = (org.eclipse.tm.tcf.services.IMemory) service;
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       @DsfServiceEventHandler
+       public void eventDispatched(ISuspendedDMEvent e) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { e.getClass() })); }
+               flushCache(e.getDMContext());
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       @DsfServiceEventHandler
+       public void eventDispatched(IResumedDMEvent e) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { e.getClass() })); }
+               if (e.getReason() != StateChangeReason.STEP) {
+                       flushCache(e.getDMContext());
+               }
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       @DsfServiceEventHandler
+       public void eventDispatched(IExpressionChangedDMEvent e) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { e.getClass() })); }
+
+               // Get the context and expression service handle
+               final IExpressionDMContext context = e.getDMContext();
+               IExpressions expressionService = getService(IExpressions.class);
+
+               // Get the variable information and update the corresponding memory
+               // locations
+               if (expressionService != null) {
+                       expressionService.getExpressionAddressData(context, new DataRequestMonitor<IExpressionDMAddress>(
+                                       getExecutor(), null) {
+                               @Override
+                               protected void handleSuccess() {
+                                       // Figure out which memory area was modified
+                                       IExpressionDMAddress expression = getData();
+                                       final int count = expression.getSize();
+                                       Object expAddress = expression.getAddress();
+                                       final Addr64 address;
+                                       if (expAddress instanceof Addr64)
+                                               address = (Addr64) expAddress;
+                                       else if (expAddress instanceof IAddress)
+                                               address = new Addr64(((IAddress) expAddress).getValue());
+                                       else
+                                               return; // not a valid memory address
+
+                                       final IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(context, IMemoryDMContext.class);
+                                       boolean modified = getMemoryCache(memoryDMC).refreshMemory(tcfMemoryService, memoryDMC, address, 0,
+                                                       1, count, new RequestMonitor(getExecutor(), null), getTCFTimeout());
+                                       if (modified) {
+                                               // we've modified cache - send an event
+                                               IAddress[] addresses = new IAddress[count];
+                                               for (int i = 0; i < count; i++) {
+                                                       addresses[i] = address.add(i);
+                                               }
+                                               getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), getProperties());
+                                       }
+                               }
+                       });
+               }
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       private static final String MEMORY_CONTEXT = "memory_context";
+       private static final String MEMORY = "memory";
+       private static final String CONTEXT_ID = "context_id";
+
+       public void loadSnapshot(Element element) throws Exception {
+               memoryCaches = new HashMap<String, MemoryCache>();
+               NodeList contextElements = element.getElementsByTagName(MEMORY_CONTEXT);
+
+               int numContexts = contextElements.getLength();
+               for (int i = 0; i < numContexts; i++) {
+                       Element contextElement = (Element) contextElements.item(i);
+                       String contextID = contextElement.getAttribute(CONTEXT_ID);
+                       MemoryCache cache = new MemoryCache(getTargetEnvironmentService().getMemoryCacheMinimumBlockSize());
+                       cache.loadSnapshot(contextElement);
+                       memoryCaches.put(contextID, cache);
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.snapshot.ISnapshotContributor#takeShapshot(org.eclipse.cdt.debug.edc.snapshot.IAlbum, org.w3c.dom.Document, org.eclipse.core.runtime.IProgressMonitor)
+        */
+       public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor) {
+               Element memoryElement = document.createElement(MEMORY);
+               SubMonitor progress = SubMonitor.convert(monitor, memoryCaches.keySet().size() * 1000);
+               progress.subTask("Memory");
+               for (String key : memoryCaches.keySet()) {
+                       MemoryCache cache = memoryCaches.get(key);
+                       Element memoryCacheElement = document.createElement(MEMORY_CONTEXT);
+                       memoryCacheElement.setAttribute(CONTEXT_ID, key);
+                       memoryCacheElement.appendChild(cache.takeSnapshot(album, document, progress.newChild(1000)));
+                       memoryElement.appendChild(memoryCacheElement);
+               }
+               return memoryElement;
+       }
+
+       public void setTCFTimeout(long msecs) {
+               tcfTimeout = msecs;
+       }
+
+       public long getTCFTimeout() {
+               return tcfTimeout;
+       }
+       
+       // Implementation of org.eclipse.cdt.dsf.debug.service.IMemory
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IMemory#fillMemory(org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext, org.eclipse.cdt.core.IAddress, long, int, int, byte[], org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+        */
+       public void fillMemory(final IMemoryDMContext context, final IAddress address, final long offset, final int word_size, final int count,
+                       final byte[] pattern, final RequestMonitor rm) {
+               asyncExec(new Runnable() {
+                       
+                       public void run() {
+                               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { address.toHexAddressString(), offset, word_size, count })); }
+
+                               // Validate the context
+                               if (context == null) {
+                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INTERNAL_ERROR,
+                                                                       "Unknown context type", null)); //$NON-NLS-1$;
+                                       rm.done();
+                                       return;
+                               }
+
+                               // Validate the word size
+                               if (word_size < 1) {
+                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, NOT_SUPPORTED,
+                                                       "Word size not supported (< 1)", null)); //$NON-NLS-1$
+                                       rm.done();
+                                       return;
+                               }
+
+                               // Validate the repeat count
+                               if (count < 0) {
+                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+                                                       "Invalid repeat count (< 0)", null)); //$NON-NLS-1$
+                                       rm.done();
+                                       return;
+                               }
+
+                               // Validate the pattern
+                               if (pattern.length < 1) {
+                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+                                                       "Empty pattern", null)); //$NON-NLS-1$
+                                       rm.done();
+                                       return;
+                               }
+
+                               // Create an aggregate buffer so we can write in 1 shot
+                               final int length = pattern.length;
+                               final byte[] buffer = new byte[count * length];
+                               for (int i = 0; i < count; i++) {
+                                       System.arraycopy(pattern, 0, buffer, i * length, length);
+                               }
+
+                               // All is clear: go for it
+                               // NOTE: We normalize word_size and count to read 1-byte words for this implementation
+                               try {
+                                       getMemoryCache(context).setMemory(tcfMemoryService, context, address, offset, 1, count * length * word_size,
+                                                       buffer, getTCFTimeout());
+                               } catch (CoreException e) {
+                                       EDCDebugger.getMessageLogger().log(e.getStatus());
+                                       rm.setStatus(e.getStatus());
+                               }
+                               rm.done();
+                               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+                       }
+                       
+               }, rm);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IMemory#getMemory(org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext, org.eclipse.cdt.core.IAddress, long, int, int, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getMemory(final IMemoryDMContext context, final IAddress address, final long offset,
+                       final int word_size, final int count, final DataRequestMonitor<MemoryByte[]> drm) {
+
+               asyncExec(new Runnable() {
+                       
+                       public void run() {
+                               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { address.toHexAddressString(), offset, word_size, count })); }
+                               // NOTE: We normalize word_size and count to read 1-byte words for this implementation
+                               try {
+                                       MemoryByte[] memoryBytes = getMemory(context, address, offset, word_size, count);
+                                       drm.setData(memoryBytes);
+                               } catch (CoreException e) {
+                                       EDCDebugger.getMessageLogger().log(e.getStatus());
+                                       drm.setStatus(e.getStatus());
+                               }
+                               drm.done();
+                               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+                       }
+                       
+               }, drm);
+
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IMemory#setMemory(org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext, org.eclipse.cdt.core.IAddress, long, int, int, byte[], org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+        */
+       public void setMemory(final IMemoryDMContext context, final IAddress address, final long offset,
+                       final int word_size, final int count, final byte[] buffer, final RequestMonitor rm) {
+
+               asyncExec(new Runnable() {
+                       
+                       public void run() {
+                               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { address.toHexAddressString(), offset, word_size, count })); }
+
+                               // Validate the context
+                               if (context == null) {
+                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INTERNAL_ERROR,
+                                                                       "Unknown context type", null)); //$NON-NLS-1$);
+                                       rm.done();
+                                       return;
+                               }
+
+                               // Validate the word size
+                               // NOTE: We only accept 1 byte words for this implementation
+                               if (word_size != 1) {
+                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, NOT_SUPPORTED,
+                                                       "Word size not supported (!= 1)", null)); //$NON-NLS-1$
+                                       rm.done();
+                                       return;
+                               }
+
+                               // Validate the byte count
+                               if (count < 0) {
+                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+                                                       "Invalid word count (< 0)", null)); //$NON-NLS-1$
+                                       rm.done();
+                                       return;
+                               }
+
+                               // Validate the buffer size
+                               if (buffer.length < count) {
+                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+                                                       "Buffer too short", null)); //$NON-NLS-1$
+                                       rm.done();
+                                       return;
+                               }
+                               // everything ok
+                               // NOTE: We normalize word_size and count to read 1-byte words for this implementation
+                               try {
+                                       getMemoryCache(context).setMemory(tcfMemoryService, context, address, offset, word_size, count, buffer, getTCFTimeout());
+                                       if (rm.isSuccess()) {
+                                               // we've modified memory - send an event
+                                               IAddress[] addresses = new IAddress[count];
+                                               for (int i = 0; i < count; i++) {
+                                                       addresses[i] = address.add(offset + i);
+                                               }
+                                               getSession().dispatchEvent(new MemoryChangedEvent(context, addresses), getProperties());
+                                       }
+                               } catch (CoreException e) {
+                                       EDCDebugger.getMessageLogger().log(e.getStatus());
+                                       rm.setStatus(e.getStatus());
+                               }
+                               rm.done();
+                               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+                       }
+                       
+               }, rm);
+
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/MemoryCache.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/MemoryCache.java
new file mode 100644 (file)
index 0000000..e62250b
--- /dev/null
@@ -0,0 +1,836 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.core.IAddressFactory;
+import org.eclipse.cdt.debug.edc.MemoryUtils;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.services.IEDCDMContext;
+import org.eclipse.cdt.debug.edc.snapshot.IAlbum;
+import org.eclipse.cdt.debug.edc.snapshot.ISnapshotContributor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+import org.eclipse.cdt.utils.Addr32Factory;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.cdt.utils.Addr64Factory;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.debug.core.model.MemoryByte;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.services.IMemory;
+import org.eclipse.tm.tcf.services.IMemory.DoneGetContext;
+import org.eclipse.tm.tcf.services.IMemory.DoneMemory;
+import org.eclipse.tm.tcf.services.IMemory.ErrorOffset;
+import org.eclipse.tm.tcf.services.IMemory.MemoryContext;
+import org.eclipse.tm.tcf.services.IMemory.MemoryError;
+import org.eclipse.tm.tcf.util.TCFTask;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * This is adapted from 
+ * org.eclipse.cdt.dsf.mi.service.MIMemory.MIMemoryCache 
+ * 
+ */
+public class MemoryCache implements ISnapshotContributor {
+
+       // Timeout waiting for TCF agent reply.
+       final private int TIMEOUT = 6000; // milliseconds
+       private int minimumBlockSize = 0;
+       private final Map<String, MemoryContext>        tcfMemoryContexts = Collections.synchronizedMap(new HashMap<String, MemoryContext>());
+       private final SortedMemoryBlockList memoryBlockList = new SortedMemoryBlockList();
+
+       /**
+        * @param minimumBlockSize minimum size of memory block to cache.
+        */
+       public MemoryCache(int minimumBlockSize) {
+               this.minimumBlockSize = minimumBlockSize;
+       }
+
+       public void reset() {
+               // clear the memory cache
+               synchronized (memoryBlockList)
+               {
+                       memoryBlockList.clear();
+               }
+       }
+
+    /**
+        *  This function walks the address-sorted memory block list to identify
+     *  the 'missing' blocks (i.e. the holes) that need to be fetched on the target.
+     * 
+     *  The idea is fairly simple but an illustration could perhaps help.
+     *  Assume the cache holds a number of cached memory blocks with gaps i.e.
+     *  there is un-cached memory areas between blocks A, B and C:
+     * 
+     *        +---------+      +---------+      +---------+
+     *        +    A    +      +    B    +      +    C    +
+     *        +---------+      +---------+      +---------+
+     *        :         :      :         :      :         :
+     *   [a]  :         :  [b] :         :  [c] :         :  [d]
+     *        :         :      :         :      :         :
+     *   [e---+--]      :  [f--+---------+--]   :         :
+     *   [g---+---------+------+---------+------+---------+----]
+     *        :         :      :         :      :         :
+     *        :   [h]   :      :   [i----+--]   :         :
+     * 
+     * 
+     *  We have the following cases to consider.The requested block [a-i] either:
+     * 
+     *  [1] Fits entirely before A, in one of the gaps, or after C
+     *      with no overlap and no contiguousness (e.g. [a], [b], [c] and [d])
+     *      -> Add the requested block to the list of blocks to fetch
+     * 
+     *  [2] Starts before an existing block but overlaps part of it, possibly
+     *      spilling in the gap following the cached block (e.g. [e], [f] and [g])
+     *      -> Determine the length of the missing part (< count)
+     *      -> Add a request to fill the gap before the existing block
+     *      -> Update the requested block for the next iteration:
+     *         - Start address to point just after the end of the cached block
+     *         - Count reduced by cached block length (possibly becoming negative, e.g. [e])
+     *      At this point, the updated requested block starts just beyond the cached block
+     *      for the next iteration.
+     * 
+     *  [3] Starts at or into an existing block and overlaps part of it ([h] and [i])
+     *      -> Update the requested block for the next iteration:
+     *         - Start address to point just after the end of the cached block
+     *         - Count reduced by length to end of cached block (possibly becoming negative, e.g. [h])
+     *      At this point, the updated requested block starts just beyond the cached block
+     *      for the next iteration.
+     * 
+     *  We iterate over the cached blocks list until there is no entry left or until
+     *  the remaining requested block count is <= 0, meaning the result list contains
+     *  only the sub-blocks needed to fill the gap(s), if any.
+     * 
+     *  (As is often the case, it takes much more typing to explain it than to just do it :-)
+     *
+     *  What is missing is a parameter that indicates the minimal block size that is worth fetching.
+     *  This is target-specific and straight in the realm of the coalescing function... 
+     *  
+     * @param reqBlockStart The address of the requested block
+     * @param count Its length
+     * @return A list of the sub-blocks to fetch in order to fill enough gaps in the memory cache
+     * to service the request
+     */
+       private LinkedList<MemoryBlock> getListOfMissingBlocks(IAddress reqBlockStart, int count) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { reqBlockStart.toHexAddressString(), count })); }
+               LinkedList<MemoryBlock> list = new LinkedList<MemoryBlock>();
+
+               synchronized (memoryBlockList)
+               {
+                       ListIterator<MemoryBlock> it = memoryBlockList.listIterator();
+
+                       // Look for holes in the list of memory blocks
+                       while (it.hasNext() && count > 0) {
+                               MemoryBlock cachedBlock = it.next();
+                               IAddress cachedBlockStart = cachedBlock.fAddress;
+                               IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLength);
+
+                               // Case where we miss a block before the cached block
+                               if (reqBlockStart.distanceTo(cachedBlockStart).longValue() >= 0) {
+                                       int length = (int) Math.min(reqBlockStart.distanceTo(cachedBlockStart).longValue(), count);
+                                       // If both blocks start at the same location, no need to create
+                                       // a new cached block
+                                       if (length > 0) {
+                                               IAddress blockAddress;
+                                               if (reqBlockStart instanceof Addr64) {
+                                                       IAddressFactory f = new Addr64Factory();
+                                                       blockAddress = f.createAddress(reqBlockStart.getValue());
+                                               } else {
+                                                       IAddressFactory f = new Addr32Factory();
+                                                       blockAddress = f.createAddress(reqBlockStart.getValue());
+                                               }
+                                               MemoryBlock newBlock = new MemoryBlock(blockAddress, length, new MemoryByte[0]);
+                                               list.add(newBlock);
+                                       }
+                                       // Adjust request block start and length for the next iteration
+                                       reqBlockStart = cachedBlockEnd;
+                                       count -= length + cachedBlock.fLength;
+                               }
+
+                               // Case where the requested block starts somewhere in the cached
+                               // block
+                               else if (cachedBlockStart.distanceTo(reqBlockStart).longValue() > 0
+                                               && reqBlockStart.distanceTo(cachedBlockEnd).longValue() >= 0) {
+                                       // Start of the requested block already in cache
+                                       // Adjust request block start and length for the next iteration
+                                       count -= reqBlockStart.distanceTo(cachedBlockEnd).longValue();
+                                       reqBlockStart = cachedBlockEnd;
+                               }
+                       }
+
+                       // Case where we miss a block at the end of the cache
+                       if (count > 0) {
+                               IAddress blockAddress;
+                               if (reqBlockStart instanceof Addr64) {
+                                       IAddressFactory f = new Addr64Factory();
+                                       blockAddress = f.createAddress(reqBlockStart.getValue());
+                               } else {
+                                       IAddressFactory f = new Addr32Factory();
+                                       blockAddress = f.createAddress(reqBlockStart.getValue());
+                               }
+                               MemoryBlock newBlock = new MemoryBlock(blockAddress, count, new MemoryByte[0]);
+                               list.add(newBlock);
+                       }
+               }
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(list)); }
+               return list;
+       }
+
+       /**
+        * This function walks the address-sorted memory block list to get the
+        * cached memory bytes (possibly from multiple contiguous blocks). This
+        * function is called *after* the missing blocks have been read from the
+        * back end i.e. the requested memory is all cached.
+        * 
+        * Again, this is fairly simple. As we loop over the address-ordered list,
+        * There are really only 2 cases:
+        * 
+        * [1] The requested block fits entirely in the cached block ([a] or [b])
+        * [2] The requested block starts in a cached block and ends in the
+        * following (contiguous) one ([c]) in which case it is treated as 2
+        * contiguous requests ([c'] and [c"])
+        * 
+        * +--------------+--------------+ + A + B + +--------------+--------------+
+        * : [a----] : [b-----] : : : : : [c-----+------] : : [c'---]+[c"---] :
+        * 
+        * @param reqBlockStart
+        *            The address of the requested block
+        * @param count
+        *            Its length
+        * @return The cached memory content
+        */
+       private MemoryByte[] getMemoryBlockFromCache(IAddress reqBlockStart, int count) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { reqBlockStart.toHexAddressString(), count })); }
+
+               MemoryByte[] resultBlock = new MemoryByte[count];
+
+               synchronized (memoryBlockList)
+               {
+                       IAddress reqBlockEnd = reqBlockStart.add(count);
+                       ListIterator<MemoryBlock> iter = memoryBlockList.listIterator();
+
+                       while (iter.hasNext()) {
+                               MemoryBlock cachedBlock = iter.next();
+                               IAddress cachedBlockStart = cachedBlock.fAddress;
+                               IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLength);
+
+                               // Case where the cached block overlaps completely the requested
+                               // memory block
+                               if (cachedBlockStart.distanceTo(reqBlockStart).longValue() >= 0
+                                               && reqBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) {
+                                       int pos = (int) cachedBlockStart.distanceTo(reqBlockStart).longValue();
+                                       System.arraycopy(cachedBlock.fBlock, pos, resultBlock, 0, count);
+                               }
+
+                               // Case where the beginning of the cached block is within the
+                               // requested memory block
+                               else if (reqBlockStart.distanceTo(cachedBlockStart).longValue() >= 0
+                                               && cachedBlockStart.distanceTo(reqBlockEnd).longValue() > 0) {
+                                       int pos = (int) reqBlockStart.distanceTo(cachedBlockStart).longValue();
+                                       int length = (int) Math.min(cachedBlock.fLength, count - pos);
+                                       System.arraycopy(cachedBlock.fBlock, 0, resultBlock, pos, length);
+                               }
+
+                               // Case where the end of the cached block is within the requested
+                               // memory block
+                               else if (cachedBlockStart.distanceTo(reqBlockStart).longValue() >= 0
+                                               && reqBlockStart.distanceTo(cachedBlockEnd).longValue() > 0) {
+                                       int pos = (int) cachedBlockStart.distanceTo(reqBlockStart).longValue();
+                                       int length = (int) Math.min(cachedBlock.fLength - pos, count);
+                                       System.arraycopy(cachedBlock.fBlock, pos, resultBlock, 0, length);
+                               }
+                       }
+               }
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArgs(resultBlock)); }
+               return resultBlock;
+       }
+
+       /**
+        * This function walks the address-sorted memory block list and updates the
+        * content with the actual memory just read from the target.
+        * 
+        * @param modBlockStart
+        * @param count
+        * @param modBlock
+        */
+       private void updateMemoryCache(IAddress modBlockStart, int count, MemoryByte[] modBlock) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { modBlockStart.toHexAddressString(), count })); }
+
+               synchronized (memoryBlockList)
+               {
+                       IAddress modBlockEnd = modBlockStart.add(count);
+                       ListIterator<MemoryBlock> iter = memoryBlockList.listIterator();
+
+                       while (iter.hasNext()) {
+                               MemoryBlock cachedBlock = iter.next();
+                               IAddress cachedBlockStart = cachedBlock.fAddress;
+                               IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLength);
+
+                               // For now, we only bother to update bytes already cached.
+                               // Note: In a better implementation (v1.1), we would augment
+                               // the cache with the missing memory blocks since we went
+                               // through the pains of reading them in the first place.
+                               // (this is left as an exercise to the reader :-)
+
+                               // Case where the modified block is completely included in the
+                               // cached block
+                               if (cachedBlockStart.distanceTo(modBlockStart).longValue() >= 0
+                                               && modBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) {
+                                       int pos = (int) cachedBlockStart.distanceTo(modBlockStart).longValue();
+                                       System.arraycopy(modBlock, 0, cachedBlock.fBlock, pos, count);
+                               }
+
+                               // Case where the beginning of the modified block is within the
+                               // cached block
+                               else if (cachedBlockStart.distanceTo(modBlockStart).longValue() >= 0
+                                               && modBlockStart.distanceTo(cachedBlockEnd).longValue() > 0) {
+                                       int pos = (int) cachedBlockStart.distanceTo(modBlockStart).longValue();
+                                       int length = (int) cachedBlockStart.distanceTo(modBlockEnd).longValue();
+                                       System.arraycopy(modBlock, 0, cachedBlock.fBlock, pos, length);
+                               }
+
+                               // Case where the end of the modified block is within the cached
+                               // block
+                               else if (cachedBlockStart.distanceTo(modBlockEnd).longValue() > 0
+                                               && modBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) {
+                                       int pos = (int) modBlockStart.distanceTo(cachedBlockStart).longValue();
+                                       int length = (int) cachedBlockStart.distanceTo(modBlockEnd).longValue();
+                                       System.arraycopy(modBlock, pos, cachedBlock.fBlock, 0, length);
+                               }
+                       }
+               }
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               return;
+       }
+
+       /**
+        * This function iterates through missing blocks (blocks not currently
+        * cached, but wanted) and reads from the target and creates new cached
+        * blocks.
+        * 
+        * @param tcfMemoryService
+        * @param context
+        * @param address
+        * @param word_size
+        * @param count
+        * @param drm
+        * @param timeOutLimit 
+        * @throws CoreException 
+        */
+       public MemoryByte[] getMemory(final IMemory tcfMemoryService, final IMemoryDMContext context, final IAddress address,
+                       final int word_size, final int count, long timeOutLimit) throws CoreException {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { context, address.toHexAddressString(), word_size, count })); }
+
+               // determine number of read requests to issue
+               final LinkedList<MemoryBlock> missingBlocks = getListOfMissingBlocks(address, count);
+               final int numberOfRequests = missingBlocks.size();
+
+               if (numberOfRequests > 0 && tcfMemoryService == null) {
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, "Fail to read memory."));
+               }
+               // System.out.printf("MemoryCache.getMemory address=%x count=%d numberOfRequests=%d\n",
+               // address.getValue(), count, numberOfRequests);
+               for (int i = 0; i < numberOfRequests; i++) {
+                       MemoryBlock block = missingBlocks.get(i);
+                       IAddress blockAddress = block.fAddress;
+                       int blockLength = (int) block.fLength;
+                       if (blockLength < minimumBlockSize)
+                               blockLength = minimumBlockSize;
+                       
+                       MemoryByte[] result;
+                       try {
+                               result = readBlock(tcfMemoryService, context, blockAddress, word_size, blockLength, timeOutLimit);
+                               MemoryBlock newBlock = new MemoryBlock(blockAddress, blockLength, result);
+                               memoryBlockList.add(newBlock);
+                       } catch (Exception e) {
+                               throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+                                               "Fail to read memory.", e.getCause())); //$NON-NLS-1$
+                       }
+               }
+               MemoryByte[] result = getMemoryBlockFromCache(address, count);
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               return result;
+       }
+
+       private MemoryContext getTCFMemoryContext(final IMemory tcfMemoryService, final String contextID, long timeOutLimit) throws IOException, InterruptedException, ExecutionException, TimeoutException {
+
+               MemoryContext ret = tcfMemoryContexts.get(contextID);
+               if (ret != null)
+                       return ret;
+               
+               final TCFTask<MemoryContext> tcfTask = new TCFTask<MemoryContext>(TIMEOUT) {
+
+                       public void run() {
+                               tcfMemoryService.getContext(contextID, new DoneGetContext() {
+
+                                       public void doneGetContext(IToken token, Exception error, MemoryContext context) {
+                                               if (error == null) {
+                                                       done(context);
+                                               } else {
+                                                       error(error);
+                                               }
+                                       }
+                               });
+                       }
+               };
+
+               ret = tcfTask.get(timeOutLimit, TimeUnit.MILLISECONDS);
+
+               if (ret != null)
+                       tcfMemoryContexts.put(contextID, ret);
+               
+               return ret;
+       }
+
+       /**
+        * This function does the actual reading from the target.
+        * 
+        * @param tcfMemoryService
+        * @param context
+        * @param address
+        * @param word_size
+        * @param count
+        * @param timeOutLimit 
+        * @return
+        * @throws IOException
+        * @throws TimeoutException 
+        * @throws ExecutionException 
+        * @throws InterruptedException 
+        */
+       private MemoryByte[] readBlock(final IMemory tcfMemoryService, final IMemoryDMContext context,
+                       final IAddress address, final int word_size, final int count, long timeOutLimit) throws IOException, InterruptedException, ExecutionException, TimeoutException {
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { context, address.toHexAddressString(), word_size, count })); }
+
+               final MemoryContext tcfMC = getTCFMemoryContext(tcfMemoryService, ((IEDCDMContext)context).getID(), timeOutLimit);
+               
+               MemoryByte[] result = null;
+
+               final TCFTask<MemoryByte[]> tcfTask = new TCFTask<MemoryByte[]>(TIMEOUT) {
+
+                       public void run() {
+                               Number tcfAddress = address.getValue();
+                               final byte[] buffer = new byte[word_size * count];
+                               tcfMC.get(tcfAddress, word_size, buffer, 0, count * word_size, 0, new DoneMemory() {
+
+                                       public void doneMemory(IToken token, MemoryError error) {
+                                               if (error == null) {
+                                                       MemoryByte[] res = new MemoryByte[buffer.length];
+                                                       for (int i = 0; i < buffer.length; i++) {
+                                                               res[i] = new MemoryByte(buffer[i]);
+                                                       }
+                                                       done(res);
+                                               } else if (error instanceof IMemory.ErrorOffset) {
+                                                       boolean someStatusKnown = false;
+                                                       IMemory.ErrorOffset errorOffset = (ErrorOffset) error;
+                                                       MemoryByte[] res = new MemoryByte[buffer.length];
+                                                       
+                                                       // TODO: figure actual endianness (MemoryByte.BIG_ENDIAN) flag; 
+                                                       // we leave out the flag here which defaults to little-endian
+                                                       for (int i = 0; i < buffer.length; i++) {
+                                                               byte flags = MemoryByte.ENDIANESS_KNOWN | MemoryByte.READABLE | MemoryByte.WRITABLE;
+                                                               
+                                                               int st = errorOffset.getStatus(i);
+                                                               if ((st & IMemory.ErrorOffset.BYTE_UNKNOWN) != 0) {
+                                                                       flags = 0;
+                                                               } else {
+                                                                       someStatusKnown = true;
+                                                                       if ((st & IMemory.ErrorOffset.BYTE_INVALID) != 0) {
+                                                                               flags &= ~(MemoryByte.READABLE + MemoryByte.WRITABLE);
+                                                                       } else {
+                                                                               if ((st & IMemory.ErrorOffset.BYTE_CANNOT_READ) != 0)
+                                                                                       flags &= ~MemoryByte.READABLE;
+                                                                               if ((st & IMemory.ErrorOffset.BYTE_CANNOT_WRITE) != 0)
+                                                                                       flags &= ~MemoryByte.WRITABLE;
+                                                                       }
+                                                               }
+                                                               res[i] = new MemoryByte(buffer[i], flags);
+                                                       }
+                                                       if (someStatusKnown)
+                                                               done(res);
+                                                       else
+                                                               error(error);
+                                               } else {
+                                                       error(error);
+                                               }
+                                       }
+                               });
+                       }
+               };
+
+               result = tcfTask.get(timeOutLimit, TimeUnit.MILLISECONDS);
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               return result;
+       }
+
+       /**
+        * This function writes a block of memory and then re-reads and updates any
+        * cached blocks.
+        * 
+        * @param tcfMemoryService
+        * @param context
+        * @param address
+        * @param offset
+        * @param word_size
+        * @param count
+        * @param buffer
+        * @param rm
+        * @throws CoreException 
+        */
+       public void setMemory(IMemory tcfMemoryService, IMemoryDMContext context, final IAddress address,
+                       final long offset, final int word_size, final int count, byte[] buffer,
+                       long timeOutLimit) throws CoreException {
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { context, address.toHexAddressString(), offset, word_size, count })); }
+
+               try {
+                       writeBlock(tcfMemoryService, context, address, offset, word_size, count, buffer, timeOutLimit);
+                       if (blockIsCached(address.add(offset), word_size * count)) {
+                               MemoryByte[] update = readBlock(tcfMemoryService, context, address.add(offset), word_size, count, timeOutLimit);
+                               updateMemoryCache(address.add(offset), update.length, update);
+                       }
+               } catch (Exception e) {
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, "Fail to write memory."));
+               }
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       /**
+        * This function figures out if a block of memory is already cached.
+        * 
+        * @param modBlockStart
+        * @param count
+        * @return
+        */
+       private boolean blockIsCached(IAddress modBlockStart, int count) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { modBlockStart.toHexAddressString(), count })); }
+               boolean cacheFound = false;
+
+               synchronized (memoryBlockList)
+               {
+                       IAddress modBlockEnd = modBlockStart.add(count);
+                       ListIterator<MemoryBlock> iter = memoryBlockList.listIterator();
+
+                       while (iter.hasNext()) {
+                               MemoryBlock cachedBlock = iter.next();
+                               IAddress cachedBlockStart = cachedBlock.fAddress;
+                               IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLength);
+
+                               // For now, we only bother to update bytes already cached.
+                               // Note: In a better implementation (v1.1), we would augment
+                               // the cache with the missing memory blocks since we went
+                               // through the pains of reading them in the first place.
+                               // (this is left as an exercise to the reader :-)
+
+                               // Case where the modified block is completely included in the
+                               // cached block
+                               if (cachedBlockStart.distanceTo(modBlockStart).longValue() >= 0
+                                               && modBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) {
+                                       cacheFound = true;
+                               }
+
+                               // Case where the beginning of the modified block is within the
+                               // cached block
+                               else if (cachedBlockStart.distanceTo(modBlockStart).longValue() >= 0
+                                               && modBlockStart.distanceTo(cachedBlockEnd).longValue() > 0) {
+                                       cacheFound = true;
+                               }
+
+                               // Case where the end of the modified block is within the cached
+                               // block
+                               else if (cachedBlockStart.distanceTo(modBlockEnd).longValue() > 0
+                                               && modBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) {
+                                       cacheFound = true;
+                               }
+                       }
+               }
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(cacheFound)); }
+               return cacheFound;
+       }
+
+       /**
+        * This function writes a memory block to the target.
+        * 
+        * @param tcfMemoryService
+        * @param context
+        * @param address
+        * @param offset
+        * @param word_size
+        * @param count
+        * @param buffer
+        * @param timeOutLimit 
+        * @throws IOException
+        * @throws TimeoutException 
+        * @throws ExecutionException 
+        * @throws InterruptedException 
+        */
+       private void writeBlock(final IMemory tcfMemoryService, final IMemoryDMContext context, final IAddress address,
+                       final long offset, final int word_size, final int count, final byte[] buffer, long timeOutLimit) throws IOException, InterruptedException, ExecutionException, TimeoutException {
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { context, address.toHexAddressString(), offset, word_size, count })); }
+
+               final TCFTask<MemoryByte[]> tcfTask = new TCFTask<MemoryByte[]>(TIMEOUT) {
+
+                       public void run() {
+                               final TCFTask<MemoryByte[]> task = this;
+                               String memoryContextID = ((IEDCDMContext) context).getID();
+                               tcfMemoryService.getContext(memoryContextID, new DoneGetContext() {
+
+                                       public void doneGetContext(IToken token, Exception error, MemoryContext context) {
+                                               if (error == null) {
+                                                       Number tcfAddress = address.add(offset).getValue();
+                                                       context.set(tcfAddress, word_size, buffer, 0, count * word_size, 0, new DoneMemory() {
+
+                                                               public void doneMemory(IToken token, MemoryError error) {
+                                                                       if (error == null) {
+                                                                               task.done(null);
+                                                                       } else {
+                                                                               task.error(error);
+                                                                       }
+                                                               }
+                                                       });
+                                               } else {
+                                                       task.error(error);
+                                               }
+                                       }
+                               });
+                       }
+               };
+
+               tcfTask.get(timeOutLimit, TimeUnit.MILLISECONDS);
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+       }
+
+       private class MemoryBlock {
+               public MemoryBlock(IAddress fAddress, long fLength, MemoryByte[] fBlock) {
+                       super();
+                       this.fAddress = fAddress;
+                       this.fLength = fLength;
+                       this.fBlock = fBlock;
+               }
+
+               public IAddress fAddress;
+               public long fLength;
+               public MemoryByte[] fBlock;
+       }
+
+       @SuppressWarnings("serial")
+       private class SortedMemoryBlockList extends LinkedList<MemoryBlock> {
+               public SortedMemoryBlockList() {
+                       super();
+               }
+
+               // Insert the block in the sorted linked list and merge contiguous
+               // blocks if necessary
+               @Override
+               synchronized public boolean add(MemoryBlock block) {
+                       if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { block.fAddress.toHexAddressString(), block.fLength })); }
+
+                       // If the list is empty, just store the block
+                       if (isEmpty()) {
+                               addFirst(block);
+                               return true;
+                       }
+
+                       // Insert the block at the correct location and then
+                       // merge the blocks if possible
+                       ListIterator<MemoryBlock> it = listIterator();
+                       while (it.hasNext()) {
+                               int index = it.nextIndex();
+                               MemoryBlock item = it.next();
+                               if (block.fAddress.compareTo(item.fAddress) < 0) {
+                                       add(index, block);
+                                       compact(index);
+                                       return true;
+                               }
+                       }
+
+                       // Put at the end of the list and merge if necessary
+                       addLast(block);
+                       compact(size() - 1);
+
+                       if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+                       return true;
+               }
+
+               // Merge this block with its contiguous neighbors (if any)
+               // Note: Merge is not performed if resulting block size would exceed
+               // MAXINT
+               private void compact(int index) {
+                       if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { index })); }
+
+                       MemoryBlock newBlock = get(index);
+
+                       // Case where the block is to be merged with the previous block
+                       if (index > 0) {
+                               MemoryBlock prevBlock = get(index - 1);
+                               IAddress endOfPreviousBlock = prevBlock.fAddress.add(prevBlock.fLength);
+                               if (endOfPreviousBlock.distanceTo(newBlock.fAddress).longValue() == 0) {
+                                       long newLength = prevBlock.fLength + newBlock.fLength;
+                                       if (newLength <= Integer.MAX_VALUE) {
+                                               MemoryByte[] block = new MemoryByte[(int) newLength];
+                                               System.arraycopy(prevBlock.fBlock, 0, block, 0, (int) prevBlock.fLength);
+                                               System.arraycopy(newBlock.fBlock, 0, block, (int) prevBlock.fLength, (int) newBlock.fLength);
+                                               newBlock = new MemoryBlock(prevBlock.fAddress, newLength, block);
+                                               remove(index);
+                                               index -= 1;
+                                               set(index, newBlock);
+                                       }
+                               }
+                       }
+
+                       // Case where the block is to be merged with the following block
+                       int lastIndex = size() - 1;
+                       if (index < lastIndex) {
+                               MemoryBlock nextBlock = get(index + 1);
+                               IAddress endOfNewBlock = newBlock.fAddress.add(newBlock.fLength);
+                               if (endOfNewBlock.distanceTo(nextBlock.fAddress).longValue() == 0) {
+                                       long newLength = newBlock.fLength + nextBlock.fLength;
+                                       if (newLength <= Integer.MAX_VALUE) {
+                                               MemoryByte[] block = new MemoryByte[(int) newLength];
+                                               System.arraycopy(newBlock.fBlock, 0, block, 0, (int) newBlock.fLength);
+                                               System.arraycopy(nextBlock.fBlock, 0, block, (int) newBlock.fLength, (int) nextBlock.fLength);
+                                               newBlock = new MemoryBlock(newBlock.fAddress, newLength, block);
+                                               set(index, newBlock);
+                                               remove(index + 1);
+                                       }
+                               }
+                       }
+
+                       if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+       }
+
+       /**
+        * Refreshes cache blocks when memory has been changed through an event.
+        * 
+        * @param tcfMemoryService
+        * @param context
+        * @param address
+        * @param offset
+        * @param word_size
+        * @param count
+        * @param rm
+        * @param timeOutLimit 
+        * @return true = cache has been modified
+        */
+       public boolean refreshMemory(IMemory tcfMemoryService, IMemoryDMContext context, IAddress address, int offset,
+                       int word_size, int count, RequestMonitor rm, long timeOutLimit) {
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { context, address.toHexAddressString(), offset, count })); }
+
+               boolean modified = false;
+               // Check if we already cache part of this memory area (which means it
+               // is used by a memory service client that will have to be updated)
+               LinkedList<MemoryBlock> list = getListOfMissingBlocks(address, count);
+               int sizeToRead = 0;
+               for (MemoryBlock block : list) {
+                       sizeToRead += block.fLength;
+               }
+
+               // If none of the requested memory is in cache, just get out
+               if (sizeToRead == count) {
+                       rm.done();
+                       return false;
+               }
+
+               try {
+                       MemoryByte[] newBlock = readBlock(tcfMemoryService, context, address, word_size, count, timeOutLimit);
+                       MemoryByte[] oldBlock = getMemoryBlockFromCache(address, count);
+                       boolean blocksDiffer = false;
+                       for (int i = 0; i < oldBlock.length; i++) {
+                               if (oldBlock[i].getValue() != newBlock[i].getValue()) {
+                                       blocksDiffer = true;
+                                       break;
+                               }
+                       }
+                       if (blocksDiffer) {
+                               updateMemoryCache(address, count, newBlock);
+                               modified = true;
+                       }
+               } catch (Exception e) {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+                                       "Error Writing Memory", e)); //$NON-NLS-1$
+               }
+               rm.done();
+
+               if (EDCTrace.MEMORY_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               return modified;
+       }
+
+       private static final String MEMORY_CACHE = "memory_cache";
+       private static final String MEMORY_BLOCK = "memory_block";
+       private static final String ATTR_ADDRESS = "address";
+       private static final String ATTR_LENGTH = "length";
+       private static final String ATTR_VALUE = "value";
+
+       public void loadSnapshot(Element element) throws Exception {
+               reset();
+               NodeList blockElements = element.getElementsByTagName(MEMORY_BLOCK);
+
+               int numBlocks = blockElements.getLength();
+               for (int i = 0; i < numBlocks; i++) {
+                       Element blockElement = (Element) blockElements.item(i);
+                       String blockAddress = blockElement.getAttribute(ATTR_ADDRESS);
+                       String blockLength = blockElement.getAttribute(ATTR_LENGTH);
+                       String blockValue = blockElement.getAttribute(ATTR_VALUE);
+                       MemoryByte[] blockBytes = MemoryUtils.convertHexStringToMemoryBytes(blockValue, blockValue.length() / 2, 2);
+                       MemoryBlock newBlock = new MemoryBlock(new Addr64(blockAddress), Long.parseLong(blockLength), blockBytes);
+                       memoryBlockList.add(newBlock);
+               }
+       }
+
+       public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor) {
+               synchronized (memoryBlockList)
+               {
+                       SubMonitor progress = SubMonitor.convert(monitor, memoryBlockList.size());
+                       progress.subTask("Memory");
+                       Element memoryCacheElement = document.createElement(MEMORY_CACHE);
+                       ListIterator<MemoryBlock> iter = memoryBlockList.listIterator();
+
+                       while (iter.hasNext()) {
+                               MemoryBlock block = iter.next();
+                               Element blockElement = document.createElement(MEMORY_BLOCK);
+                               blockElement.setAttribute(ATTR_ADDRESS, block.fAddress.toHexAddressString());
+                               blockElement.setAttribute(ATTR_LENGTH, Long.toString(block.fLength));
+                               blockElement.setAttribute(ATTR_VALUE, MemoryUtils.convertMemoryBytesToHexString(block.fBlock));
+                               memoryCacheElement.appendChild(blockElement);
+                               progress.worked(1);
+                       }
+                       return memoryCacheElement;
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Modules.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Modules.java
new file mode 100644 (file)
index 0000000..0068959
--- /dev/null
@@ -0,0 +1,1188 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocator;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.internal.PathUtils;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC;
+import org.eclipse.cdt.debug.edc.internal.snapshot.SnapshotUtils;
+import org.eclipse.cdt.debug.edc.internal.symbols.IRuntimeSection;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISection;
+import org.eclipse.cdt.debug.edc.internal.symbols.RuntimeSection;
+import org.eclipse.cdt.debug.edc.internal.symbols.Section;
+import org.eclipse.cdt.debug.edc.internal.symbols.files.ExecutableSymbolicsReaderFactory;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+import org.eclipse.cdt.debug.edc.services.DMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCDMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCExecutionDMC;
+import org.eclipse.cdt.debug.edc.services.IEDCModuleDMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCModules;
+import org.eclipse.cdt.debug.edc.snapshot.IAlbum;
+import org.eclipse.cdt.debug.edc.snapshot.ISnapshotContributor;
+import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider.ILineAddresses;
+import org.eclipse.cdt.debug.edc.tcf.extension.ProtocolConstants.IModuleProperty;
+import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.debug.core.model.ISourceLocator;
+import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class Modules extends AbstractEDCService implements IModules, IEDCModules {
+
+       public static final String MODULE = "module";
+       public static final String SECTION = "section";
+
+       private static final String ADDRESS_RANGE_CACHE = "_address_range";
+       private static final String LINE_ADDRESSES_CACHE = "_line_addresses";
+       private static final String NO_FILE_CACHE = "_no_file";
+
+       /**
+        * Modules that are loaded for each ISymbolDMContext (process).
+        */
+       private final Map<String, List<ModuleDMC>> modules = Collections
+                       .synchronizedMap(new HashMap<String, List<ModuleDMC>>());
+
+       private ISourceLocator sourceLocator;
+       private static int nextModuleID = 100;
+
+       public static class EDCAddressRange implements AddressRange, Serializable {
+               
+               private static final long serialVersionUID = -6475152211053407789L;
+               private IAddress startAddr, endAddr;
+
+               public EDCAddressRange(IAddress start, IAddress end) {
+                       startAddr = start;
+                       endAddr = end;
+               }
+
+               public IAddress getEndAddress() {
+                       return endAddr;
+               }
+
+               public void setEndAddress(IAddress address) {
+                       endAddr = address;
+               }
+
+               public IAddress getStartAddress() {
+                       return startAddr;
+               }
+
+               public void setStartAddress(IAddress address) {
+                       startAddr = address;
+               }
+
+               @Override
+               public String toString() {
+                       return MessageFormat.format("[{0},{1})", startAddr.toHexAddressString(), endAddr.toHexAddressString());
+               }
+
+               public boolean contains(IAddress address) {
+                       return getStartAddress().compareTo(address) <= 0
+                       && getEndAddress().compareTo(address) > 0;
+               }
+       }
+
+       public static class EDCLineAddresses implements ILineAddresses, Serializable {
+
+               private static final long serialVersionUID = 3263812332106024057L;
+
+               private int lineNumber;
+               private List<IAddress>  addresses;
+               
+               public EDCLineAddresses(int lineNumber, IAddress addr) {
+                       super();
+                       this.lineNumber = lineNumber;
+                       addresses = new ArrayList<IAddress>();
+                       addresses.add(addr);
+               }
+
+               public EDCLineAddresses(int lineNumber, List<IAddress> addrs) {
+                       super();
+                       this.lineNumber = lineNumber;
+                       addresses = new ArrayList<IAddress>(addrs);
+               }
+
+               public int getLineNumber() {
+                       return lineNumber;
+               }
+
+               public IAddress[] getAddress() {
+                       return addresses.toArray(new IAddress[addresses.size()]);
+               }
+
+               /**
+                * add addresses mapped to the line.
+                * @param addr
+                */
+               public void addAddress(List<IAddress> addrs) {
+                       addresses.addAll(addrs);
+               }
+
+               /**
+                * add addresses mapped to the line.
+                * @param addrs
+                */
+               public void addAddress(IAddress[] addrs) {
+                       for (IAddress a : addrs)
+                               addresses.add(a);
+               }
+
+               @Override
+               public String toString() {
+                       String addrs = "";
+                       for (IAddress a : addresses) {
+                               addrs += a.toHexAddressString() + " ";
+                       }
+                       return "EDCLineAddresses [lineNumber=" + lineNumber
+                                       + ", addresses=(" + addrs + ")]";
+               }
+       }
+       
+       public class ModuleDMC extends DMContext implements IEDCModuleDMContext, ISnapshotContributor,
+       // This means we'll install existing breakpoints
+                       // for each newly loaded module
+                       IBreakpointsTargetDMContext,
+                       // This means calcAddressInfo() also applies to single module
+                       // in addition to a process.
+                       ISymbolDMContext  {
+               private final ISymbolDMContext symbolContext;
+
+               private final IPath hostFilePath;
+               private IEDCSymbolReader symReader;
+               private final List<IRuntimeSection> runtimeSections = new ArrayList<IRuntimeSection>();
+
+               public ModuleDMC(ISymbolDMContext symbolContext, Map<String, Object> props) {
+                       super(Modules.this, symbolContext == null ? new IDMContext[0] : new IDMContext[] { symbolContext }, Integer
+                                       .toString(getNextModuleID()), props);
+                       this.symbolContext = symbolContext;
+
+                       String filename = "";
+                       if (props.containsKey(IModuleProperty.PROP_FILE))
+                               filename = (String) props.get(IModuleProperty.PROP_FILE);
+
+                       hostFilePath = locateModuleFileOnHost(filename);
+               }
+
+               public ISymbolDMContext getSymbolContext() {
+                       return symbolContext;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.services.IEDCModuleDMContext#getSymbolReader()
+                */
+               public IEDCSymbolReader getSymbolReader() {
+                       return symReader;
+               }
+
+               public void loadSnapshot(Element element) throws Exception {
+                       NodeList sectionElements = element.getElementsByTagName(SECTION);
+
+                       int numSections = sectionElements.getLength();
+                       for (int i = 0; i < numSections; i++) {
+                               Element sectionElement = (Element) sectionElements.item(i);
+                               Element propElement = (Element) sectionElement.getElementsByTagName(SnapshotUtils.PROPERTIES).item(0);
+                               HashMap<String, Object> properties = new HashMap<String, Object>();
+                               SnapshotUtils.initializeFromXML(propElement, properties);
+
+                               IAddress linkAddress = new Addr64(sectionElement.getAttribute(ISection.PROPERTY_LINK_ADDRESS));
+                               int sectionID = Integer.parseInt(sectionElement.getAttribute(ISection.PROPERTY_ID));
+                               long size = Long.parseLong(sectionElement.getAttribute(ISection.PROPERTY_SIZE));
+
+                               RuntimeSection section = new RuntimeSection(new Section(sectionID, size, linkAddress, properties));
+                               section.relocate(new Addr64(sectionElement.getAttribute(IRuntimeSection.PROPERTY_RUNTIME_ADDRESS)));
+                               runtimeSections.add(section);
+                       }
+
+                       initializeSymbolReader();
+               }
+
+               public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor) {
+                       SubMonitor progress = SubMonitor.convert(monitor, runtimeSections.size() + 1);
+                       progress.subTask("Modules");
+                       Element contextElement = document.createElement(MODULE);
+                       contextElement.setAttribute(PROP_ID, this.getID());
+                       Element propsElement = SnapshotUtils.makeXMLFromProperties(document, getProperties());
+                       contextElement.appendChild(propsElement);
+
+                       for (IRuntimeSection s : runtimeSections) {
+                               Element sectionElement = document.createElement(SECTION);
+                               sectionElement.setAttribute(ISection.PROPERTY_ID, Integer.toString(s.getId()));
+                               sectionElement.setAttribute(ISection.PROPERTY_SIZE, Long.toString(s.getSize()));
+                               sectionElement.setAttribute(ISection.PROPERTY_LINK_ADDRESS, s.getLinkAddress().toHexAddressString());
+                               sectionElement.setAttribute(IRuntimeSection.PROPERTY_RUNTIME_ADDRESS, s.getRuntimeAddress()
+                                               .toHexAddressString());
+                               propsElement = SnapshotUtils.makeXMLFromProperties(document, s.getProperties());
+                               sectionElement.appendChild(propsElement);
+                               contextElement.appendChild(sectionElement);
+                               progress.worked(1);
+                       }
+
+                       if (!hostFilePath.isEmpty()) {
+                               album.addFile(hostFilePath);
+                               IPath possibleSymFile = ExecutableSymbolicsReaderFactory.findSymbolicsFile(hostFilePath);
+                               if (possibleSymFile != null) {
+                                       album.addFile(possibleSymFile);
+                               }
+                       }
+                       progress.worked(1);
+                       return contextElement;
+               }
+
+               /**
+                * Relocate sections of the module. This should be called when the
+                * module is loaded.<br>
+                * <br>
+                * The relocation handling is target environment dependent.
+                * Implementation here has been tested for debug applications on
+                * Windows, Linux and Symbian. <br>
+                * 
+                * @param props
+                *            - runtime section properties from OS or from loader.
+                */
+               public void relocateSections(Map<String, Object> props) {
+
+                       initializeSymbolReader();
+
+                       if (symReader != null) {        
+                               for (ISection section: symReader.getSections())
+                               {
+                                       runtimeSections.add(new RuntimeSection(section));
+                               }
+                       }
+                       
+                       if (props.containsKey(IModuleProperty.PROP_IMAGE_BASE_ADDRESS)) {
+                               // Windows module (PE file)
+                               //
+
+                               Object base = props.get(IModuleProperty.PROP_IMAGE_BASE_ADDRESS);
+                               IAddress imageBaseAddr = null;
+                               if (base != null) {
+                                       if (base instanceof Integer)
+                                               imageBaseAddr = new Addr64(base.toString());
+                                       else if (base instanceof Long)
+                                               imageBaseAddr = new Addr64(base.toString());
+                                       else if (base instanceof String) // the string should be hex
+                                               // string
+                                               imageBaseAddr = new Addr64((String) base, 16);
+                                       else
+                                               EDCDebugger.getMessageLogger().logError(
+                                                               MessageFormat.format("Module property PROP_ADDRESS has invalid format {0}.", base
+                                                                               .getClass()), null);
+                               }
+
+                               Number size = 0;
+                               if (props.containsKey(IModuleProperty.PROP_CODE_SIZE))
+                                       size = (Number) props.get(IModuleProperty.PROP_CODE_SIZE);
+
+                               if (symReader != null) {
+                                       // relocate
+                                       //
+                                       IAddress linkBase = symReader.getBaseLinkAddress();
+                                       if (linkBase != null && !linkBase.equals(imageBaseAddr)) {
+                                               BigInteger offset = linkBase.distanceTo(imageBaseAddr);
+                                               for (IRuntimeSection s : runtimeSections) {
+                                                       IAddress runtimeB = s.getLinkAddress().add(offset);
+                                                       s.relocate(runtimeB);
+                                               }
+                                       }
+                               } else { // fill in fake section data
+                                       Map<String, Object> pp = new HashMap<String, Object>();
+                                       pp.put(ISection.PROPERTY_NAME, ISection.NAME_TEXT);
+                                       runtimeSections.add(new RuntimeSection(new Section(0, size.longValue(), imageBaseAddr, pp)));
+                               }
+                       } else if (props.containsKey(IModuleProperty.PROP_CODE_ADDRESS)) {
+                               // platforms other than Windows
+                               //
+                               Number codeAddr = null, dataAddr = null, bssAddr = null;
+                               Number codeSize = null, dataSize = null, bssSize = null;
+
+                               try {
+                                       codeAddr = (Number) props.get(IModuleProperty.PROP_CODE_ADDRESS);
+                                       dataAddr = (Number) props.get(IModuleProperty.PROP_DATA_ADDRESS);
+                                       bssAddr = (Number) props.get(IModuleProperty.PROP_BSS_ADDRESS);
+                                       codeSize = (Number) props.get(IModuleProperty.PROP_CODE_SIZE);
+                                       dataSize = (Number) props.get(IModuleProperty.PROP_DATA_SIZE);
+                                       bssSize = (Number) props.get(IModuleProperty.PROP_BSS_SIZE);
+                               } catch (ClassCastException e) {
+                                       EDCDebugger.getMessageLogger().logError("Module property value has invalid format.", null);
+                               }
+
+                               if (symReader != null) {
+                                       // Relocate.
+                                       for (IRuntimeSection s : runtimeSections) {
+                                               if (s.getProperties().get(ISection.PROPERTY_NAME).equals(ISection.NAME_TEXT)
+                                                               && codeAddr != null)
+                                                       s.relocate(new Addr64(codeAddr.toString()));
+                                               else if (s.getProperties().get(ISection.PROPERTY_NAME).equals(ISection.NAME_DATA)
+                                                               && dataAddr != null)
+                                                       s.relocate(new Addr64(dataAddr.toString()));
+                                               else if (s.getProperties().get(ISection.PROPERTY_NAME).equals(ISection.NAME_BSS)
+                                                               && bssAddr != null)
+                                                       s.relocate(new Addr64(bssAddr.toString()));
+                                       }
+                               } else {
+                                       // binary file not available.
+                                       // fill in our fake sections. If no section size available,
+                                       // don't bother.
+                                       //
+                                       Map<String, Object> pp = new HashMap<String, Object>();
+
+                                       if (codeAddr != null && codeSize != null) {
+                                               pp.put(ISection.PROPERTY_NAME, ISection.NAME_TEXT);
+                                               runtimeSections.add(new RuntimeSection(new Section(0, codeSize.intValue(), new Addr64(codeAddr.toString()), pp)));
+                                       }
+                                       if (dataAddr != null && dataSize != null) {
+                                               pp.clear();
+                                               pp.put(ISection.PROPERTY_NAME, ISection.NAME_DATA);
+                                               runtimeSections.add(new RuntimeSection(new Section(0, dataSize.intValue(), new Addr64(dataAddr.toString()), pp)));
+                                       }
+                                       if (bssAddr != null && bssSize != null) {
+                                               pp.clear();
+                                               pp.put(ISection.PROPERTY_NAME, ISection.NAME_BSS);
+                                               runtimeSections.add(new RuntimeSection(new Section(0, bssSize.intValue(), new Addr64(bssAddr.toString()), pp)));
+                                       }
+                               }
+                       } else {
+                               // No runtime address info available from target environment.
+                               // The runtime sections will just be the link-time sections.
+                               // 
+                               // This works well for the case where no relocation is needed
+                               // such as running the main executable (not DLLs nor shared
+                               // libs)
+                               // on Windows and Linux.
+                               // 
+                               // However, this may also indicate an error that the debug agent
+                               // (or even the target OS or loader) is not doing its job of
+                               // telling us the runtime address info.
+                       }
+               }
+
+               private void initializeSymbolReader() {
+                       if (hostFilePath.toFile().exists()) {
+                               symReader = Symbols.getSymbolReader(hostFilePath);
+                               if (symReader == null)
+                                       EDCDebugger.getMessageLogger().log(IStatus.WARNING,
+                                                       MessageFormat.format("''{0}'' has no recognized file format.",
+                                                                       hostFilePath), null);
+                               else if (! symReader.hasRecognizedDebugInformation()) {
+                                       // Log as INFO, not ERROR.
+                                       EDCDebugger.getMessageLogger().log(IStatus.INFO,
+                                                       MessageFormat.format("''{0}'' has no recognized symbolics.",
+                                                                       hostFilePath), null);
+                               }
+                       } else {
+                               // Binary file not on host. Do we want to prompt user for one ?
+                               
+                               // TODO: report this differently for the main executable vs. DLLs
+                               EDCDebugger.getMessageLogger().log(IStatus.WARNING, MessageFormat
+                                               .format("Cannot debug ''{0}''; no match found on disk, through source lookup, or in Executables view",
+                                                               hostFilePath), null);
+                       
+                       }
+               }
+
+               /**
+                * Check if a given runtime address falls in this module
+                * 
+                * @param absoluteAddr
+                *            - absolute runtime address.
+                * @return
+                */
+               public boolean containsAddress(IAddress runtimeAddress) {
+                       for (IRuntimeSection s : runtimeSections) {
+                               long offset = s.getRuntimeAddress().distanceTo(runtimeAddress).longValue();
+                               if (offset >= 0 && offset < s.getSize())
+                                       return true;
+                       }
+
+                       return false;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.services.IEDCModuleDMContext#toLinkAddress(org.eclipse.cdt.core.IAddress)
+                */
+               public IAddress toLinkAddress(IAddress runtimeAddress) {
+                       IAddress ret = null;
+
+                       for (IRuntimeSection s : runtimeSections) {
+                               long offset = s.getRuntimeAddress().distanceTo(runtimeAddress).longValue();
+                               if (offset >= 0 && offset < s.getSize()) {
+                                       return s.getLinkAddress().add(offset);
+                               }
+                       }
+
+                       return ret;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCModuleDMContext#toRuntimeAddress(org.eclipse.cdt.core.IAddress)
+                */
+               public IAddress toRuntimeAddress(IAddress linkAddress) {
+                       IAddress ret = null;
+
+                       for (IRuntimeSection s : runtimeSections) {
+                               long offset = s.getLinkAddress().distanceTo(linkAddress).longValue();
+                               if (offset >= 0 && offset < s.getSize()) {
+                                       return s.getRuntimeAddress().add(offset);
+                               }
+                       }
+
+                       return ret;
+               }
+
+               /**
+                * Get file name (without path) of the module.
+                * 
+                * @return
+                */
+               public String getFile() {
+                       return hostFilePath.lastSegment();
+               }
+
+               @Override
+               public String toString() {
+                       StringBuilder builder = new StringBuilder();
+                       builder.append("\nModuleDMC [");
+                       if (hostFilePath != null) {
+                               builder.append("file=");
+                               builder.append(hostFilePath.lastSegment());
+                               builder.append(", ");
+                       }
+                       
+                       if (symbolContext != null) {
+                               builder.append("owner=");
+                               builder.append(symbolContext.toString());
+                       }
+                       
+                       for (IRuntimeSection s : runtimeSections) {
+                               builder.append("\n");
+                               builder.append(s);
+                       }
+                       
+                       builder.append("]");
+                       
+                       return builder.toString();
+               }
+
+               @Override
+               public int hashCode() {
+                       final int prime = 31;
+                       int result = super.hashCode();
+                       result = prime * result + getOuterType().hashCode();
+                       result = prime * result + ((hostFilePath == null) ? 0 : hostFilePath.hashCode());
+                       result = prime * result + ((symbolContext == null) ? 0 : symbolContext.hashCode());
+                       return result;
+               }
+
+               @Override
+               public boolean equals(Object obj) {
+                       if (this == obj)
+                               return true;
+                       if (!super.equals(obj))
+                               return false;
+                       if (getClass() != obj.getClass())
+                               return false;
+                       ModuleDMC other = (ModuleDMC) obj;
+                       if (!getOuterType().equals(other.getOuterType()))
+                               return false;
+                       if (hostFilePath == null) {
+                               if (other.hostFilePath != null)
+                                       return false;
+                       } else if (!hostFilePath.equals(other.hostFilePath))
+                               return false;
+                       if (symbolContext == null) {
+                               if (other.symbolContext != null)
+                                       return false;
+                       } else if (!symbolContext.equals(other.symbolContext))
+                               return false;
+                       return true;
+               }
+
+               private IEDCModules getOuterType() {
+                       return Modules.this;
+               }
+       }
+
+       static class ModuleDMData implements IModuleDMData {
+
+               private final Map<String, Object> properties;
+
+               public ModuleDMData(ModuleDMC dmc) {
+                       properties = dmc.getProperties();
+               }
+
+               public String getFile() {
+                       return (String) properties.get(IModuleProperty.PROP_FILE);
+               }
+
+               public String getName() {
+                       return (String) properties.get(IEDCDMContext.PROP_NAME);
+               }
+
+               public long getTimeStamp() {
+                       return 0;
+                       // return (String) properties.get(IModuleProperty.PROP_TIME);
+               }
+
+               public String getBaseAddress() {
+                       // return hex string representation.
+                       //
+                       Object baseAddress = properties.get(IModuleProperty.PROP_IMAGE_BASE_ADDRESS);
+                       if (baseAddress == null)
+                               baseAddress = properties.get(IModuleProperty.PROP_CODE_ADDRESS);
+
+                       if (baseAddress != null)
+                               return baseAddress.toString();
+                       else
+                               return "";
+               }
+
+               public String getToAddress() {
+                       // TODO this should return the end address, e.g. base + size
+                       return getBaseAddress();
+               }
+
+               public boolean isSymbolsLoaded() {
+                       return false;
+               }
+
+               public long getSize() {
+                       Number moduleSize = (Number) properties.get(IModuleProperty.PROP_CODE_SIZE);
+                       if (moduleSize != null)
+                               return moduleSize.longValue();
+                       else
+                               return 0;
+               }
+
+       }
+
+       public static class ModuleLoadedEvent extends AbstractDMEvent<ISymbolDMContext> implements ModuleLoadedDMEvent {
+
+               private final ModuleDMC module;
+               private final IExecutionDMContext executionDMC;
+
+               public ModuleLoadedEvent(ISymbolDMContext symbolContext, IExecutionDMContext executionDMC, ModuleDMC module) {
+                       super(symbolContext);
+                       this.module = module;
+                       this.executionDMC = executionDMC;
+               }
+
+               public IExecutionDMContext getExecutionDMC() {
+                       return executionDMC;
+               }
+
+               public IModuleDMContext getLoadedModuleContext() {
+                       return module;
+               }
+
+       }
+
+       public static class ModuleUnloadedEvent extends AbstractDMEvent<ISymbolDMContext> implements ModuleUnloadedDMEvent {
+
+               private final ModuleDMC module;
+               private final IExecutionDMContext executionDMC;
+
+               public ModuleUnloadedEvent(ISymbolDMContext symbolContext, IExecutionDMContext executionDMC, ModuleDMC module) {
+                       super(symbolContext);
+                       this.module = module;
+                       this.executionDMC = executionDMC;
+               }
+
+               public IExecutionDMContext getExecutionDMC() {
+                       return executionDMC;
+               }
+
+               public IModuleDMContext getUnloadedModuleContext() {
+                       return module;
+               }
+
+       }
+
+       public Modules(DsfSession session) {
+               super(session, new String[] { IModules.class.getName(), IEDCModules.class.getName(), Modules.class.getName() });
+       }
+
+       public void setSourceLocator(ISourceLocator sourceLocator) {
+               this.sourceLocator = sourceLocator;
+       }
+
+       public ISourceLocator getSourceLocator() {
+               return sourceLocator;
+       }
+
+       private void addModule(ModuleDMC module) {
+               ISymbolDMContext symContext = module.getSymbolContext();
+               if (symContext instanceof IEDCDMContext) {
+                       String symContextID = ((IEDCDMContext) symContext).getID();
+                       synchronized (modules) {
+                               List<ModuleDMC> moduleList = modules.get(symContextID);
+                               if (moduleList == null) {
+                                       moduleList = Collections.synchronizedList(new ArrayList<ModuleDMC>());
+                                       modules.put(symContextID, moduleList);
+                               }
+                               moduleList.add(module);
+                       }
+               }
+       }
+
+       private void removeModule(ModuleDMC module) {
+               ISymbolDMContext symContext = module.getSymbolContext();
+               if (symContext instanceof IEDCDMContext) {
+                       String symContextID = ((IEDCDMContext) symContext).getID();
+                       synchronized (modules) {
+                               List<ModuleDMC> moduleList = modules.get(symContextID);
+                               if (moduleList != null) {
+                                       // other module attributes may not be passed during removal,
+                                       // so remove the module with the same name
+                                       for (ModuleDMC next : moduleList) {
+                                               if (next.getFile().equals(module.getFile())) {
+                                                       moduleList.remove(next);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+       }
+
+       /*
+        * The result AddressRange[] will contain absolute runtime addresses. And
+        * the "symCtx" can be a process or a module.
+        */
+       @SuppressWarnings("unchecked")
+       public void calcAddressInfo(ISymbolDMContext symCtx, String file, int line, int col,
+                       DataRequestMonitor<AddressRange[]> rm) {
+               IModuleDMContext[] moduleList = null;
+
+               if (symCtx instanceof IEDCExecutionDMC) {
+                       String symContextID = ((IEDCDMContext) symCtx).getID();
+                       moduleList = getModulesForContext(symContextID);
+               } else if (symCtx instanceof IModuleDMContext) {
+                       moduleList = new IModuleDMContext[1];
+                       moduleList[0] = (IModuleDMContext) symCtx;
+               } else {
+                       // should not happen
+                       assert false : "Unknown ISymbolDMContext class.";
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, MessageFormat.format(
+                                       "Unknown class implementing ISymbolDMContext : {0}", symCtx.getClass().getName()), null));
+                       rm.done();
+                       return;
+               }
+
+               List<EDCAddressRange> addrRanges = new ArrayList<EDCAddressRange>(1);
+               
+               for (IModuleDMContext module : moduleList) {
+                       ModuleDMC mdmc = (ModuleDMC) module;
+                       IEDCSymbolReader reader = mdmc.getSymbolReader();
+
+                       if (reader != null) {
+
+                               Collection<AddressRange> linkAddressRanges = null;
+                               Map<String, Collection<AddressRange>> cachedRanges = new HashMap<String, Collection<AddressRange>>();
+                               // Check the persistent cache
+                               String cacheKey = reader.getSymbolFile().toOSString() + ADDRESS_RANGE_CACHE;
+                               String noFileCacheKey = reader.getSymbolFile().toOSString() + NO_FILE_CACHE;
+                               Set<String> noFileCachedData = EDCDebugger.getDefault().getCache().getCachedData(noFileCacheKey, Set.class, reader.getModificationDate());
+                               if (noFileCachedData != null && noFileCachedData.contains(file))
+                                       continue; // We have already determined that this file is not used by this module, don't bother checking again.
+                               
+                               Map<String, Collection<AddressRange>> cachedData = EDCDebugger.getDefault().getCache().getCachedData(cacheKey, Map.class, reader.getModificationDate());
+                               if (cachedData != null)
+                               {
+                                       cachedRanges = cachedData;
+                                       linkAddressRanges = cachedRanges.get(file + line);
+                               }
+                               
+                               if (linkAddressRanges == null)
+                               {
+                                       linkAddressRanges = LineEntryMapper.getAddressRangesAtSource(  
+                                               reader.getModuleScope().getModuleLineEntryProvider(),
+                                               PathUtils.createPath(file),
+                                               line);
+                                       
+                                       if (linkAddressRanges == null)
+                                       { // If this file is not used by this module, cache it so we can avoid searching it again.
+                                               if (noFileCachedData == null)
+                                                       noFileCachedData = new HashSet<String>();
+                                               noFileCachedData.add(file);
+                                               EDCDebugger.getDefault().getCache().putCachedData(noFileCacheKey, (Serializable) noFileCachedData, reader.getModificationDate());                               
+                                               continue;
+                                       }
+                                       cachedRanges.put(file + line, linkAddressRanges);
+                                       EDCDebugger.getDefault().getCache().putCachedData(cacheKey, (Serializable) cachedRanges, reader.getModificationDate());                         
+                               }
+                                                               
+                               // convert addresses to runtime ones.
+                               for (AddressRange linkAddressRange : linkAddressRanges) {
+                                       EDCAddressRange addrRange = new EDCAddressRange(
+                                                       mdmc.toRuntimeAddress(linkAddressRange.getStartAddress()),
+                                                       mdmc.toRuntimeAddress(linkAddressRange.getEndAddress()));
+                                       addrRanges.add(addrRange);
+                               }
+                       }
+               }
+
+               if (addrRanges.size() > 0) {
+                       AddressRange[] ar = addrRanges.toArray(new AddressRange[addrRanges.size()]);
+                       rm.setData(ar);
+               } else {
+                       /*
+                        * we try to set the breakpoint for every module since we don't know
+                        * which one the file is in. we report this error though if the file
+                        * isn't in the module, and let the caller handle the error.
+                        */
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, MessageFormat.format(
+                                       "Fail to find address for source line {0}: line# {1}", file, line), null));
+               }
+
+               rm.done();
+       }
+
+       public void calcLineInfo(ISymbolDMContext symCtx, IAddress address, DataRequestMonitor<LineInfo[]> rm) {
+               // TODO Auto-generated method stub
+
+       }
+
+       /**
+        * Given a source line (let's call it anchor), find the line closest to the
+        * anchor in the neighborhood (including the anchor itself) that has machine
+        * code. If the anchor itself has code, it's returned. Otherwise neighbor
+        * lines both above and below the anchor will be checked. If the closest
+        * line above the anchor and the closest line below the anchor have the same
+        * distance from the anchor, the one below will be selected.
+        * 
+        * This is mainly used in setting breakpoint at anchor line.
+        * 
+        * @param symCtx
+        *            the symbol context in which to perform the lookup. It can be
+        *            an execution context (e.g. a process), or a module (exe or
+        *            dll) in a process.
+        * @param file
+        *            the file that contains the source lines in question.
+        * @param anchor
+        *            line number of the anchor source line.
+        * @param neighbor_limit
+        *            specify the limit of the neighborhood: up to this number of
+        *            lines above the anchor and up to this number of lines below
+        *            the anchor will be checked if needed. But the check will never
+        *            go beyond the source file. When the limit is zero, no neighbor
+        *            lines will be checked. If the limit has value of -1, it means
+        *            the actual limit is the source file.
+        * @param rm
+        *            contains an object of {@link ILineAddresses} if the line with
+        *            code is found. And addresses in it are runtime addresses. The
+        *            RM will contain error status otherwise.
+        */
+       public void findClosestLineWithCode(ISymbolDMContext symCtx, String file, int anchor, int neighbor_limit,
+                       DataRequestMonitor<ILineAddresses> rm) {
+               IModuleDMContext[] moduleList = null;
+
+               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null,
+                               "Find closest line with code. context: " + EDCTrace.fixArg(symCtx) + " file: " + file + " anchor: " + anchor + " limit: " + neighbor_limit); }
+
+               if (symCtx instanceof IEDCExecutionDMC) {
+                       String symContextID = ((IEDCDMContext) symCtx).getID();
+                       moduleList = getModulesForContext(symContextID);
+               } else if (symCtx instanceof IModuleDMContext) {
+                       moduleList = new IModuleDMContext[1];
+                       moduleList[0] = (IModuleDMContext) symCtx;
+               } else {
+                       // should not happen
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, MessageFormat.format(
+                                       "Unknown class implementing ISymbolDMContext : {0}", symCtx.getClass().getName()), null));
+                       rm.done();
+                       if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null,
+                                       rm.getStatus()); }
+                       return;
+               }
+
+               EDCLineAddresses result = null;
+               
+               for (IModuleDMContext module : moduleList) {
+                       ModuleDMC mdmc = (ModuleDMC) module;
+                       IEDCSymbolReader reader = mdmc.getSymbolReader();
+
+                       if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null,
+                                       "module: " + mdmc + " reader: " + reader); }
+
+                       if (reader == null) 
+                               continue;
+
+                       List<ILineAddresses> codeLines = null;
+                       
+                       Map<String, List<ILineAddresses>> cache = new HashMap<String, List<ILineAddresses>>();
+                       // Check the persistent cache
+                       String cacheKey = reader.getSymbolFile().toOSString() + LINE_ADDRESSES_CACHE;
+                       String noFileCacheKey = reader.getSymbolFile().toOSString() + NO_FILE_CACHE;
+                       @SuppressWarnings("unchecked")
+                       Set<String> noFileCachedData = EDCDebugger.getDefault().getCache().getCachedData(noFileCacheKey, Set.class, reader.getModificationDate());
+                       if (noFileCachedData != null && noFileCachedData.contains(file))
+                       {
+                               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null,
+                                               "Persistent cache says file not used by module"); }
+                               continue; // We have already determined that this file is not used by this module, don't bother checking again.
+                       }
+                       
+                       @SuppressWarnings("unchecked")
+                       Map<String, List<ILineAddresses>> cachedData = EDCDebugger.getDefault().getCache().getCachedData(cacheKey, Map.class, reader.getModificationDate());
+                       if (cachedData != null)
+                       {
+                               cache = cachedData;
+                               codeLines = cachedData.get(file + anchor);
+                       }
+                       
+                       if (codeLines == null)  // cache missed
+                       {
+                               if (! reader.getModuleScope().getModuleLineEntryProvider().hasSourceFile(PathUtils.createPath(file)))
+                               { // If this file is not used by this module, cache it so we can avoid searching it again.
+                                       if (noFileCachedData == null)
+                                               noFileCachedData = new HashSet<String>();
+                                       noFileCachedData.add(file);
+                                       EDCDebugger.getDefault().getCache().putCachedData(noFileCacheKey, (Serializable) noFileCachedData, reader.getModificationDate());                               
+                                       if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null,
+                                       "File not used by module"); }
+                                       continue;
+                               }
+                       
+                               codeLines = reader.getModuleScope().getModuleLineEntryProvider().findClosestLineWithCode(
+                                               PathUtils.createPath(file),     anchor, neighbor_limit);
+
+                               if (codeLines == null)
+                               {
+                                       if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null,
+                                       "codeLines == null"); }
+                                       continue;       // should not happen
+                               }
+                               
+                               // Cache code lines (with their link addresses), whether we find it or not.
+                               cache.put(file + anchor, codeLines);
+                               EDCDebugger.getDefault().getCache().putCachedData(cacheKey, (Serializable) cache, reader.getModificationDate());                                
+                               if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null,
+                                               "codeLines: " + codeLines); }
+                       }
+
+                       // convert addresses to runtime ones.
+                       //
+                       List<EDCLineAddresses> runtimeCLs = new ArrayList<Modules.EDCLineAddresses>(codeLines.size());
+                       for (ILineAddresses cl : codeLines) {
+                               List<IAddress> rt_addrs = new ArrayList<IAddress>(1);
+                               for (IAddress a : cl.getAddress())
+                                       rt_addrs.add(mdmc.toRuntimeAddress(a));
+                               runtimeCLs.add(new EDCLineAddresses(cl.getLineNumber(), rt_addrs));
+                       }
+                       
+                       for (ILineAddresses l : runtimeCLs) 
+                               result = selectCodeLine(result, l, anchor);
+               }
+
+               if (result != null) {
+                       rm.setData(result);
+               } else {
+                       /*
+                        * we try to set the breakpoint for every module since we don't know
+                        * which one the file is in. we report this error though if the file
+                        * isn't in the module, and let the caller handle the error.
+                        */
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, MessageFormat.format(
+                                       "Fail to find address sround source line {0}: line# {1}", file, anchor), null));
+               }
+
+               rm.done();
+       }
+       
+       private EDCLineAddresses selectCodeLine(EDCLineAddresses prevChoice,
+                       ILineAddresses newLine, int anchor) {
+               
+               if (prevChoice == null)
+                       prevChoice = (EDCLineAddresses)newLine;
+               else {
+                       if (newLine.getLineNumber() == prevChoice.getLineNumber()) {
+                               // merge the addresses. Same source line has different addresses in different module.
+                               prevChoice.addAddress(newLine.getAddress());
+                       }
+                       else {
+                               // code line is different for the anchor in different module
+                               if (newLine.getLineNumber() == anchor) 
+                                       // always honor anchor itself
+                                       prevChoice = (EDCLineAddresses)newLine;
+                               else if (prevChoice.getLineNumber() != anchor) {
+                                       /*
+                                        * Two different code lines are found (from different
+                                        * modules or different CUs) and neither of them is anchor.
+                                        * Don't bother returning both of them as that would cause
+                                        * unnecessary complexity to breakpoint setting as it means
+                                        * moving breakpoint set on anchor line to two different
+                                        * lines. Just keep the one closer to anchor. And user will
+                                        * see the breakpoint works in one module (or CU) but not
+                                        * the other.
+                                        */
+                                       int new_distance = Math.abs(newLine.getLineNumber() - anchor);
+                                       int prev_distance = Math.abs(prevChoice.getLineNumber() - anchor);
+                                       
+                                       if (new_distance < prev_distance)
+                                               prevChoice = (EDCLineAddresses)newLine;
+                                       else if (new_distance == prev_distance) {
+                                               // Same distance from anchor, choose the one below anchor
+                                               if (newLine.getLineNumber() > prevChoice.getLineNumber())
+                                                       prevChoice = (EDCLineAddresses)newLine;
+                                       }
+                               }
+                       }
+               }
+               
+               return prevChoice;
+       }
+
+       /**
+        * Get runtime addresses mapped to given source line in given run context.
+        *  
+        * @param context
+        * @param sourceFile
+        * @param lineNumber
+        * @param drm If no address found, holds an empty list.
+        */
+       public void getLineAddress(IExecutionDMContext context,
+                       String sourceFile, int lineNumber, final DataRequestMonitor<List<IAddress>> drm) {
+               final List<IAddress> addrs = new ArrayList<IAddress>(1);
+               
+               final ExecutionDMC dmc = (ExecutionDMC) context;
+               if (dmc == null) {
+                       drm.setData(addrs);
+                       drm.done();
+                       return;
+               }
+               
+               ISymbolDMContext symCtx = DMContexts.getAncestorOfType(context, ISymbolDMContext.class);
+
+               sourceFile = EDCLaunch.getLaunchForSession(getSession().getId()).getCompilationPath(sourceFile);
+
+               calcAddressInfo(symCtx, sourceFile, lineNumber, 0, 
+                               new DataRequestMonitor<AddressRange[]>(getExecutor(), drm) {
+
+                       @Override
+                       protected void handleCompleted() {
+                               if (! isSuccess()) {
+                                       drm.setStatus(getStatus());
+                                       drm.done();
+                                       return;
+                               }
+
+                               AddressRange[] addr_ranges = getData();
+
+                               for (AddressRange range : addr_ranges) {
+                                       IAddress a = range.getStartAddress();  // this is runtime address
+                                       addrs.add(a);
+                               }
+
+                               drm.setData(addrs);
+                               drm.done();
+                       }
+               });
+       }
+               
+       public void getModuleData(IModuleDMContext dmc, DataRequestMonitor<IModuleDMData> rm) {
+               rm.setData(new ModuleDMData((ModuleDMC) dmc));
+               rm.done();
+       }
+
+       public void getModules(ISymbolDMContext symCtx, DataRequestMonitor<IModuleDMContext[]> rm) {
+               String symContextID = ((IEDCDMContext) symCtx).getID();
+               IModuleDMContext[] moduleList = getModulesForContext(symContextID);
+               rm.setData(moduleList);
+               rm.done();
+       }
+
+       public IModuleDMContext[] getModulesForContext(String symContextID) {
+               synchronized (modules) {
+                       List<ModuleDMC> moduleList = modules.get(symContextID);
+                       if (moduleList == null)
+                               return new IModuleDMContext[0];
+                       else
+                               return moduleList.toArray(new IModuleDMContext[moduleList.size()]);
+               }
+       }
+
+       private int getNextModuleID() {
+               return nextModuleID++;
+       }
+
+       public void moduleLoaded(ISymbolDMContext symbolContext, IExecutionDMContext executionDMC, Map<String, Object> moduleProps) {
+               ModuleDMC module = new ModuleDMC(symbolContext, moduleProps);
+               module.relocateSections(moduleProps);
+               addModule(module);
+               getSession().dispatchEvent(new ModuleLoadedEvent(symbolContext, executionDMC, module),
+                               Modules.this.getProperties());
+       }
+
+       public void moduleUnloaded(ISymbolDMContext symbolContext, IExecutionDMContext executionDMC,
+                       Map<String, Object> moduleProps) {
+               Object fileName = moduleProps.get(IEDCDMContext.PROP_NAME);
+               ModuleDMC module = getModuleByName(symbolContext, fileName);
+               if (module == null) {
+                       EDCDebugger.getMessageLogger().logError("Unexpected unload of module: " + fileName, null);
+                       return;
+               }
+               Object requireResumeValue = moduleProps.get("RequireResume");
+               if (requireResumeValue != null && requireResumeValue instanceof Boolean)
+                       module.setProperty("RequireResume", requireResumeValue);
+               removeModule(module);
+               getSession().dispatchEvent(new ModuleUnloadedEvent(symbolContext, executionDMC, module),
+                               Modules.this.getProperties());
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCModules#getModuleByAddress(org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext, org.eclipse.cdt.core.IAddress)
+        */
+       public ModuleDMC getModuleByAddress(ISymbolDMContext symCtx, IAddress instructionAddress) {
+               ModuleDMC bestMatch = null;
+               if (symCtx instanceof ModuleDMC) {
+                       if (((ModuleDMC)symCtx).containsAddress(instructionAddress))
+                               bestMatch = (ModuleDMC)symCtx;
+               }
+               else {
+                       synchronized (modules) {
+                               List<ModuleDMC> moduleList = modules.get(((IEDCDMContext) symCtx).getID());
+                               if (moduleList != null) {
+                                       for (ModuleDMC moduleDMC : moduleList) {
+                                               if (moduleDMC.containsAddress(instructionAddress)) {
+                                                       bestMatch = moduleDMC;
+                                                       break;
+                                               }
+                                       }
+       
+                                       if (bestMatch == null) {
+                                               // TODO: add a bogus wrap-all module ?
+                                       }
+                               }
+                       }
+               }
+               return bestMatch;
+       }
+
+       /**
+        * Find the host file that corresponds to a given module file whose name
+        * comes from target platform.
+        * 
+        * @param originalPath
+        *            path or filename from target platform.
+        * @return the path to an existing file on host, null otherwise.
+        */
+       public IPath locateModuleFileOnHost(String originalPath) {
+               if (originalPath == null || originalPath.length() == 0)
+                       return Path.EMPTY;
+
+               // Canonicalize path for the host OS, in hopes of finding a match directly on the host,
+               // and for searching sources and executables below.
+               //
+               IPath path = PathUtils.findExistingPathIfCaseSensitive(PathUtils.createPath(originalPath));
+
+               // Try source locator, use the host-correct path.
+               //
+               Object sourceElement = null;
+               ISourceLocator locator = getSourceLocator();
+               if (locator != null) {
+                       if (locator instanceof ICSourceLocator || locator instanceof CSourceLookupDirector) {
+                               if (locator instanceof ICSourceLocator)
+                                       sourceElement = ((ICSourceLocator) locator).findSourceElement(path.toOSString());
+                               else
+                                       sourceElement = ((CSourceLookupDirector) locator).getSourceElement(path.toOSString());
+                       }
+                       if (sourceElement != null) {
+                               if (sourceElement instanceof LocalFileStorage) {
+                                       return new Path(((LocalFileStorage) sourceElement).getFile().getAbsolutePath());
+                               }
+                       }
+               }
+               
+               return path;
+       }
+
+       public void loadModulesForContext(ISymbolDMContext context, Element element) throws Exception {
+
+               List<ModuleDMC> contextModules = Collections.synchronizedList(new ArrayList<ModuleDMC>());
+
+               NodeList moduleElements = element.getElementsByTagName(MODULE);
+
+               int numModules = moduleElements.getLength();
+               for (int i = 0; i < numModules; i++) {
+                       Element moduleElement = (Element) moduleElements.item(i);
+                       Element propElement = (Element) moduleElement.getElementsByTagName(SnapshotUtils.PROPERTIES).item(0);
+                       HashMap<String, Object> properties = new HashMap<String, Object>();
+                       SnapshotUtils.initializeFromXML(propElement, properties);
+
+                       ModuleDMC module = new ModuleDMC(context, properties);
+                       module.loadSnapshot(moduleElement);
+                       contextModules.add(module);
+
+               }
+               modules.put(((IEDCDMContext) context).getID(), contextModules);
+
+       }
+       
+       /**
+        * get module with given file name
+        * 
+        * @param symCtx
+        * @param fileName
+        *            executable name for module
+        * @return null if not found.
+        */
+       public ModuleDMC getModuleByName(ISymbolDMContext symCtx, Object fileName) {
+               ModuleDMC module = null;
+               synchronized (modules) {
+                       List<ModuleDMC> moduleList = modules.get(((IEDCDMContext) symCtx).getID());
+                       if (moduleList != null) {
+                               for (ModuleDMC moduleDMC : moduleList) {
+                                       if ((moduleDMC.getName().compareToIgnoreCase((String) fileName)) == 0 ) {
+                                               module = moduleDMC;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               return module;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Noop.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Noop.java
new file mode 100644 (file)
index 0000000..2c6fc0b
--- /dev/null
@@ -0,0 +1,64 @@
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Implementation of the no-op service used for testing
+ *
+ */
+public class Noop extends AbstractEDCService implements INoop {
+
+       public Noop(DsfSession session) {
+               super(session, new String[] {INoop.class.getName()});
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.INoop#noop(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void noop(IDMContext ctx, DataRequestMonitor<Boolean> rm) {
+               rm.setData(true);
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.INoop#longNoop(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void longNoop(IDMContext whatever, final DataRequestMonitor<Boolean> rm) {
+               new Thread() {
+                       public void run() {
+                               try {
+                                       for (int i = 0; i < 100; i++) {
+                                               Thread.sleep(100);
+                                               if (rm.isCanceled()) {
+                                                       rm.setStatus(Status.CANCEL_STATUS);
+                                                       rm.done();
+                                                       return;
+                                               }
+                                       }
+                               } catch (InterruptedException e) {}
+                               rm.setData(true);
+                               rm.done();
+                       }
+               }.start();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.INoop#longNoopUsingServiceTracker(int, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+        */
+       public void longNoopUsingServiceTracker(int duration, RequestMonitor rm) {
+               for (int i = 0; i < duration; i++) {
+                       // ask for any service; our own is fine
+                       getService(INoop.class);
+                       try {
+                               Thread.sleep(1000);
+                       } catch (InterruptedException e) {
+                               return;
+                       }
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Processes.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Processes.java
new file mode 100644 (file)
index 0000000..4137a1c
--- /dev/null
@@ -0,0 +1,303 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC;
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+import org.eclipse.cdt.debug.edc.services.IDSFServiceUsingTCF;
+import org.eclipse.cdt.debug.edc.services.IEDCDMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCExecutionDMC;
+import org.eclipse.cdt.debug.edc.tcf.extension.ProtocolConstants;
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator2;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules;
+import org.eclipse.cdt.dsf.debug.service.IModules.IModuleDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+import org.eclipse.cdt.dsf.debug.service.IProcesses;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.tm.tcf.protocol.IService;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IProcesses.ProcessContext;
+
+public class Processes extends AbstractEDCService implements IProcesses, IEventListener, IDSFServiceUsingTCF {
+
+       private org.eclipse.tm.tcf.services.IProcesses tcfProcessesService;
+       
+       /*
+        * The data of a corresponding thread or process.
+        */
+       @Immutable
+       protected static class ExecutionDMData implements IThreadDMData {
+               String name = "unknown";
+               String id = "unknown";
+
+               public ExecutionDMData(ExecutionDMC dmc) {
+                       id = dmc.getProperty(ProtocolConstants.PROP_OS_ID).toString();
+                       name = (String) dmc.getProperty(IEDCDMContext.PROP_NAME);
+               }
+
+               public String getId() {
+                       return id;
+               }
+
+               public String getName() {
+                       return name;
+               }
+
+               public boolean isDebuggerAttached() {
+                       return true;
+               }
+       }
+
+       public Processes(DsfSession session) {
+               super(session, new String[] { IProcesses.class.getName(), Processes.class.getName() });
+       }
+
+       @Override
+       protected void doInitialize(RequestMonitor requestMonitor) {
+               super.doInitialize(requestMonitor);
+               getSession().addServiceEventListener(this, null);
+       }
+
+       public void attachDebuggerToProcess(IProcessDMContext procCtx, DataRequestMonitor<IDMContext> rm) {
+               rm.done();
+       }
+
+       public void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
+               ExecutionDMC edcDMC = (ExecutionDMC) dmc;
+               rm.setData(edcDMC.canDetach());
+               rm.done();
+       }
+
+       public void canTerminate(IThreadDMContext thread, DataRequestMonitor<Boolean> rm) {
+               ExecutionDMC executionDmc = (ExecutionDMC) thread;
+               rm.setData(executionDmc.canTerminate());
+               rm.done();
+       }
+
+       public void debugNewProcess(IDMContext dmc, String file, Map<String, Object> attributes,
+                       DataRequestMonitor<IDMContext> rm) {
+               rm.done();
+       }
+
+       /**
+        * Detach debugger from all processes in the debug session.
+        * @param rm
+        */
+       public void detachDebuggerFromSession(final RequestMonitor rm) {
+               RunControl rcService = getServicesTracker().getService(RunControl.class);
+               ExecutionDMC[] processes = rcService.getRootDMC().getChildren();
+               
+               CountingRequestMonitor crm = new CountingRequestMonitor(getExecutor(), rm);
+               
+               crm.setDoneCount(processes.length);
+               
+               for (ExecutionDMC p : processes)
+                       detachDebuggerFromProcess(p, crm);
+       }
+       
+       public void detachDebuggerFromProcess(final IDMContext exeDmc, final RequestMonitor rm) {
+               /*
+                * 1. Remove all breakpoints for all modules in the process.
+                * 2. Resume the process.
+                * 3. Detach the process from agent and host debugger.
+                */
+               
+               // Make sure detach from the process, not just a thread.
+               final IProcessDMContext dmc = DMContexts.getAncestorOfType(exeDmc, IProcessDMContext.class);
+
+               final BreakpointsMediator2 bmService = getServicesTracker().getService(BreakpointsMediator2.class);
+               if (bmService == null) {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "Failed to get BreakpointsMediator2 service."));
+                       rm.done();
+                       return;
+               }
+               IModules modulesService = getServicesTracker().getService(IModules.class);
+               if (modulesService == null) {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "Failed to get Modules service."));
+                       rm.done();
+                       return;
+               }
+
+               ISymbolDMContext symCtx = DMContexts.getAncestorOfType(dmc, ISymbolDMContext.class);
+               modulesService.getModules(symCtx, new DataRequestMonitor<IModules.IModuleDMContext[]>(getExecutor(), rm) {
+
+                       @Override
+                       protected void handleCompleted() {
+                               if (! isSuccess())
+                                       super.handleCompleted();
+                               else {
+                                       IModuleDMContext[] processModules = getData();
+                                       
+                                       CountingRequestMonitor bpRemovedCRM = new CountingRequestMonitor(getExecutor(), rm) {
+
+                                               @Override
+                                               protected void handleCompleted() {
+                                                       if (! isSuccess()) {
+                                                               super.handleCompleted();
+                                                               return;
+                                                       }
+                                                       
+                                                       // Now resume the process
+                                                       ((ExecutionDMC)dmc).resume(new RequestMonitor(getExecutor(), rm){
+
+                                                               @Override
+                                                               protected void handleCompleted() {
+                                                                       if (!isSuccess())
+                                                                               super.handleCompleted();
+                                                                       else {
+                                                                               doDetachDebugger((ExecutionDMC)dmc, rm);
+                                                                       }
+                                                               }
+                                                       });
+                                               }
+                                       }; 
+                                       
+                                       int bpTargetsDMCCnt = 0;
+                                       for (IModuleDMContext m : processModules) {
+                                               if (m instanceof IBreakpointsTargetDMContext) {
+                                                       // In EDC, each Module is a BpTargetsDMC.
+                                                       bpTargetsDMCCnt++;
+                                                       bmService.stopTrackingBreakpoints((IBreakpointsTargetDMContext)m, bpRemovedCRM);
+                                               }
+                                       }
+                                       assert bpTargetsDMCCnt > 0;
+                                       
+                                       bpRemovedCRM.setDoneCount(bpTargetsDMCCnt);
+                               }
+                       }});
+       }
+
+       /**
+        * ask debugger to do final detach: forget the process.
+        * 
+        * @param dmc
+        * @param rm
+        */
+       protected void doDetachDebugger(final ExecutionDMC dmc, final RequestMonitor rm) {
+               // First detach agent so that the program won't die when the agent dies.
+               // Then detach host debugger.
+               //
+               Protocol.invokeLater(new Runnable() {
+
+                       public void run() {
+                               tcfProcessesService.getContext(dmc.getID(), new org.eclipse.tm.tcf.services.IProcesses.DoneGetContext() {
+                                       
+                                       public void doneGetContext(IToken token, Exception error,
+                                                       ProcessContext context) {
+                                               if (error != null) {
+                                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "Fail to get TCF context for process: " + dmc.getID(), error));
+                                                       rm.done();
+                                               }
+                                               else {
+                                                       context.detach(new org.eclipse.tm.tcf.services.IProcesses.DoneCommand() {
+                                                               
+                                                               public void doneCommand(IToken token, Exception error) {
+                                                                       if (error != null)
+                                                                               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "Fail to detach process \"" + dmc.getID() + "\" from TCF agent.", error));
+                                                                       else {
+                                                                               // everything ok, now detach from host debugger,
+                                                                               // which will shutdown the debug session if the process
+                                                                               // is the last one.
+                                                                               dmc.detach();
+                                                                       }
+                                                                       rm.done();
+                                                               }
+                                                       });
+                                               }
+                                       }
+                               });
+                               
+                       }});
+       }
+
+       public void getDebuggingContext(IThreadDMContext dmc, DataRequestMonitor<IDMContext> rm) {
+               rm.done();
+       }
+
+       public void getExecutionData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm) {
+               if (dmc instanceof IEDCExecutionDMC)
+                       rm.setData(new ExecutionDMData((ExecutionDMC) dmc));
+               rm.done();
+       }
+
+       public void getProcessesBeingDebugged(IDMContext dmc, DataRequestMonitor<IDMContext[]> rm) {
+               rm.setData(new IDMContext[0]);
+               DsfServicesTracker tracker = getServicesTracker();
+               if (tracker != null) {
+                       RunControl runcontrol = tracker.getService(RunControl.class);
+                       if (runcontrol != null) {
+                               IDMContext[] processes = runcontrol.getRootDMC().getChildren();
+                               rm.setData(processes);
+                       }
+               }
+               rm.done();
+       }
+
+       public void getRunningProcesses(IDMContext dmc, DataRequestMonitor<IProcessDMContext[]> rm) {
+               rm.done();
+       }
+
+       public void isDebugNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
+               rm.done();
+       }
+
+       public void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
+               rm.done();
+       }
+
+       public void isRunNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
+               rm.done();
+       }
+
+       public void runNewProcess(IDMContext dmc, String file, Map<String, Object> attributes,
+                       DataRequestMonitor<IProcessDMContext> rm) {
+               rm.done();
+       }
+
+       public void terminate(IThreadDMContext thread, RequestMonitor requestMonitor) {
+               ExecutionDMC executionDmc = (ExecutionDMC) thread;
+               executionDmc.terminate(requestMonitor);
+       }
+
+       public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
+               rm.done();
+       }
+
+       // Event handler when a thread or a threadGroup exits
+       @DsfServiceEventHandler
+       public void eventDispatched(IExitedDMEvent e) {
+       }
+
+       public void eventReceived(Object output) {
+       }
+
+       public void tcfServiceReady(IService service) {
+               assert service instanceof org.eclipse.tm.tcf.services.IProcesses;
+               tcfProcessesService = (org.eclipse.tm.tcf.services.IProcesses) service;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/RunControl.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/RunControl.java
new file mode 100644 (file)
index 0000000..aee60e1
--- /dev/null
@@ -0,0 +1,2761 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import java.nio.ByteBuffer;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.IAddressExpressionEvaluator;
+import org.eclipse.cdt.debug.edc.IJumpToAddress;
+import org.eclipse.cdt.debug.edc.JumpToAddress;
+import org.eclipse.cdt.debug.edc.disassembler.IDisassembledInstruction;
+import org.eclipse.cdt.debug.edc.disassembler.IDisassembler;
+import org.eclipse.cdt.debug.edc.disassembler.IDisassembler.IDisassemblerOptions;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Breakpoints.BreakpointDMData;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.EDCAddressRange;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleDMC;
+import org.eclipse.cdt.debug.edc.internal.snapshot.Album;
+import org.eclipse.cdt.debug.edc.internal.snapshot.SnapshotUtils;
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+import org.eclipse.cdt.debug.edc.services.DMContext;
+import org.eclipse.cdt.debug.edc.services.Disassembly;
+import org.eclipse.cdt.debug.edc.services.IDSFServiceUsingTCF;
+import org.eclipse.cdt.debug.edc.services.IEDCDMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCExecutionDMC;
+import org.eclipse.cdt.debug.edc.services.IEDCModuleDMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCModules;
+import org.eclipse.cdt.debug.edc.services.IEDCSymbols;
+import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
+import org.eclipse.cdt.debug.edc.services.Registers;
+import org.eclipse.cdt.debug.edc.services.Registers.RegisterDMC;
+import org.eclipse.cdt.debug.edc.services.Registers.RegisterGroupDMC;
+import org.eclipse.cdt.debug.edc.services.Stack;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.services.Stack.VariableDMC;
+import org.eclipse.cdt.debug.edc.snapshot.IAlbum;
+import org.eclipse.cdt.debug.edc.snapshot.ISnapshotContributor;
+import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.debug.edc.symbols.IModuleLineEntryProvider;
+import org.eclipse.cdt.debug.edc.tcf.extension.ProtocolConstants;
+import org.eclipse.cdt.debug.edc.tcf.extension.ProtocolConstants.IModuleProperty;
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules.IModuleDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
+import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IRunControl2;
+import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMContext;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.debug.core.model.MemoryByte;
+import org.eclipse.tm.tcf.protocol.IService;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IRunControl.DoneCommand;
+import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class RunControl extends AbstractEDCService implements IRunControl2, ICachingService, ISnapshotContributor,
+               IDSFServiceUsingTCF {
+
+       public static final String EXECUTION_CONTEXT = "execution_context";
+       public static final String EXECUTION_CONTEXT_REGISTERS = "execution_context_registers";
+       public static final String EXECUTION_CONTEXT_MODULES = "execution_context_modules";
+       public static final String EXECUTION_CONTEXT_FRAMES = "execution_context_frames";
+       /**
+        * Context property names. Properties that are optional but have default
+        * implicit values are indicated below
+        */
+       public static final String 
+                       PROP_PARENT_ID = "ParentID", 
+                       PROP_IS_CONTAINER = "IsContainer",       // default = true
+                       PROP_HAS_STATE = "HasState",
+                       PROP_CAN_RESUME = "CanResume",       // default = true
+                       PROP_CAN_COUNT = "CanCount",
+                       PROP_CAN_SUSPEND = "CanSuspend",     // default = true
+                       PROP_CAN_TERMINATE = "CanTerminate", // default = false
+                       PROP_IS_SUSPENDED = "State",         // default = false          
+                       PROP_MESSAGE = "Message", 
+                       PROP_SUSPEND_PC = "SuspendPC",
+                       PROP_DISABLE_STEPPING = "DisableStepping";
+
+       /*
+        * See where this is used for more.
+        */
+       private static final int RESUME_NOTIFICATION_DELAY = 1000;      // milliseconds
+       
+       // Whether module is being loaded (if true) or unloaded (if false)
+
+       public abstract static class DMCSuspendedEvent extends AbstractDMEvent<IExecutionDMContext> {
+
+               private final StateChangeReason reason;
+               private final Map<String, Object> params;
+
+               public DMCSuspendedEvent(IExecutionDMContext dmc, StateChangeReason reason, Map<String, Object> params) {
+                       super(dmc);
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { dmc, reason, params })); }
+                       this.reason = reason;
+                       this.params = params;
+               }
+
+               public StateChangeReason getReason() {
+                       return reason;
+               }
+
+               public Map<String, Object> getParams() {
+                       return params;
+               }
+               
+       }
+       
+       public static class SuspendedEvent extends DMCSuspendedEvent implements ISuspendedDMEvent {
+
+               public SuspendedEvent(IExecutionDMContext dmc,
+                               StateChangeReason reason, Map<String, Object> params) {
+                       super(dmc, reason, params);
+               }
+
+       }
+
+       public static class ContainerSuspendedEvent extends DMCSuspendedEvent implements IContainerSuspendedDMEvent {
+
+               public ContainerSuspendedEvent(IExecutionDMContext dmc,
+                               StateChangeReason reason, Map<String, Object> params) {
+                       super(dmc, reason, params);
+               }
+
+               public IExecutionDMContext[] getTriggeringContexts() {
+                       return new IExecutionDMContext[]{getDMContext()};
+               }
+       }
+
+       public abstract static class DMCResumedEvent extends AbstractDMEvent<IExecutionDMContext> {
+
+               public DMCResumedEvent(IExecutionDMContext dmc) {
+                       super(dmc);
+               }
+
+               public StateChangeReason getReason() {
+                       return StateChangeReason.USER_REQUEST;
+               }
+       }
+
+       public static class ResumedEvent extends DMCResumedEvent implements IResumedDMEvent {
+
+               public ResumedEvent(IExecutionDMContext dmc) {
+                       super(dmc);
+               }
+       }
+
+       public static class ContainerResumedEvent extends DMCResumedEvent implements IContainerResumedDMEvent {
+
+               public ContainerResumedEvent(IExecutionDMContext dmc) {
+                       super(dmc);
+               }
+
+               public IExecutionDMContext[] getTriggeringContexts() {
+                       return new IExecutionDMContext[]{getDMContext()};
+               }
+}
+
+       private static StateChangeReason toDsfStateChangeReason(String tcfReason) {
+               if (tcfReason == null)
+                       return StateChangeReason.UNKNOWN;
+               if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_USER_REQUEST))
+                       return StateChangeReason.USER_REQUEST;
+               if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_STEP))
+                       return StateChangeReason.STEP;
+               if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_BREAKPOINT))
+                       return StateChangeReason.BREAKPOINT;
+               if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_EXCEPTION))
+                       return StateChangeReason.EXCEPTION;
+               if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_CONTAINER))
+                       return StateChangeReason.CONTAINER;
+               if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_WATCHPOINT))
+                       return StateChangeReason.WATCHPOINT;
+               if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_SIGNAL))
+                       return StateChangeReason.SIGNAL;
+               if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_SHAREDLIB))
+                       return StateChangeReason.SHAREDLIB;
+               if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_ERROR))
+                       return StateChangeReason.ERROR;
+               return StateChangeReason.UNKNOWN;
+       }
+
+       @Immutable
+       private static class ExecutionData implements IExecutionDMData2 {
+               private final StateChangeReason reason;
+               private final String details;
+
+               ExecutionData(StateChangeReason reason, String details) {
+                       this.reason = reason;
+                       this.details = details;
+               }
+
+               public StateChangeReason getStateChangeReason() {
+                       return reason;
+               }
+
+               public String getDetails() {
+                       return details;
+               }
+       }
+
+       public abstract class ExecutionDMC extends DMContext implements IExecutionDMContext,
+                       ISnapshotContributor, IEDCExecutionDMC {
+
+               private final List<ExecutionDMC> children = Collections.synchronizedList(new ArrayList<ExecutionDMC>());
+               private StateChangeReason stateChangeReason = StateChangeReason.UNKNOWN;
+               private String stateChangeDetails = null;
+               private final RunControlContext tcfContext;
+               private final ExecutionDMC parentExecutionDMC;
+               private String latestPC = null;
+               private RequestMonitor steppingRM = null;
+               private boolean isStepping = false;
+               
+               // See where this is used for more.
+               private int countOfScheduledNotifications = 0 ;
+
+               /**
+                * Whether user chose to "terminate" or "disconnect" the context.
+                */
+               private boolean isTerminatingThanDisconnecting = false;
+               
+               private List<EDCAddressRange> disabledRanges = Collections.synchronizedList(new ArrayList<EDCAddressRange>());
+               private boolean suspendEventsEnabled = true;
+               
+               public ExecutionDMC(ExecutionDMC parent, Map<String, Object> props, RunControlContext tcfContext) {
+                       super(RunControl.this, parent == null ? new IDMContext[0] : new IDMContext[] { parent }, props);
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { parent, properties })); }
+                       this.parentExecutionDMC = parent;
+                       this.tcfContext = tcfContext;
+                       if (props != null) {
+                               dmcsByID.put(getID(), this);
+                       }
+                       if (parent != null)
+                               parent.addChild(this);
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               private void addChild(ExecutionDMC executionDMC) {
+                       synchronized (children) {
+                               children.add(executionDMC);
+                       }
+               }
+
+               private void removeChild(IEDCExecutionDMC executionDMC) {
+                       synchronized (children) {
+                               children.remove(executionDMC);
+                       }
+               }
+
+               public ExecutionDMC[] getChildren() {
+                       synchronized (children) {
+                               return children.toArray(new ExecutionDMC[children.size()]);
+                       }
+               }
+
+               public boolean wantFocusInUI() {
+                       Boolean wantFocus = (Boolean)properties.get(ProtocolConstants.PROP_WANT_FOCUS_IN_UI);
+                       if (wantFocus == null)
+                               wantFocus = true;       // default if unknown (not set by debug agent).
+                       return wantFocus;
+               }
+
+               public abstract ExecutionDMC contextAdded(Map<String, Object> properties, RunControlContext tcfContext);
+
+               public abstract boolean canDetach();
+               
+               public abstract boolean canStep();
+
+               public void loadSnapshot(Element element) throws Exception {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(element)); } 
+                       NodeList ecElements = element.getElementsByTagName(EXECUTION_CONTEXT);
+                       int numcontexts = ecElements.getLength();
+                       for (int i = 0; i < numcontexts; i++) {
+                               Element contextElement = (Element) ecElements.item(i);
+                               if (contextElement.getParentNode().equals(element)) {
+                                       try {
+                                               Element propElement = (Element) contextElement.getElementsByTagName(SnapshotUtils.PROPERTIES)
+                                                               .item(0);
+                                               HashMap<String, Object> properties = new HashMap<String, Object>();
+                                               SnapshotUtils.initializeFromXML(propElement, properties);
+                                               ExecutionDMC exeDMC = contextAdded(properties, null);
+                                               exeDMC.loadSnapshot(contextElement);
+                                       } catch (CoreException e) {
+                                               EDCDebugger.getMessageLogger().logError(null, e);
+                                       }
+                               }
+
+                       }
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor)throws Exception {
+                       Element contextElement = document.createElement(EXECUTION_CONTEXT);
+                       contextElement.setAttribute(PROP_ID, this.getID());
+
+                       Element propsElement = SnapshotUtils.makeXMLFromProperties(document, getProperties());
+                       contextElement.appendChild(propsElement);
+
+                       ExecutionDMC[] dmcs = getChildren();
+                       SubMonitor progress = SubMonitor.convert(monitor, dmcs.length * 1000);
+                       progress.subTask(getName());
+                       
+                       for (ExecutionDMC executionDMC : dmcs) {
+                               Element dmcElement = executionDMC.takeSnapshot(album, document, progress.newChild(1000));
+                               contextElement.appendChild(dmcElement);
+                       }
+
+                       return contextElement;
+               }
+
+               public boolean isSuspended() {
+                       synchronized (properties) {
+                               return RunControl.getProperty(properties, PROP_IS_SUSPENDED, false);
+                       }
+               }
+
+               public StateChangeReason getStateChangeReason() {
+                       return stateChangeReason;
+               }
+
+               public String getStateChangeDetails() {
+                       return stateChangeDetails;
+               }
+
+               public void setIsSuspended(boolean isSuspended) {
+                       synchronized (properties) {
+                               properties.put(PROP_IS_SUSPENDED, isSuspended);
+                       }
+                       if (getParent() != null)
+                               getParent().childIsSuspended(isSuspended);
+               }
+
+               private void childIsSuspended(boolean isSuspended) {
+                       if (isSuspended) {
+                               setIsSuspended(true);
+                       } else {
+                               boolean anySuspended = false;
+                               for (ExecutionDMC childDMC : getChildren()) {
+                                       if (childDMC.isSuspended()) {
+                                               anySuspended = true;
+                                               break;
+                                       }
+                               }
+                               if (!anySuspended)
+                                       setIsSuspended(false);
+                       }
+               }
+
+               protected void contextException(String msg) {
+               assert getExecutor().isInExecutorThread();
+
+               setIsSuspended(true);
+                       synchronized (properties) {
+                               properties.put(PROP_MESSAGE, msg);
+                       }
+                       stateChangeReason = StateChangeReason.EXCEPTION;
+                       getSession().dispatchEvent(
+                                       createSuspendedEvent(StateChangeReason.EXCEPTION, new HashMap<String, Object>()),
+                                       RunControl.this.getProperties());
+               }
+
+               protected void contextSuspended(String pc, String reason, final Map<String, Object> params) {
+               assert getExecutor().isInExecutorThread();
+
+               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(new Object[] { pc, reason, params })); }
+                       if (pc != null) {
+                               // the PC from TCF agent is decimal string.
+                               // convert it to hex string.
+                               pc = Long.toHexString(Long.parseLong(pc));
+                       }
+
+                       latestPC = pc;
+
+                       setIsSuspended(true);
+                       synchronized (properties) {
+                               properties.put(PROP_MESSAGE, reason);
+                               properties.put(PROP_SUSPEND_PC, pc);
+                       }
+                       stateChangeReason = toDsfStateChangeReason(reason);
+
+                       if (stateChangeReason == StateChangeReason.SHAREDLIB) {
+                               handleModuleEvent(this, params);
+                       } else {
+
+                               properties.put(PROP_DISABLE_STEPPING, params.get(ProtocolConstants.PROP_DISABLE_STEPPING));
+                               properties.put(ProtocolConstants.PROP_WANT_FOCUS_IN_UI, params.get(ProtocolConstants.PROP_WANT_FOCUS_IN_UI));
+
+                               stateChangeDetails = (String) params.get(ProtocolConstants.PROP_SUSPEND_DETAIL);
+                               
+                               // TODO This is not what the stateChangeDetails is for, we need an extended thread description
+                               // and is "foreground" really the right term?
+                               
+                               // Show the context is foreground one, if possible.
+                               //
+                               Boolean isForeground = (Boolean)params.get(ProtocolConstants.PROP_IS_FOREGROUND);
+                               if (isForeground != null)
+                                       stateChangeDetails += isForeground ? " [foreground]" : "";
+                               
+                               final ExecutionDMC dmc = this;
+
+                               final DataRequestMonitor<Boolean> preprocessDrm = new DataRequestMonitor<Boolean>(getExecutor(), null) {
+                                       @Override
+                                       protected void handleCompleted() {
+                                               Boolean honorSuspend = getData();
+                                               
+                                               if (honorSuspend!=null && honorSuspend) { // do suspend
+
+                                                       // All the following must be done in DSF dispatch
+                                                       // thread to ensure data integrity.
+
+                                                       // Mark done of the single step RM, if any pending.
+                                                       if (steppingRM != null) {
+                                                               steppingRM.done();
+                                                               steppingRM = null;
+                                                       }
+
+                                                       // Mark any stepping as done.
+                                                       setStepping(false);
+
+                                                       // Remove temporary breakpoints set by stepping.
+                                                       // Note we don't want to do this on a sharedLibrary
+                                                       // event as otherwise
+                                                       // stepping will be screwed up by that event.
+                                                       //
+                                                       Breakpoints bpService = getService(Breakpoints.class);
+                                                       bpService.removeAllTempBreakpoints(new RequestMonitor(getExecutor(), null));
+                                                       
+                                                       // check to see if we are in a disabled range
+                                                       IAddress pcAddress = new Addr64(dmc.getPC(), 16);
+                                                       EDCAddressRange disabledRange = dmc.getDisabledRange(pcAddress);
+                                                       if (disabledRange != null)
+                                                       {
+                                                               stepAddressRange(dmc, false, pcAddress, disabledRange.getEndAddress(), new RequestMonitor(getExecutor(), null));
+                                                       }
+                                                       else
+                                                       {
+                                                               // Only after completion of those preprocessing do 
+                                                               // we fire the event.
+                                                               if (dmc.suspendEventsEnabled())
+                                                                       getSession().dispatchEvent(dmc.createSuspendedEvent(stateChangeReason, params),
+                                                                               RunControl.this.getProperties());
+                                                       }
+                                                       dmc.clearDisabledRanges();
+                                               } else { 
+                                                       // ignore suspend if, say, breakpoint condition is not met.
+                                                       RunControl.this.resume(dmc, new RequestMonitor(getExecutor(), null));
+                                               }
+                                       }
+                               };
+                               
+                               preprocessOnSuspend(dmc, latestPC, preprocessDrm);
+                       }
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               protected boolean suspendEventsEnabled() {
+                       return suspendEventsEnabled ;
+               }
+               
+               protected void setSuspendEventsEnabled(boolean enabled)
+               {
+                       suspendEventsEnabled = enabled;
+               }
+
+               protected void clearDisabledRanges() {
+                       disabledRanges.clear();
+               }
+
+               /**
+                * handle module load event and unload event. A module is an executable file
+                * or a library (e.g. DLL or shared lib).
+                * 
+                * @param dmc
+                * @param moduleProperties
+                */
+               private void handleModuleEvent(final IEDCExecutionDMC dmc, final Map<String, Object> moduleProperties) {
+                       // The following needs be done in DSF dispatch thread.
+                       getSession().getExecutor().execute(new Runnable() {
+                               public void run() {
+                                       // based on properties, either load or unload the module
+                                       boolean loaded = true;
+                                       Object loadedValue = moduleProperties.get(IModuleProperty.PROP_MODULE_LOADED);
+                                       if (loadedValue != null) {
+                                               if (loadedValue instanceof Boolean)
+                                                       loaded = (Boolean) loadedValue;
+                                       }
+
+                                       if (loaded)
+                                               handleModuleLoadedEvent(dmc, moduleProperties);
+                                       else
+                                               handleModuleUnloadedEvent(dmc, moduleProperties);
+                               }
+                       });
+               }
+               
+               public Boolean canTerminate() {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null); }
+                       boolean result = false;
+                       synchronized (properties) {
+                               result = RunControl.getProperty(properties, PROP_CAN_TERMINATE, result);
+                       }
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null, result); }
+                       return result;
+               }
+
+               /**
+                * Resume the context.
+                * 
+                * @param rm
+                *            this is marked done as long as the resume command
+                *            succeeds.
+                */
+               public boolean supportsStepMode(StepType type) {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this)); }
+
+                       int mode = 0;
+                       switch (type) {
+                       case STEP_OVER:
+                               mode = org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OVER_RANGE;
+                               break;
+                       case STEP_INTO:
+                               mode = org.eclipse.tm.tcf.services.IRunControl.RM_STEP_INTO_RANGE;
+                               break;
+                       case STEP_RETURN:
+                               mode = org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OUT;
+                               break;
+                       case INSTRUCTION_STEP_OVER:
+                               mode = org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OVER;
+                               break;
+                       case INSTRUCTION_STEP_INTO:
+                               mode = org.eclipse.tm.tcf.services.IRunControl.RM_STEP_INTO;
+                               break;
+                       }
+
+                       if (hasTCFContext())
+                               return getTCFContext().canResume(mode);
+                       else
+                               return false;
+               }
+
+               /**
+                * Resume the context.
+                * 
+                * @param rm
+                *            this is marked done as long as the resume command
+                *            succeeds.
+                */
+               public void resume(final RequestMonitor rm) {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this)); }
+
+                       flushCache(this);
+
+                       if (hasTCFContext()) {
+                               Protocol.invokeLater(new Runnable() {
+                                       public void run() {
+                                               getTCFContext()
+                                                               .resume(org.eclipse.tm.tcf.services.IRunControl.RM_RESUME,
+                                                                               0, new DoneCommand() {
+
+                                                                                       public void doneCommand(
+                                                                                                       IToken token,
+                                                                                                       final Exception error) {
+                                                                                               getExecutor().execute(
+                                                                                                               new Runnable() {
+                                                                                                                       public void run() {
+                                                                                                                               if (error == null) {
+                                                                                                                                       contextResumed(true);
+                                                                                                                                       if (EDCTrace.RUN_CONTROL_TRACE_ON) {
+                                                                                                                                               EDCTrace.getTrace().trace(null, "Resume command succeeded.");
+                                                                                                                                       }
+                                                                                                                               } else {
+                                                                                                                                       if (EDCTrace.RUN_CONTROL_TRACE_ON) {
+                                                                                                                                               EDCTrace.getTrace().trace(null, "Resume command failed.");
+                                                                                                                                       }
+                                                                                                                                       rm.setStatus(new Status(
+                                                                                                                                                       IStatus.ERROR,
+                                                                                                                                                       EDCDebugger.PLUGIN_ID,
+                                                                                                                                                       REQUEST_FAILED,
+                                                                                                                                                       "Resume failed.",
+                                                                                                                                                       null));
+                                                                                                                               }
+                                                                                                                               rm.done();
+                                                                                                                       }
+                                                                                                               });
+                                                                                       }
+                                                                               });
+                                       }
+                               });
+                       }
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               /**
+                * Resume the context but the request monitor is only marked done when
+                * the context is suspended. (vs. regular resume()). <br>
+                * Note this method does not wait for suspended-event.
+                * 
+                * @param rm
+                */
+               protected void resumeForStepping(final RequestMonitor rm) {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this)); }
+
+                       setStepping(true);
+
+                       flushCache(this);
+
+                       if (hasTCFContext()) {
+                               Protocol.invokeLater(new Runnable() {
+                                       public void run() {
+                                               getTCFContext().resume(org.eclipse.tm.tcf.services.IRunControl.RM_RESUME,
+                                                                               0, new DoneCommand() {
+
+                                                                                       public void doneCommand(
+                                                                                                       IToken token,
+                                                                                                       final Exception error) {
+                                                                                               // do this in DSF executor thread.
+                                                                                               getExecutor().execute(
+                                                                                                               new Runnable() {
+                                                                                                                       public void run() {
+                                                                                                                               handleTCFResumeDoneForStepping(
+                                                                                                                                               "ResumeForStepping",
+                                                                                                                                               error,
+                                                                                                                                               rm);
+                                                                                                                       }
+                                                                                                               });
+                                                                                       }
+                                                                               });
+                                       }
+                               });
+                       }
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               private void handleTCFResumeDoneForStepping(String command, Exception tcfError, RequestMonitor rm) {
+                       assert getExecutor().isInExecutorThread();
+                       
+                       String msg = command;
+                       if (tcfError == null) {
+                               msg += " succeeded.";
+                               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().trace(null, msg); }
+                               contextResumed(false);
+
+                               // we'll mark it as done when we get next
+                               // suspend event.
+                               assert steppingRM == null;
+                               steppingRM = rm;
+                       } else {
+                               msg += " failed.";
+                               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().trace(null, msg); }
+
+                               setStepping(false);
+                               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, msg, tcfError));
+                               rm.done();
+                       }
+               }
+
+               public void suspend(final RequestMonitor requestMonitor) {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this)); }
+                       if (isSnapshot())
+                       {
+                               Album.getAlbumBySession(getSession().getId()).stopPlayingSnapshots();                           
+                       }
+                       else
+                       if (hasTCFContext()) {
+                               Protocol.invokeLater(new Runnable() {
+                                       public void run() {
+                                               getTCFContext().suspend(new DoneCommand() {
+
+                                                       public void doneCommand(IToken token,
+                                                                       Exception error) {
+                                                               if (EDCTrace.RUN_CONTROL_TRACE_ON) {
+                                                                       EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this));
+                                                               }
+                                                               requestMonitor.done();
+                                                               if (EDCTrace.RUN_CONTROL_TRACE_ON) {
+                                                                       EDCTrace.getTrace().traceExit(null);
+                                                               }
+                                                       }
+                                               });
+                                       }
+                               });
+                       }
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               public void terminate(final RequestMonitor requestMonitor) {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this)); }
+
+                       isTerminatingThanDisconnecting = true;
+                       
+                       if (hasTCFContext()) {
+                               Protocol.invokeLater(new Runnable() {
+                                       public void run() {
+                                               getTCFContext().terminate(new DoneCommand() {
+
+                                                       public void doneCommand(IToken token, Exception error) {
+                                                               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this)); }
+                                                               if (error != null) {
+                                                                       requestMonitor.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, 
+                                                                                       "terminate() failed.", error));
+                                                               }
+                                                               
+                                                               requestMonitor.done();
+                                                               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+                                                       }
+                                               });
+                                       }
+                               });
+                       } else {        
+                               // Snapshots, for e.g., don't have a TCF RunControlContext, so just remove all the contexts recursively
+                               detachAllContexts();
+                       }
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               protected ExecutionDMC getParent() {
+                       return parentExecutionDMC;
+               }
+
+               /**
+                * get latest PC register value of the context.
+                * 
+                * @return hex string of the PC value.
+                */
+               public String getPC() {
+                       return latestPC;
+               }
+               
+               /**
+                * Change cached PC value.
+                * This is only supposed to be used for move-to-line & resume-from-line commands.
+                *  
+                * @param pc
+                */
+               private void setPC(String pc) {
+                       latestPC = pc;
+               }
+
+               /**
+                * Detach debugger from this context and all its children.
+                */
+               public void detach(){
+                       isTerminatingThanDisconnecting = false;
+                       /**
+                        * agent side detaching is invoked by Processes service.
+                        * Here we just purge the context.
+                        */
+                       purgeFromDebugger();
+               }
+
+               /**
+                * Purge this context and all its children and grand-children
+                * from debugger UI and internal data cache.
+                */
+               public void purgeFromDebugger(){
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null); }
+
+                       for (ExecutionDMC e : getChildren())
+                               // recursively forget children first
+                               e.purgeFromDebugger();
+
+                       ExecutionDMC parent = getParent();
+                       if (parent != null)
+                               parent.removeChild(this);
+                       
+                       getSession().dispatchEvent(new ExitedEvent(this, isTerminatingThanDisconnecting), RunControl.this.getProperties());
+                       
+                       if (getRootDMC().getChildren().length == 0) 
+                               // no more contexts under debug, fire exitedEvent for the rootDMC which
+                               // will trigger shutdown of the debug session.
+                               // See EDCLaunch.eventDispatched(IExitedDMEvent e).
+                               // Whether the root is terminated or disconnected depends on whether 
+                               // the last context is terminated or disconnected.
+                               getSession().dispatchEvent(new ExitedEvent(getRootDMC(), isTerminatingThanDisconnecting), RunControl.this.getProperties());
+                       
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               /**
+                * Recursively marks all execution contexts as resumed
+                * @param dmc
+                */
+               public void resumeAll(){
+                       contextResumed(true);                   
+                       for (ExecutionDMC e : getChildren()){
+                               e.resumeAll();
+                       }
+               }
+               
+               protected void contextResumed(boolean fireResumeEventNow) {
+               assert getExecutor().isInExecutorThread();
+
+               if (children.size() > 0) {
+                       // If it has kids (e.g. a process has threads), only need
+                       // to mark the kids as resumed.
+                       for (ExecutionDMC e : children){
+                                       e.contextResumed(fireResumeEventNow);
+                               }
+                       return;
+               }
+               
+               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { this, fireResumeEventNow })); }
+                       
+                       setIsSuspended(false);
+                       
+                       if (fireResumeEventNow)
+                               getSession().dispatchEvent(this.createResumedEvent(), RunControl.this.getProperties());
+                       else
+                               scheduleResumeEvent();
+
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               /** 
+                * Schedule a task to run after some time which will
+                * notify platform that the context is running.
+                */
+               private void scheduleResumeEvent() {
+                       countOfScheduledNotifications++;
+
+                       final ExecutionDMC dmc = this;
+                       
+                       Runnable notifyPlatformTask = new Runnable() {
+                               public void run() {
+                                       /*
+                                        * Notify platform the context is running.
+                                        * 
+                                        * But don't do that if another such task is scheduled
+                                        * (namely current stepping is done within the RESUME_NOTIFICATION_DELAY and
+                                        * another stepping/resume is underway).
+                                        */
+                                       countOfScheduledNotifications--;
+                                       if (countOfScheduledNotifications == 0 && !isSuspended())
+                                               getSession().dispatchEvent(dmc.createResumedEvent(), RunControl.this.getProperties());
+                               }};
+                       
+                       getExecutor().schedule(notifyPlatformTask, RESUME_NOTIFICATION_DELAY, TimeUnit.MILLISECONDS);
+               }
+
+               /**
+                * Execute a single instruction. Note the "rm" is marked done() only
+                * when we get the suspend event, not when we successfully send the
+                * command to TCF agent.
+                * 
+                * @param rm
+                */
+               protected void singleStep(final boolean stepInto, final RequestMonitor rm) {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this.getName())); }
+
+                       setStepping(true);
+
+                       flushCache(this);
+
+                       if (hasTCFContext())
+                       {
+                               Protocol.invokeLater(new Runnable() {
+                                       public void run() {
+                                               int mode = stepInto ? org.eclipse.tm.tcf.services.IRunControl.RM_STEP_INTO
+                                                               : org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OVER;
+                                               getTCFContext().resume(mode, 1, new DoneCommand() {
+                                                       public void doneCommand(IToken token, final Exception error) {
+                                                               // do this in DSF executor thread.
+                                                               getExecutor().execute(new Runnable() {
+                                                                       public void run() {
+                                                                               handleTCFResumeDoneForStepping("SingleStep", error, rm);
+                                                                       }
+                                                               });
+                                                       }
+                                               });
+                                       }
+                               });
+                       }
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               /**
+                * Step out of the current function. Note the "rm" is marked done() only
+                * when we get the suspend event, not when we successfully send the
+                * command to TCF agent.
+                * 
+                * @param rm
+                */
+               protected void stepOut(final RequestMonitor rm) {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this.getName())); }
+
+                       setStepping(true);
+
+                       flushCache(this);
+
+                       if (hasTCFContext()) {
+                               Protocol.invokeLater(new Runnable() {
+                                       public void run() {
+                                               getTCFContext()
+                                                               .resume(org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OUT,
+                                                                               0, new DoneCommand() {
+
+                                                                                       public void doneCommand(
+                                                                                                       IToken token,
+                                                                                                       final Exception error) {
+                                                                                               // do this in DSF executor thread.
+                                                                                               getExecutor().execute(
+                                                                                                               new Runnable() {
+                                                                                                                       public void run() {
+                                                                                                                               handleTCFResumeDoneForStepping(
+                                                                                                                                               "StepOut",
+                                                                                                                                               error,
+                                                                                                                                               rm);
+                                                                                                                       }
+                                                                                                               });
+                                                                                       }
+                                                                               });
+                                       }
+                               });
+                       }
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               protected void stepRange(final boolean stepInto, final IAddress rangeStart, final IAddress rangeEnd,
+                               final RequestMonitor rm) {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this.getName())); }
+
+                       setStepping(true);
+
+                       flushCache(this);
+
+                       if (hasTCFContext()) {
+                               Protocol.invokeLater(new Runnable() {
+                                       public void run() {
+                                               int mode = stepInto ? org.eclipse.tm.tcf.services.IRunControl.RM_STEP_INTO_RANGE
+                                                               : org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OVER_RANGE;
+                                               Map<String, Object> params = new HashMap<String, Object>();
+                                               params.put("RANGE_START", rangeStart.getValue());
+                                               params.put("RANGE_END", rangeEnd.getValue());
+
+                                               getTCFContext().resume(mode, 0, params, new DoneCommand() {
+
+                                                       public void doneCommand(IToken token,
+                                                                       final Exception error) {
+                                                               // do this in DSF executor thread.
+                                                               getExecutor().execute(new Runnable() {
+                                                                       public void run() {
+                                                                               handleTCFResumeDoneForStepping(
+                                                                                               "StepRange", error, rm);
+                                                                       }
+                                                               });
+                                                       }
+                                               });
+                                       }
+                               });
+                       }
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+               }
+
+               /**
+                * set whether debugger is stepping in the context.
+                * 
+                * @param isStepping
+                */
+               public void setStepping(boolean isStepping) {
+                       this.isStepping = isStepping;
+               }
+
+               /**
+                * @return whether debugger is stepping the context.
+                */
+               public boolean isStepping() {
+                       return isStepping;
+               }
+
+               public void addDisabledRange(IAddress lowAddress, IAddress highAddress) {
+                       disabledRanges.add(new EDCAddressRange(lowAddress, highAddress));
+               }
+
+               public EDCAddressRange getDisabledRange(IAddress address) {
+                       for (EDCAddressRange dRange : disabledRanges) {
+                               if (dRange.contains(address))
+                                       return dRange;
+                       }
+                       return null;
+               }
+
+               protected DMCSuspendedEvent createSuspendedEvent(StateChangeReason reason, Map<String, Object> properties) {
+                       return new SuspendedEvent(this, reason, properties);
+               }
+
+               protected DMCResumedEvent createResumedEvent() {
+                       return new ResumedEvent(this);
+               }
+
+               public RunControlContext getTCFContext() {
+                       return tcfContext;
+               }
+
+               public boolean hasTCFContext() {
+                       return tcfContext != null;
+               }
+
+       }
+
+       public class ProcessExecutionDMC extends ExecutionDMC implements IContainerDMContext, IProcessDMContext,
+                       ISymbolDMContext, IBreakpointsTargetDMContext, IDisassemblyDMContext {
+
+               public ProcessExecutionDMC(ExecutionDMC parent, Map<String, Object> properties, RunControlContext tcfContext) {
+                       super(parent, properties, tcfContext);
+               }
+
+               @Override
+               public ExecutionDMC contextAdded(Map<String, Object> properties, RunControlContext tcfContext) {
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(properties)); }
+                       ThreadExecutionDMC newDMC = new ThreadExecutionDMC(this, properties, tcfContext);
+                       getSession().dispatchEvent(new StartedEvent(newDMC), RunControl.this.getProperties());
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(newDMC)); }
+                       return newDMC;
+               }
+
+               public ISymbolDMContext getSymbolDMContext() {
+                       return this;
+               }
+
+               @Override
+               public void loadSnapshot(Element element) throws Exception {
+                       // load modules first, since this loads a stack which must consult modules and symbolics
+                       Modules modulesService = getService(Modules.class);
+                       modulesService.loadModulesForContext(this, element);
+                       super.loadSnapshot(element);
+               }
+
+               @Override
+               public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor)throws Exception {
+                       SubMonitor progress = SubMonitor.convert(monitor, 1000);
+                       progress.subTask(getName());
+                       Element contextElement = super.takeSnapshot(album, document, progress.newChild(500));
+                       Element modulesElement = document.createElement(EXECUTION_CONTEXT_MODULES);
+                       Modules modulesService = getService(Modules.class);
+
+                       IModuleDMContext[] modules = modulesService.getModulesForContext(this.getID());
+                       SubMonitor modulesMonitor = progress.newChild(500);
+                       modulesMonitor.setWorkRemaining(modules.length * 1000);
+                       modulesMonitor.subTask("Modules");
+                       for (IModuleDMContext moduleContext : modules) {
+                               ModuleDMC moduleDMC = (ModuleDMC) moduleContext;
+                               modulesElement.appendChild(moduleDMC.takeSnapshot(album, document, modulesMonitor.newChild(1000)));
+                       }
+                       
+                       contextElement.appendChild(modulesElement);
+                       return contextElement;
+               }
+
+               @Override
+               public boolean canDetach() {
+                       // Can detach from a process unless we're part of a snapshot.
+                       return hasTCFContext();
+               }
+
+               @Override
+               public boolean canStep() {
+                       // can't step a process.
+                       return false;
+               }
+       }
+
+       public class ThreadExecutionDMC extends ExecutionDMC implements IThreadDMContext, IDisassemblyDMContext {
+
+               public ThreadExecutionDMC(ExecutionDMC parent, Map<String, Object> properties, RunControlContext tcfContext) {
+                       super(parent, properties, tcfContext);
+                       if (EDCTrace.RUN_CONTROL_TRACE_ON) { 
+                               EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { parent, properties })); 
+                               EDCTrace.getTrace().traceExit(null);
+                       }
+               }
+
+               public ISymbolDMContext getSymbolDMContext() {
+                       return DMContexts.getAncestorOfType(this, ISymbolDMContext.class);
+               }
+
+               @Override
+               public void loadSnapshot(Element element) throws Exception {
+                       super.loadSnapshot(element);
+                       Registers regService = getService(Registers.class);
+                       regService.loadGroupsForContext(this, element);
+
+                       Stack stackService = getService(Stack.class);
+                       NodeList frameElements = element.getElementsByTagName(EXECUTION_CONTEXT_FRAMES);
+                       for (int i = 0; i < frameElements.getLength(); i++) {
+                               Element frameElement = (Element) frameElements.item(i);
+                               stackService.loadFramesForContext(this, frameElement);
+                       }
+
+                       getSession().dispatchEvent(
+                                       createSuspendedEvent(StateChangeReason.EXCEPTION, new HashMap<String, Object>()),
+                                       RunControl.this.getProperties());
+               }
+
+               @Override
+               public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor)throws Exception {
+                       SubMonitor progress = SubMonitor.convert(monitor, 1000);
+                       progress.subTask(getName());
+                       Element contextElement = super.takeSnapshot(album, document, progress.newChild(100));
+                       Element registersElement = document.createElement(EXECUTION_CONTEXT_REGISTERS);
+                       Registers regService = getService(Registers.class);
+                       
+                       IRegisterGroupDMContext[] regGroups = regService.getGroupsForContext(this);
+                       SubMonitor registerMonitor = progress.newChild(300);
+                       registerMonitor.setWorkRemaining(regGroups.length * 1000);
+                       registerMonitor.subTask("Registers");
+                       for (IRegisterGroupDMContext registerGroupDMContext : regGroups) {
+                               RegisterGroupDMC regDMC = (RegisterGroupDMC) registerGroupDMContext;
+                               registersElement.appendChild(regDMC.takeSnapshot(album, document, registerMonitor.newChild(1000)));
+                       }
+                       
+                       contextElement.appendChild(registersElement);
+
+                       Element framesElement = document.createElement(EXECUTION_CONTEXT_FRAMES);
+                       Stack stackService = getService(Stack.class);
+                       Expressions expressionsService = getService(Expressions.class);
+
+                       IFrameDMContext[] frames = stackService.getFramesForDMC(this, 0, IStack.ALL_FRAMES);
+                       SubMonitor framesMonitor = progress.newChild(600);
+                       framesMonitor.setWorkRemaining(frames.length * 2000);
+                       framesMonitor.subTask("Stack Frames");
+                       for (IFrameDMContext frameDMContext : frames) {
+                               StackFrameDMC frameDMC = (StackFrameDMC) frameDMContext;
+                               
+                               // Get the local variables for each frame
+                               IVariableDMContext[] variables = frameDMC.getLocals();
+                               SubMonitor variablesMonitor = framesMonitor.newChild(1000);
+                               variablesMonitor.setWorkRemaining(variables.length * 10);
+                               variablesMonitor.subTask("Variables");
+                               for (IVariableDMContext iVariableDMContext : variables) {
+                                       VariableDMC varDMC = (VariableDMC) iVariableDMContext;
+                                       IExpressionDMContext expression = expressionsService.createExpression(frameDMContext, varDMC.getName());
+                                       boolean wasEnabled = FormatExtensionManager.instance().isEnabled();
+                                       FormatExtensionManager.instance().setEnabled(true);
+                                       expressionsService.loadExpressionValues(expression, Album.getVariableCaptureDepth());
+                                       FormatExtensionManager.instance().setEnabled(wasEnabled);
+                                       variablesMonitor.worked(10);
+                                       variablesMonitor.subTask("Variables - " + varDMC.getName());
+                               }
+                               
+                               framesElement.appendChild(frameDMC.takeSnapshot(album, document, framesMonitor.newChild(1000)));
+                       }
+                       contextElement.appendChild(framesElement);
+
+                       return contextElement;
+               }
+
+               @Override
+               public ExecutionDMC contextAdded(Map<String, Object> properties, RunControlContext tcfContext) {
+                       assert (false);
+                       return null;
+               }
+
+               @Override
+               public boolean canDetach() {
+                       // Cannot detach from a thread.
+                       return false;
+               }
+
+               @Override
+               public boolean canStep() {
+                       if (isSuspended()) {
+                               synchronized (properties) {
+                                       return !RunControl.getProperty(properties, PROP_DISABLE_STEPPING, false);
+                               }
+                       }
+                       
+                       return false;
+               }
+       }
+
+       /**
+        * Context representing a program running on a bare device without OS, which
+        * can also be the boot-up "process" of an OS.
+        * <p>
+        * It's like a thread context as it has its registers and stack frames, but
+        * also like a process as it has modules associated with it. Currently we
+        * set it as an IProcessDMContext so that it appears as a ContainerVMNode in
+        * debug view. See LaunchVMProvider for more. Also it's treated like a
+        * process in
+        * {@link Processes#getProcessesBeingDebugged(IDMContext, DataRequestMonitor)}
+        */
+       public class BareDeviceExecutionDMC extends ThreadExecutionDMC 
+                               implements IProcessDMContext, ISymbolDMContext, IBreakpointsTargetDMContext {
+
+               public BareDeviceExecutionDMC(ExecutionDMC parent,
+                               Map<String, Object> properties, RunControlContext tcfContext) {
+                       super(parent, properties, tcfContext);
+                       assert !RunControl.getProperty(properties, PROP_IS_CONTAINER, true);
+               }
+
+               @Override
+               protected DMCSuspendedEvent createSuspendedEvent(StateChangeReason reason, Map<String, Object> properties) {
+                       return new ContainerSuspendedEvent(this, reason, properties);
+               }
+
+               @Override
+               protected DMCResumedEvent createResumedEvent() {
+                       return new ContainerResumedEvent(this);
+               }
+
+               @Override
+               public boolean canDetach() {
+                       return true;
+               }
+               
+       }
+       
+       public class RootExecutionDMC extends ExecutionDMC implements ISourceLookupDMContext {
+
+               public RootExecutionDMC(Map<String, Object> props) {
+                       super(null, props, null);
+               }
+
+               @Override
+               public ExecutionDMC contextAdded(Map<String, Object> properties, RunControlContext tcfContext) {
+                       ExecutionDMC newDMC;
+                       // If the new context being added under root is a container context,
+                       // we treat it as a Process, otherwise a bare device program context.
+                       //
+                       if (RunControl.getProperty(properties, PROP_IS_CONTAINER, true))
+                               newDMC = new ProcessExecutionDMC(this, properties, tcfContext);
+                       else
+                               newDMC = new BareDeviceExecutionDMC(this, properties, tcfContext);
+                       
+                       getSession().dispatchEvent(new StartedEvent(newDMC), RunControl.this.getProperties());
+                       return newDMC;
+               }
+
+               public ISymbolDMContext getSymbolDMContext() {
+                       return null;
+               }
+
+               @Override
+               public boolean canDetach() {
+                       return false;
+               }
+
+               @Override
+               public boolean canStep() {
+                       return false;
+               }
+       }
+
+       private static final String EXECUTION_CONTEXTS = "execution_contexts";
+
+       private org.eclipse.tm.tcf.services.IRunControl tcfRunService;
+       private RootExecutionDMC rootExecutionDMC;
+       private final Map<String, ExecutionDMC> dmcsByID = new HashMap<String, ExecutionDMC>();
+       
+       public RunControl(DsfSession session) {
+               super(session, new String[] { 
+                               IRunControl.class.getName(), 
+                               IRunControl2.class.getName(), 
+                               RunControl.class.getName(),
+                               ISnapshotContributor.class.getName() });
+               initializeRootExecutionDMC();
+       }
+
+       private void initializeRootExecutionDMC() {
+               HashMap<String, Object> props = new HashMap<String, Object>();
+               props.put(IEDCDMContext.PROP_ID, "root");
+               rootExecutionDMC = new RootExecutionDMC(props);
+       }
+
+       public void canResume(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
+               rm.setData(((ExecutionDMC) context).isSuspended() ? Boolean.TRUE : Boolean.FALSE);
+               rm.done();
+       }
+
+       public void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor<Boolean> rm) {
+               rm.setData(((ExecutionDMC) context).canStep() ? Boolean.TRUE : Boolean.FALSE);
+               rm.done();
+       }
+
+       public void canSuspend(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
+               if (isSnapshot())
+                       rm.setData(Album.getAlbumBySession(getSession().getId()).isPlayingSnapshots());
+               else
+                       rm.setData(((ExecutionDMC) context).isSuspended() ? Boolean.FALSE : Boolean.TRUE);
+               rm.done();
+       }
+
+       public void getExecutionContexts(IContainerDMContext c, DataRequestMonitor<IExecutionDMContext[]> rm) {
+               if (c instanceof ProcessExecutionDMC) {
+                       ProcessExecutionDMC edmc = (ProcessExecutionDMC) c;
+                       IEDCExecutionDMC[] threads = edmc.getChildren();
+                       IExecutionDMContext[] threadArray = new IExecutionDMContext[threads.length];
+                       System.arraycopy(threads, 0, threadArray, 0, threads.length);
+                       rm.setData(threadArray);
+               }
+               rm.done();
+       }
+
+       public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor<IExecutionDMData> rm) {
+               if (dmc instanceof ExecutionDMC) {
+                       ExecutionDMC exedmc = (ExecutionDMC) dmc;
+                       if (exedmc.isSuspended()) {
+                               rm.setData(new ExecutionData(exedmc.getStateChangeReason(), exedmc.getStateChangeDetails()));
+                       } else {
+                               rm.setData(new ExecutionData(StateChangeReason.UNKNOWN, null));
+                       }
+               } else
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_HANDLE,
+                                       "Given context: " + dmc + " is not a recognized execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
+               rm.done();
+       }
+
+       public boolean isStepping(IExecutionDMContext context) {
+               if (context instanceof ExecutionDMC) {
+                       ExecutionDMC exedmc = (ExecutionDMC) context;
+                       return exedmc.isStepping();
+               }
+               return false;
+       }
+
+       public boolean isSuspended(IExecutionDMContext context) {
+               if (context instanceof ExecutionDMC) {
+                       ExecutionDMC exedmc = (ExecutionDMC) context;
+                       return exedmc.isSuspended();
+               }
+               return false;
+       }
+
+       /**
+        * Preprocessing for suspend event. This is done before we broadcast the
+        * suspend event across the debugger. Here's what's done in the
+        * preprocessing by default: <br>
+        * 1. Adjust PC after control hits a software breakpoint where the PC
+        * points at the byte right after the breakpoint instruction. This is to
+        * move PC back to the address of the breakpoint instruction.<br>
+        * 2. If we stops at a breakpoint, evaluate condition of the breakpoint
+        * and determine if we should ignore the suspend event and resume or
+        * should honor the suspend event and sent it up the ladder.
+        * <p>
+        * Subclass can override this method to add their own special preprocessing,
+        * while calling super implementation to carry out the default common.
+        * <p>
+        * This must be called in DSF executor thread.
+        * 
+        * @param pc
+        *            program pointer value from the event, in the format of
+        *            big-endian hex string. Can be null.
+        * @param drm
+        *            DataRequestMonitor whose result indicates whether to honor
+        *            the suspend.
+        */
+       protected void preprocessOnSuspend(final ExecutionDMC dmc, final String pc,
+                       final DataRequestMonitor<Boolean> drm) {
+               
+               assert getExecutor().isInExecutorThread();
+
+               asyncExec(new Runnable() {
+                       
+                       public void run() {
+                               try {
+                                       Breakpoints bpService = getService(Breakpoints.class);
+                                       Registers regService = getService(Registers.class);
+                                       String pcString = pc;
+
+                                       if (pc == null) {
+                                               // read PC register
+                                               pcString = regService.getRegisterValue(dmc, getTargetEnvironmentService().getPCRegisterID());
+                                       }
+
+                                       dmc.setPC(pcString);
+
+                                       // This check is to speed up handling of suspend due to
+                                       // other reasons such as "step".
+                                       // The TCF agents should always report the
+                                       // "stateChangeReason" as BREAKPOINT when a breakpoint
+                                       // is hit.
+
+                                       if (dmc.getStateChangeReason() != StateChangeReason.BREAKPOINT) {
+                                               drm.setData(true);
+                                               drm.done();
+                                               return;
+                                       }
+
+                                       if (!bpService.usesTCFBreakpointService()) {
+                                               // generic software breakpoint is used.
+                                               // We need to move PC back to the breakpoint
+                                               // instruction.
+                                               long pcValue;
+
+                                               pcValue = Long.valueOf(pcString, 16);
+                                               pcValue -= getTargetEnvironmentService()
+                                                               .getBreakpointInstruction(dmc, new Addr64(pcString, 16)).length;
+                                               pcString = Long.toHexString(pcValue);
+
+                                               // Stopped but not due to breakpoint set by debugger.
+                                               // For instance, some Windows DLL has "int 3"
+                                               // instructions in it.
+                                               // 
+                                               if (bpService.findBreakpoint(new Addr64(pcString, 16)) != null) {
+                                                       // Now adjust PC register.
+                                                       regService.writeRegister(dmc, getTargetEnvironmentService().getPCRegisterID(), pcString);
+                                                       dmc.setPC(pcString);
+                                               }
+                                       }
+
+                                       // check if a conditional breakpoint (must be a user bp) is hit
+                                       //
+                                       BreakpointDMData bp = bpService.findUserBreakpoint(new Addr64(pcString, 16));
+                                       if (bp != null) {
+                                               // evaluate the condition
+                                               bpService.evaluateBreakpointCondition(dmc, bp, drm);
+                                       } else {
+                                               drm.setData(true);
+                                               drm.done();
+                                       }
+                               } catch (CoreException e) {
+                                       Status s = new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), null, e);
+                                       EDCDebugger.getMessageLogger().log(s);
+                                       drm.setStatus(s);
+                                       drm.done();
+                               }
+                               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(drm.getData())); }
+                       }
+                       
+               }, drm);
+       }
+
+       public void resume(IExecutionDMContext context, final RequestMonitor rm) {
+               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(MessageFormat.format("resume context {0}", context))); }
+
+               if (!(context instanceof ExecutionDMC)) {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_HANDLE, MessageFormat.format(
+                                       "The context [{0}] is not a recognized execution context.", context), null));
+                       rm.done();
+               }
+
+               final ExecutionDMC dmc = (ExecutionDMC) context;
+
+               prepareToRun(dmc, new DataRequestMonitor<Boolean>(getExecutor(), rm) {
+
+                       @Override
+                       protected void handleSuccess() {
+                               dmc.resume(rm);
+                               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(MessageFormat.format("resume() done on context {0}", dmc))); }
+                       }
+               });
+       }
+
+       /**
+        * Prepare for resuming or stepping by <br>
+        * - executing current instruction if PC is at a breakpoint.
+        * 
+        * @param dmc
+        *            - the execution context, usually a thread.
+        * @param drm
+        *            - data request monitor which will contain boolean value on
+        *            done indicating whether an instruction is executed during the
+        *            preparation.
+        */
+       private void prepareToRun(final ExecutionDMC dmc, final DataRequestMonitor<Boolean> drm) {
+               // If there is breakpoint at current PC, remove it => Single step =>
+               // Restore it.
+
+               final Breakpoints bpService = getService(Breakpoints.class);
+               if (bpService.usesTCFBreakpointService()) {
+                       // no need to do anything since the breakpoints service is expected to handle
+                       // stepping past breakpoints since it's the one that sets them
+                       drm.setData(false);
+                       drm.done();
+                       return;
+               }
+
+               String latestPC = dmc.getPC();
+
+               if (latestPC != null) {
+                       final BreakpointDMData bp = bpService.findUserBreakpoint(new Addr64(latestPC, 16));
+                       if (bp != null) {
+                               bpService.disableBreakpoint(bp, new RequestMonitor(getExecutor(), drm) {
+
+                                       @Override
+                                       protected void handleSuccess() {
+                                               // Now step over the instruction
+                                               //
+                                               dmc.setSuspendEventsEnabled(false);
+                                               dmc.singleStep(true, new RequestMonitor(getExecutor(), drm) {
+                                                       @Override
+                                                       protected void handleCompleted() {
+                                                               dmc.setSuspendEventsEnabled(true);
+                                                               super.handleCompleted();
+                                                       }
+
+                                                       @Override
+                                                       protected void handleSuccess() {
+                                                               // At this point the single instruction
+                                                               // execution should be done
+                                                               // and the context being suspended.
+                                                               //
+                                                               drm.setData(true); // indicates an instruction
+                                                               // is executed
+
+                                                               // Now restore the breakpoint.
+                                                               bpService.enableBreakpoint(bp, drm);
+                                                       }
+                                               });
+                                       }
+                               });
+                       } else { // no breakpoint at PC
+                               drm.setData(false);
+                               drm.done();
+                       }
+               } else {
+                       drm.setData(false);
+                       drm.done();
+               }
+       }
+
+       // This is a coarse timer on stepping for internal use.
+       // When needed, turn it on and watch output in console.
+       //
+       private static long steppingStartTime = 0;
+       public static boolean timeStepping() {
+               return false;
+       }
+       
+       public static long getSteppingStartTime() {
+               return steppingStartTime;
+       }
+       
+       public void step(final IExecutionDMContext context, final StepType outerStepType, final RequestMonitor rm) {
+               
+               asyncExec(new Runnable() {
+                       
+                       public void run() {
+                               StepType stepType = outerStepType;
+                               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(MessageFormat.format("{0} context {1}", stepType, context))); }
+
+                               if (!(context instanceof ExecutionDMC)) {
+                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_HANDLE, MessageFormat.format(
+                                                       "The context [{0}] is not a recognized execution context.", context), null));
+                                       rm.done();
+                               }
+
+                               if (timeStepping())
+                                       steppingStartTime = System.currentTimeMillis();
+                               
+                               final ExecutionDMC dmc = (ExecutionDMC) context;
+
+                               dmc.setStepping(true);
+
+                               IAddress pcAddress = null;
+
+                               if (dmc.getPC() == null) { // PC is even unknown, can only do
+                                       // one-instruction step.
+                                       stepType = StepType.INSTRUCTION_STEP_INTO;
+                               } else
+                                       pcAddress = new Addr64(dmc.getPC(), 16);
+
+                               // For step-out (step-return), no difference between source level or
+                               // instruction level.
+                               //
+                               if (stepType == StepType.STEP_RETURN)
+                                       stepType = StepType.INSTRUCTION_STEP_RETURN;
+
+                               // Source level stepping request.
+                               // 
+                               if (stepType == StepType.STEP_OVER || stepType == StepType.STEP_INTO) {
+                                       IEDCModules moduleService = getService(Modules.class);
+
+                                       ISymbolDMContext symCtx = DMContexts.getAncestorOfType(context, ISymbolDMContext.class);
+
+                                       IEDCModuleDMContext module = moduleService.getModuleByAddress(symCtx, pcAddress);
+
+                                       // Check if there is source info for PC address.
+                                       //
+                                       if (module != null) {
+                                               IEDCSymbolReader reader = module.getSymbolReader();
+                                               assert pcAddress != null;
+                                               if (reader != null) {
+                                                       IAddress linkAddress = module.toLinkAddress(pcAddress);
+                                                       IModuleLineEntryProvider lineEntryProvider
+                                                         = reader.getModuleScope().getModuleLineEntryProvider();
+                                                       ILineEntry line = lineEntryProvider.getLineEntryAtAddress(linkAddress);
+                                                       if (line != null) {
+                                                               // get runtime addresses of the line boundaries.
+                                                               IAddress endAddr = module.toRuntimeAddress(line.getHighAddress());
+
+                                                               // get the next source line entry that has a line #
+                                                               // greater than the current line # (and in the same file),
+                                                               // but is not outside of the function address range
+                                                               // if found, the start addr of that entry is our end
+                                                               // address, otherwise use the existing end address
+                                                               ILineEntry nextLine
+                                                                 = lineEntryProvider.getNextLineEntry(
+                                                                               lineEntryProvider.getLineEntryAtAddress(linkAddress),
+                                                                               stepType == StepType.STEP_OVER);
+                                                               if (nextLine != null) {
+                                                                       endAddr = module.toRuntimeAddress(nextLine.getLowAddress());
+                                                               } else {        // nextLine == null probably means last line
+                                                                       IEDCSymbols symbolsService = getService(Symbols.class);
+                                                                       IFunctionScope functionScope
+                                                                         = symbolsService.getFunctionAtAddress(dmc.getSymbolDMContext(), pcAddress);
+                                                                       if (stepType == StepType.STEP_OVER) {
+                                                                               while (functionScope != null
+                                                                                               && functionScope.getParent() instanceof IFunctionScope) {
+                                                                                       functionScope = (IFunctionScope)functionScope.getParent();
+                                                                               }
+                                                                       }
+                                                                       if (functionScope != null)
+                                                                               endAddr = module.toRuntimeAddress(functionScope.getHighAddress());
+                                                               }
+                                                               if (stepType == StepType.STEP_OVER) {
+                                                                       // Create a disabled range
+                                                                       Collection<ILineEntry> ranges
+                                                                         = lineEntryProvider.getLineEntriesForLines(line.getFilePath(),
+                                                                                                                                                                line.getLineNumber(),
+                                                                                                                                                                line.getLineNumber());
+                                                                       if (ranges.size() > 1)
+                                                                       {
+                                                                               for (ILineEntry iLineEntry : ranges) {
+                                                                                       dmc.addDisabledRange(module.toRuntimeAddress(iLineEntry.getLowAddress()),
+                                                                                                                                module.toRuntimeAddress(iLineEntry.getHighAddress()));
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               /*
+                                                                * It's possible that PC is larger than startAddr
+                                                                * (e.g. user does a few instruction level stepping
+                                                                * then switch to source level stepping; or when we
+                                                                * just step out a function). We just parse and
+                                                                * stepping instructions within [pcAddr, endAddr)
+                                                                * instead of all those within [startAddr, endAddr).
+                                                                * One possible problem with the solution is when
+                                                                * control jumps from within [pcAddress, endAddr) to
+                                                                * somewhere within [startAddr, pcAddress), the
+                                                                * stepping would stop at somewhere within
+                                                                * [startAddr, pcAddress) instead of outside of the
+                                                                * [startAddr, endAddr). But that case is rare (e.g.
+                                                                * a source line contains a bunch of statements) and
+                                                                * that "problem" is not unacceptable as user could
+                                                                * just keep stepping or set a breakpoint and run.
+                                                                * 
+                                                                * We can overcome the problem but that would incur
+                                                                * much more complexity in the stepping code and
+                                                                * brings down the stepping speed.
+                                                                * ........................ 08/30/2009
+                                                                */
+
+                                                               stepAddressRange(dmc, stepType == StepType.STEP_INTO, pcAddress, endAddr, rm);
+
+                                                               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null, "source level stepping."); }
+                                                               return;
+                                                       }
+                                               }
+                                       }
+
+                                       // No source found, fall back to instruction level step.
+                                       if (stepType == StepType.STEP_INTO)
+                                               stepType = StepType.INSTRUCTION_STEP_INTO;
+                                       else
+                                               stepType = StepType.INSTRUCTION_STEP_OVER;
+                               }
+
+                               // instruction level step
+                               // 
+                               if (stepType == StepType.INSTRUCTION_STEP_OVER)
+                                       stepOverOneInstruction(dmc, pcAddress, rm);
+                               else if (stepType == StepType.INSTRUCTION_STEP_INTO)
+                                       stepIntoOneInstruction(dmc, rm);
+                               else if (stepType == StepType.INSTRUCTION_STEP_RETURN)
+                                       stepOut(dmc, pcAddress, rm);
+
+                               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+                       }
+               }, rm);
+       }
+
+       private void stepOut(final ExecutionDMC dmc, IAddress pcAddress, final RequestMonitor rm) {
+
+               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "Step out from address " + pcAddress.toHexAddressString()); }
+
+               if (dmc.supportsStepMode(StepType.STEP_RETURN)) {
+                       dmc.stepOut(rm);
+                       return;
+               }
+
+               Stack stackService = getService(Stack.class);
+               IFrameDMContext[] frames;
+               try {
+                       frames = stackService.getFramesForDMC(dmc, 0, 1);
+               } catch (CoreException e) {
+                       Status s = new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), null, e);
+                       EDCDebugger.getMessageLogger().log(s);
+                       rm.setStatus(s);
+                       rm.done();
+                       return;
+               }
+               if (frames.length <= 1) {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
+                                       "Cannot step out as no caller frame is available.", null));
+                       rm.done();
+                       return;
+               }
+
+               if (handleSteppingOutOfInLineFunctions(dmc, frames, rm))
+                       return;
+
+               final IAddress stepToAddress = ((StackFrameDMC) frames[1]).getInstructionPtrAddress();
+               
+               final Breakpoints bpService = getService(Breakpoints.class);
+
+               prepareToRun(dmc, new DataRequestMonitor<Boolean>(getExecutor(), rm) {
+                       @Override
+                       protected void handleSuccess() {
+
+                               boolean goon = true;
+
+                               if (getData() == true) {
+                                       // one instruction has been executed
+                                       IAddress newPC = new Addr64(dmc.getPC(), 16);
+
+                                       // And we already stepped out (that instruction is return
+                                       // instruction).
+                                       //
+                                       if (newPC.equals(stepToAddress)) {
+                                               goon = false;
+                                       }
+                               }
+
+                               if (goon) {
+                                       bpService.setTempBreakpoint(dmc, stepToAddress, new RequestMonitor(getExecutor(), rm) {
+                                               @Override
+                                               protected void handleSuccess() {
+                                                       dmc.resumeForStepping(rm);
+                                               }
+                                       });
+                               } else
+                                       rm.done();
+                       }
+               });
+       }
+
+       /**
+        * handle module load event. A module is an executable file
+        * or a library (e.g. DLL or shared lib).
+        * Allow subclass to override for special handling if needed.
+        * This must be called in DSF dispatch thread.
+        * 
+        * @param dmc
+        * @param moduleProperties
+        */
+       protected void handleModuleLoadedEvent(IEDCExecutionDMC dmc, Map<String, Object> moduleProperties) {
+               ISymbolDMContext symbolContext = dmc.getSymbolDMContext();
+
+               if (symbolContext != null) {
+                       Modules modulesService = getService(Modules.class);
+                       modulesService.moduleLoaded(symbolContext, dmc, moduleProperties);
+               }
+       }
+               
+       /**
+        * handle module unload event. A module is an executable file
+        * or a library (e.g. DLL or shared lib).
+        * Allow subclass to override for special handling if needed.
+        * This must be called in DSF dispatch thread.
+        * 
+        * @param dmc
+        * @param moduleProperties
+        */
+       protected void handleModuleUnloadedEvent(IEDCExecutionDMC dmc, Map<String, Object> moduleProperties) {
+               ISymbolDMContext symbolContext = dmc.getSymbolDMContext();
+
+               if (symbolContext != null) {
+                       Modules modulesService = getService(Modules.class);
+                       modulesService.moduleUnloaded(symbolContext, dmc, moduleProperties);
+               }
+       }
+
+       private boolean handleSteppingOutOfInLineFunctions(final ExecutionDMC dmc,
+                       IFrameDMContext[] frames, final RequestMonitor rm) {
+
+               assert frames.length > 1 && frames[0] instanceof StackFrameDMC;
+
+               StackFrameDMC currentFrame = ((StackFrameDMC) frames[0]);
+
+               IEDCModuleDMContext module = currentFrame.getModule();
+               if (module != null) {
+                       IFunctionScope func = currentFrame.getFunctionScope();
+                       // if inline ...
+                       if (func != null && (func.getParent() instanceof IFunctionScope)) {
+
+                               // ... but if PC is at beginning of function, then act like not in inline
+                               // (i.e. step-out as though standing at call to any non-inline function)
+                               if (currentFrame.isInlineShouldBeHidden(null))
+                                       return false;
+
+                               // ... or if PC at at high-address, that means we're actually done with it
+                               IAddress functRuntimeHighAddr = module.toRuntimeAddress(func.getHighAddress());
+                               IAddress frameInstrPtr = currentFrame.getInstructionPtrAddress();
+                               if (functRuntimeHighAddr.equals(frameInstrPtr))
+                                       return false;
+               
+                               // getting here means treat the line as a regular line to step over
+                               stepAddressRange(dmc, false, frameInstrPtr, functRuntimeHighAddr,
+                                                                new RequestMonitor(getExecutor(), rm) {
+                                       @Override
+                                       protected void handleSuccess() {
+                                               rm.done();
+                                       }});
+               
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * check if the instruction at PC is a subroutine call. If yes, set a
+        * breakpoint after it and resume; otherwise just execute one instruction.
+        * 
+        * @param dmc
+        * @param pcAddress
+        * @param rm
+        */
+       private void stepOverOneInstruction(final ExecutionDMC dmc, final IAddress pcAddress, final RequestMonitor rm) {
+
+               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "address " + pcAddress.toHexAddressString()); }
+
+               if (dmc.supportsStepMode(StepType.INSTRUCTION_STEP_OVER)) {
+                       dmc.singleStep(false, rm);
+                       return;
+               }
+
+               ITargetEnvironment env = getTargetEnvironmentService();
+               final IDisassembler disassembler = (env != null) ? env.getDisassembler() : null;
+               if (disassembler == null) {
+                       rm.setStatus(Disassembly.statusNoDisassembler());
+                       rm.done();
+                       return;
+               }
+
+               Memory memoryService = getService(Memory.class);
+               IMemoryDMContext mem_dmc = DMContexts.getAncestorOfType(dmc, IMemoryDMContext.class);
+
+               // We need to get the instruction at the PC. We have to
+               // retrieve memory bytes for longest instruction.
+               @SuppressWarnings("null") // (env == null) -> (disassembler == null) -> return above
+               int maxInstLength = env.getLongestInstructionLength();
+
+               // Note this memory read will give us memory bytes with
+               // debugger breakpoints removed, which is just what we want.
+               memoryService.getMemory(mem_dmc, pcAddress, 0, 1, maxInstLength,
+                                                               new DataRequestMonitor<MemoryByte[]>(getExecutor(), rm) {
+                       @Override
+                       protected void handleSuccess() {
+                               ByteBuffer codeBuf = Disassembly.translateMemoryBytes(getData(), pcAddress, rm);
+                               if (codeBuf == null) {
+                                       return; // rm status set in checkMemoryBytes()
+                               }
+
+                               IDisassemblyDMContext dis_dmc
+                                 = DMContexts.getAncestorOfType(dmc, IDisassemblyDMContext.class);
+                               Map<String, Object> options = new HashMap<String, Object>();
+                               options.put(IDisassemblerOptions.ADDRESS_IS_PC, 1);
+                               IDisassembledInstruction inst;
+                               try {
+                                       inst = disassembler.disassembleOneInstruction(pcAddress, codeBuf, options, dis_dmc);
+                               } catch (CoreException e) {
+                                       rm.setStatus(e.getStatus());
+                                       rm.done();
+                                       return;
+                               }
+
+                               final boolean isSubroutineCall = inst.getJumpToAddress() != null
+                                               && inst.getJumpToAddress().isSubroutineAddress();
+                               final IAddress nextInstructionAddress = pcAddress.add(inst.getSize());
+
+                               stepIntoOneInstruction(dmc, new RequestMonitor(getExecutor(), rm) {
+                                       @Override
+                                       protected void handleSuccess() {
+                                               if (!isSubroutineCall)
+                                                       rm.done();
+                                               else {
+                                                       // If current instruction is subroutine call, set a
+                                                       // temp
+                                                       // breakpoint at next instruction and resume ...
+                                                       //
+                                                       Breakpoints bpService = getService(Breakpoints.class);
+                                                       bpService.setTempBreakpoint(dmc, nextInstructionAddress,
+                                                                                                               new RequestMonitor(getExecutor(), rm) {
+                                                               @Override
+                                                               protected void handleSuccess() {
+                                                                       dmc.resumeForStepping(rm);
+                                                               }
+                                                       });
+                                               }
+                                       }
+                               });
+                       }
+               });
+       }
+
+       /**
+        * Step into or over an address range. Note the startAddr is also the PC
+        * value.
+        * 
+        * @param dmc
+        * @param stepIn
+        *            - whether to step-in.
+        * @param startAddr
+        *            - also the PC register value.
+        * @param endAddr
+        * @param rm
+        *            - marked done after the stepping is over and context is
+        *            suspended again.
+        */
+       private void stepAddressRange(final ExecutionDMC dmc, final boolean stepIn, final IAddress startAddr,
+                       final IAddress endAddr, final RequestMonitor rm) {
+               if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, MessageFormat.format("address range [{0},{1})", startAddr.toHexAddressString(), endAddr.toHexAddressString())); }
+
+               if (dmc.supportsStepMode(stepIn ? StepType.STEP_INTO : StepType.STEP_OVER)) {
+                       dmc.stepRange(stepIn, startAddr, endAddr, rm);
+                       return;
+               }
+
+               ITargetEnvironment env = getTargetEnvironmentService();
+               final IDisassembler disassembler = (env != null) ? env.getDisassembler() : null;
+               if (disassembler == null) {
+                       rm.setStatus(Disassembly.statusNoDisassembler());
+                       rm.done();
+                       return;
+               }
+
+               final Memory memoryService = getService(Memory.class);
+               IMemoryDMContext mem_dmc = DMContexts.getAncestorOfType(dmc, IMemoryDMContext.class);
+
+               int memSize = startAddr.distanceTo(endAddr).intValue();
+
+               final IAddress pcAddress = startAddr;
+
+               // Note this memory read will give us memory bytes with
+               // debugger breakpoints removed, which is just what we want.
+               memoryService.getMemory(mem_dmc, startAddr, 0, 1, memSize,
+                                                               new DataRequestMonitor<MemoryByte[]>(getExecutor(), rm) {
+                       @Override
+                       protected void handleSuccess() {
+                               ByteBuffer codeBuf = Disassembly.translateMemoryBytes(getData(), startAddr, rm);
+                               if (codeBuf == null) {
+                                       return; // rm status set in checkMemoryBytes()
+                               }
+
+                               IDisassemblyDMContext dis_dmc
+                                 = DMContexts.getAncestorOfType(dmc, IDisassemblyDMContext.class);
+
+                               Map<String, Object> options = new HashMap<String, Object>();
+
+                               List<IDisassembledInstruction> instList;
+                               try {
+                                       instList
+                                         = disassembler.disassembleInstructions(startAddr, endAddr, codeBuf,
+                                                                                                                        options, dis_dmc);
+                               } catch (CoreException e) {
+                                       rm.setStatus(e.getStatus());
+                                       rm.done();
+                                       return;
+                               }
+
+                               // Now collect all possible stop points
+                               //
+                               final List<IAddress> stopPoints = new ArrayList<IAddress>();
+                               final List<IAddress> runToAndCheckPoints = new ArrayList<IAddress>();
+                               boolean insertBPatRangeEnd = true;
+
+                               for (IDisassembledInstruction inst : instList) {
+                                       final IAddress instAddr = inst.getAddress();
+                                       if (insertBPatRangeEnd == false)
+                                               insertBPatRangeEnd = true;
+                                       IJumpToAddress jta = inst.getJumpToAddress();
+                                       if (jta == null)
+                                               continue;
+                                       
+                                       // the instruction is a control-change instruction
+                                       //
+                                       if (!jta.isImmediate()) {
+
+                                               if (inst.getAddress().equals(pcAddress)) {
+                                                       // Control is already at the instruction, evaluate
+                                                       // it.
+                                                       //
+                                                       String expr = (String) jta.getValue();
+                                                       if (expr.equals(JumpToAddress.EXPRESSION_RETURN_FAR)
+                                                                       || expr.equals(JumpToAddress.EXPRESSION_RETURN_NEAR)
+                                                                       || expr.equals(JumpToAddress.EXPRESSION_LR)) {
+                                                               // The current instruction is return instruction. Just execute it
+                                                               // to step-out and we are done with the stepping. This way we avoid
+                                                               // looking for return address from caller stack frame which may not
+                                                               // even available.
+                                                               // Is it possible that the destination address of the step-out
+                                                               // is still within the [startAddr, endAddr)range ? In theory
+                                                               // yes, but in practice it means one source line has several
+                                                               // function bodies in it, who would do that?
+                                                               //
+                                                               stepIntoOneInstruction(dmc, rm);
+                                                               return;
+                                                       }
+                                                       // evaluate the address expression
+
+                                                       if (!jta.isSubroutineAddress() || stepIn)
+                                                       {
+                                                               IAddressExpressionEvaluator evaluator = getTargetEnvironmentService()
+                                                               .getAddressExpressionEvaluator();
+                                                               if (evaluator == null) {
+                                                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
+                                                                                       "No evaluator for address expression yet.", null));
+                                                                       rm.done();
+                                                                       return;
+                                                               }
+
+                                                               Registers regService = getService(Registers.class);
+
+                                                               IAddress addr;
+                                                               try {
+                                                                       addr = evaluator.evaluate(dmc, expr, regService, memoryService);
+                                                               } catch (CoreException e) {
+                                                                       rm.setStatus(e.getStatus());
+                                                                       rm.done();
+                                                                       return;
+                                                               }
+                                                               // don't add an address if we already have it
+                                                               if (!stopPoints.contains(addr))
+                                                                       stopPoints.add(addr);
+                                                       }
+                                               } else {
+                                                       // we must run to this instruction first
+                                                       //
+                                                       /*
+                                                        * What if control would skip (jump-over) this
+                                                        * instruction within the [startAddr, endAddr) range
+                                                        * ? So we should go on collecting stop points from
+                                                        * the remaining instructions in the range and then
+                                                        * do our two-phase stepping (see below)
+                                                        */
+                                                       if (!runToAndCheckPoints.contains(instAddr))
+                                                               runToAndCheckPoints.add(instAddr);
+                                               }
+                                       } else { // "jta" is immediate address.
+
+                                               IAddress jumpAddress = (IAddress) jta.getValue();
+
+                                               if (jta.isSoleDestination()) {
+                                                       if (jta.isSubroutineAddress()) {
+                                                               // is subroutine call
+                                                               if (stepIn && !stopPoints.contains(jumpAddress)) {
+                                                                       stopPoints.add(jumpAddress);
+                                                                       // no need to check remaining instructions
+                                                                       // !! Wrong. Control may jump over (skip)this instruction
+                                                                       // within the [startAddr, endAddr) range, so we still need
+                                                                       // to parse instructions after this instruction.
+                                                                       // break;
+                                                               } else {
+                                                                       // step over the call instruction. Just stop
+                                                                       // at next instruction.
+                                                                       // nothing to do.
+                                                               }
+                                                       } else {
+                                                               // Unconditional jump instruction
+                                                               // ignore jump within the address range
+                                                               if (!(startAddr.compareTo(jumpAddress) <= 0 && jumpAddress.compareTo(endAddr) < 0)) {
+                                                                       insertBPatRangeEnd = false;
+                                                                       if (!stopPoints.contains(jumpAddress))
+                                                                               stopPoints.add(jumpAddress);
+                                                               }
+                                                       }
+                                               } else {
+                                                       // conditional jump
+                                                       // ignore jump within the address range
+                                                       if (!(startAddr.compareTo(jumpAddress) <= 0 && jumpAddress.compareTo(endAddr) < 0) 
+                                                                                                               && !stopPoints.contains(jumpAddress))
+                                                       {
+                                                               stopPoints.add(jumpAddress);
+                                                       }
+                                               }
+                                       }
+                               } // end of parsing instructions
+
+                               // need a temp breakpoint at the "endAddr".
+                               if (insertBPatRangeEnd && !stopPoints.contains(endAddr))
+                                       stopPoints.add(endAddr);
+
+                               if (runToAndCheckPoints.size() > 0) {
+                                       // Now do our two-phase stepping.
+                                       //
+
+                                       if (runToAndCheckPoints.size() > 1) {
+                                               /*
+                                                * Wow, there are two control-change instructions in the
+                                                * range that requires run-to-check (let's call them RTC
+                                                * point). In theory the stepping might fail (not stop
+                                                * as desired) in such case: When we try to run to the
+                                                * first RTC, the control may skip the first RTC and run
+                                                * to second RTC (note we don't know the stop points of
+                                                * the second RTC yet) and run out of the range and be
+                                                * gone with the wind...
+                                                * 
+                                                * There is no way we can solve the problem. Good thing
+                                                * is, in practice is the case even possible ?
+                                                */
+                                               // Log (and show it, get rid of the "show" part after
+                                               // tons of test) warning here.
+                                               EDCDebugger.getMessageLogger().log(
+                                                               new Status(IStatus.WARNING, EDCDebugger.PLUGIN_ID,
+                                                                               MessageFormat.format(
+                                                                                               "More than one run-to-check points in the address range [{0},{1}). Stepping might fail.",
+                                                                                               startAddr.toHexAddressString(), endAddr.toHexAddressString())));
+                                       }
+
+                                       // ------------ Phase 1: run to the first RTC.
+                                       //
+                                       // recursive call
+                                       stepAddressRange(dmc, stepIn, startAddr, runToAndCheckPoints.get(0), new RequestMonitor(
+                                                       getExecutor(), rm) {
+                                               @Override
+                                               protected void handleSuccess() {
+                                                       IAddress newPC = new Addr64(dmc.getPC(), 16);
+
+                                                       boolean doneWithStepping = false;
+                                                       for (IAddress addr : stopPoints)
+                                                               if (newPC.equals(addr)) {
+                                                                       doneWithStepping = true; // done with the
+                                                                       // stepping
+                                                                       break;
+                                                               }
+
+                                                       Breakpoints bpService = getService(Breakpoints.class);
+                                                       if (bpService.findUserBreakpoint(newPC) != null) { // hit
+                                                               // a
+                                                               // user
+                                                               // breakpoint
+                                                               doneWithStepping = true;
+                                                       }
+
+                                                       if (!doneWithStepping)
+                                                               // -------- Phase 2: run to the "endAddr".
+                                                               //
+                                                               stepAddressRange(dmc, stepIn, newPC, endAddr, rm); // Recursive
+                                                       // call
+                                                       else
+                                                               rm.done();
+                                               }
+                                       });
+                               } else { // no RTC points, set temp breakpoints at stopPoints
+                                       // and run...
+
+                                       // Make sure we step over breakpoint at PC (if any)
+                                       //
+                                       prepareToRun(dmc, new DataRequestMonitor<Boolean>(getExecutor(), rm) {
+                                               @Override
+                                               protected void handleSuccess() {
+
+                                                       boolean goon = true;
+
+                                                       Breakpoints bpService = getService(Breakpoints.class);
+
+                                                       if (getData() == true) {
+                                                               // one instruction has been executed
+                                                               IAddress newPC = new Addr64(dmc.getPC(), 16);
+
+                                                               if (bpService.findUserBreakpoint(newPC) != null) {
+                                                                       // hit a user breakpoint. Stepping finishes.
+                                                                       goon = false;
+                                                               } else {
+                                                                       // Check if we finish the stepping by
+                                                                       // checking the newPC against
+                                                                       // our stopPoints instead of checking if
+                                                                       // newPC is outside of [startAddr, endAddr)
+                                                                       // so that such case would not fail: step
+                                                                       // over this address range:
+                                                                       //
+                                                                       // 0x10000 call ... // a user breakpoint is
+                                                                       // set here
+                                                                       // 0x10004 ...
+                                                                       // 0x1000c ...
+                                                                       // 
+                                                                       //
+                                                                       for (IAddress addr : stopPoints)
+                                                                               if (newPC.equals(addr)) {
+                                                                                       goon = false;
+                                                                                       break;
+                                                                               }
+                                                               }
+                                                       }
+
+                                                       if (goon) {
+                                                               // Now set temp breakpoints at our stop points.
+                                                               //
+                                                               CountingRequestMonitor setTempBpRM = new CountingRequestMonitor(getExecutor(), rm) {
+                                                                       @Override
+                                                                       protected void handleSuccess() {
+                                                                               // we are done setting all temporary
+                                                                               // breakpoints
+                                                                               dmc.resumeForStepping(rm);
+                                                                       }
+                                                               };
+
+                                                               setTempBpRM.setDoneCount(stopPoints.size());
+
+                                                               for (IAddress addr : stopPoints) {
+                                                                       bpService.setTempBreakpoint(dmc, addr, setTempBpRM);
+                                                               }
+                                                       } else
+                                                               rm.done();
+                                               }
+                                       });
+                               }
+
+                       }
+               });
+       }
+
+       /**
+        * step-into one instruction at current PC, namely execute only one
+        * instruction.
+        * 
+        * @param dmc
+        * @param rm
+        *            - this RequestMonitor is marked done when the execution
+        *            finishes and target suspends again.
+        */
+       private void stepIntoOneInstruction(final ExecutionDMC dmc, final RequestMonitor rm) {
+
+               prepareToRun(dmc, new DataRequestMonitor<Boolean>(getExecutor(), rm) {
+                       @Override
+                       protected void handleSuccess() {
+                               if (getData() == true /* already executed one instruction */)
+                                       // The "step" is over
+                                       rm.done();
+                               else {
+                                       dmc.singleStep(true, rm);
+                               }
+                       }
+               });
+       }
+
+       public void suspend(IExecutionDMContext context, RequestMonitor requestMonitor) {
+               if (context instanceof ExecutionDMC) {
+                       ((ExecutionDMC) context).suspend(requestMonitor);
+               } else {
+                       requestMonitor.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_HANDLE, MessageFormat
+                                       .format("The context [{0}] is not a recognized execution context.", context), null));
+                       requestMonitor.done();
+               }
+       }
+
+       public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
+               rm.done();
+       }
+
+       public void flushCache(IDMContext context) {
+               if (isSnapshot())
+                       return;
+               // Flush the Registers cache immediately
+               // For instance the readPCRegister() may get wrong PC value when an
+               // asynchronous suspend event comes too quick after resume.
+               Registers regService = getService(Registers.class);
+               regService.flushCache(context);
+       }
+
+       @Override
+       public void shutdown(RequestMonitor monitor) {
+               if (tcfRunService != null) {
+                       Protocol.invokeLater(new Runnable() {
+                               public void run() {
+                                       tcfRunService.removeListener(runListener);
+                               }
+                       });
+               }
+               unregister();
+               super.shutdown(monitor);
+       }
+
+       public RootExecutionDMC getRootDMC() {
+               return rootExecutionDMC;
+       }
+
+       public static class StartedEvent extends AbstractDMEvent<IExecutionDMContext> implements IStartedDMEvent {
+
+               public StartedEvent(IExecutionDMContext context) {
+                       super(context);
+               }
+       }
+
+       public static class ExitedEvent extends AbstractDMEvent<IExecutionDMContext> implements IExitedDMEvent {
+               private boolean isTerminatedThanDisconnected;
+               
+               public ExitedEvent(IExecutionDMContext context, boolean isTerminatedThanDisconnected) {
+                       super(context);
+                       this.isTerminatedThanDisconnected = isTerminatedThanDisconnected;
+               }
+
+               public boolean isTerminatedThanDisconnected() {
+                       return isTerminatedThanDisconnected;
+               }
+       }
+
+       /*
+        * NOTE: 
+        * Methods in this listener are invoked in TCF dispatch thread.
+        * When they call into DSF services/objects, make sure it's done in 
+        * DSF executor thread so as to avoid possible racing condition.
+        */
+       private final org.eclipse.tm.tcf.services.IRunControl.RunControlListener runListener = new org.eclipse.tm.tcf.services.IRunControl.RunControlListener() {
+
+               public void containerResumed(String[] context_ids) {
+               }
+
+               public void containerSuspended(String context, String pc, String reason, Map<String, Object> params,
+                               String[] suspended_ids) {
+               }
+
+               public void contextAdded(final RunControlContext[] contexts) {
+                       getExecutor().execute(new Runnable() {
+                               public void run() {
+                                       for (RunControlContext ctx : contexts) {
+                                               ExecutionDMC dmc = rootExecutionDMC;
+                                               String parentID = ctx.getParentID();
+                                               if (parentID != null)
+                                                       dmc = dmcsByID.get(parentID);
+                                               if (dmc != null) {
+                                                       dmc.contextAdded(ctx.getProperties(), ctx);
+                                               }
+                                       }
+                               }
+                       });
+               }
+
+               public void contextChanged(RunControlContext[] contexts) {
+               }
+
+               public void contextException(final String context, final String msg) {
+                       getExecutor().execute(new Runnable() {
+                               public void run() {
+                                       ExecutionDMC dmc = getContext(context);
+                                       if (dmc != null)
+                                               dmc.contextException(msg);
+                               }
+                       });
+               }
+
+               public void contextRemoved(final String[] context_ids) {
+                       getExecutor().execute(new Runnable() {
+                               public void run() {
+                                       for (String contextID : context_ids) {
+                                               ExecutionDMC dmc = getContext(contextID);
+                                               assert dmc != null;
+                                               if (dmc != null)
+                                                       dmc.purgeFromDebugger();
+                                       }
+                               }
+                       });
+               }
+
+               public void contextResumed(final String context) {
+                       getExecutor().execute(new Runnable() {
+                               public void run() {
+                                       ExecutionDMC dmc = getContext(context);
+                                       if (dmc != null)
+                                               dmc.contextResumed(false);
+                               }
+                       });
+               }
+
+               public void contextSuspended(final String context, final String pc, final String reason,
+                               final Map<String, Object> params) {
+                       getExecutor().execute(new Runnable() {
+                               public void run() {
+                                       ExecutionDMC dmc = getContext(context);
+                                       if (dmc != null)
+                                               dmc.contextSuspended(pc, reason, params);
+                                       else {
+                                               EDCDebugger.getMessageLogger().logError(
+                                                       MessageFormat.format("Unkown context [{0}] is reported in suspended event. Make sure TCF agent has reported contextAdded event first.", context), 
+                                                       null);
+                                       }
+                               }
+                       });
+               }
+       };
+
+       public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor)throws Exception {
+               Element contextsElement = document.createElement(EXECUTION_CONTEXTS);
+               ExecutionDMC[] dmcs = rootExecutionDMC.getChildren();
+               SubMonitor progress = SubMonitor.convert(monitor, dmcs.length * 1000);
+
+               for (ExecutionDMC executionDMC : dmcs) {
+                       Element dmcElement = executionDMC.takeSnapshot(album, document, progress.newChild(1000));
+                       contextsElement.appendChild(dmcElement);
+               }
+               return contextsElement;
+       }
+
+       public ExecutionDMC getContext(String contextID) {
+               return dmcsByID.get(contextID);
+       }
+
+       public void loadSnapshot(Element snapshotRoot) throws Exception {
+               NodeList ecElements = snapshotRoot.getElementsByTagName(EXECUTION_CONTEXTS);
+               rootExecutionDMC.resumeAll();
+               initializeRootExecutionDMC();
+               rootExecutionDMC.loadSnapshot((Element) ecElements.item(0));
+       }
+
+       public void tcfServiceReady(IService service) {
+               if (service instanceof org.eclipse.tm.tcf.services.IRunControl) {
+                       tcfRunService = (org.eclipse.tm.tcf.services.IRunControl) service;
+                       Protocol.invokeLater(new Runnable() {
+                               public void run() {
+                                       tcfRunService.addListener(runListener);
+                               }
+                       });
+               } else
+                       assert false;
+       }
+
+       /**
+        * Stop debugging all execution contexts. This does not kill/terminate
+        * the actual process or thread.
+        * See: {@link #terminateAllContexts(RequestMonitor)}
+        */
+       private void detachAllContexts(){
+               getRootDMC().detach();
+       }
+
+       /**
+        * Terminate all contexts so as to terminate the debug session.
+        * 
+        * @param rm can be null.
+        */
+       public void terminateAllContexts(final RequestMonitor rm){
+
+               CountingRequestMonitor crm = new CountingRequestMonitor(getExecutor(), rm) {
+                       @Override
+                       protected void handleError() {
+                               // failed to terminate at least one process, usually
+                               // because connection to target is lost, or some processes
+                               // cannot be killed (e.g. OS does not permit that).
+                               // Just untarget the contexts.
+                               detachAllContexts();
+               
+                               if (rm != null)
+                                       rm.done();
+                       }
+                       
+               };
+               
+               // It's assumed 
+               // 1. First level of children under rootDMC are processes.
+               // 2. Killing them would kill all contexts (processes and threads) being debugged.
+               //
+               ExecutionDMC[] processes = getRootDMC().getChildren();
+               crm.setDoneCount(processes.length);
+               
+               for (ExecutionDMC e : processes) {
+                       e.terminate(crm);
+               }
+       }
+
+       public void canRunToLine(IExecutionDMContext context, String sourceFile,
+                       int lineNumber, final DataRequestMonitor<Boolean> rm) {
+               // I tried to have better filtering as shown in commented code. But that 
+               // just made the command fail to be enabled as desired. Not sure about the 
+               // exact cause yet, but one problem (from the upper framework) I've seen is 
+               // this API is not called whenever user selects a line in source editor (or
+               // disassembly view) and bring up context menu.
+               // Hence we blindly answer yes. The behavior is on par with DSF-GDB.
+               // ................. 03/11/10  
+               rm.setData(true);
+               rm.done();
+               
+//             // Return true if we can find address(es) for the line in the context.
+//             //
+//             getLineAddress(context, sourceFile, lineNumber, new DataRequestMonitor<List<IAddress>>(getExecutor(), rm){
+//                     @Override
+//                     protected void handleCompleted() {
+//                             if (! isSuccess())
+//                                     rm.setData(false);
+//                             else {
+//                                     rm.setData(getData().size() > 0);
+//                             }
+//                             rm.done();
+//                     }});
+       }
+
+       public void runToLine(final IExecutionDMContext context, String sourceFile,
+                       int lineNumber, boolean skipBreakpoints, final RequestMonitor rm) {
+               
+               getLineAddress(context, sourceFile, lineNumber, new DataRequestMonitor<List<IAddress>>(getExecutor(), rm){
+                       @Override
+                       protected void handleCompleted() {
+                               if (! isSuccess()) {
+                                       rm.setStatus(getStatus());
+                                       rm.done();
+                               }
+                               else {
+                                       runToAddresses(context, getData(), rm);
+                               }
+                       }});
+       }
+
+       private void runToAddresses(IExecutionDMContext context,
+                       final List<IAddress> addrs, final RequestMonitor rm) {
+               // 1. Single step over breakpoint, if PC is at a breakpoint.
+               // 2. Set temp breakpoint at the addresses.
+               // 3. Resume the context.
+               //
+               final ExecutionDMC dmc = (ExecutionDMC)context;
+               assert dmc != null;
+               
+               prepareToRun(dmc, new DataRequestMonitor<Boolean>(getExecutor(), rm){
+
+                       @Override
+                       protected void handleCompleted() {
+                               if (! isSuccess()) {
+                                       rm.setStatus(getStatus());
+                                       rm.done();
+                                       return;
+                               }
+                               
+                               CountingRequestMonitor settingBP_crm = new CountingRequestMonitor(getExecutor(), rm) {
+                                       @Override
+                                       protected void handleCompleted() {
+                                               if (! isSuccess()) {
+                                                       // as long as we fail to set on temp breakpoint, we bail out.
+                                                       rm.setStatus(getStatus());
+                                                       rm.done();
+                                               }
+                                               else {
+                                                       // all temp breakpoints are successfully set.
+                                                       // Now resume the context.
+                                                       dmc.resume(rm);
+                                               }
+                                       }};
+                               
+                               settingBP_crm.setDoneCount(addrs.size());
+                               
+                               Breakpoints bpService = getService(Breakpoints.class);
+                               
+                               for (IAddress a : addrs)
+                                       bpService.setTempBreakpoint(dmc, a, settingBP_crm);
+                       }}
+               );
+       }
+
+       public void canRunToAddress(IExecutionDMContext context, IAddress address,
+                       DataRequestMonitor<Boolean> rm) {
+               // See comment in canRunToLine() for more.
+               rm.setData(true);
+               rm.done();
+
+//             // If the address is not in any module of the run context, return false. 
+//             Modules moduleService = getService(Modules.class);
+//
+//             ISymbolDMContext symCtx = DMContexts.getAncestorOfType(context, ISymbolDMContext.class);
+//
+//             ModuleDMC m = moduleService.getModuleByAddress(symCtx, address);
+//             rm.setData(m == null);
+//             rm.done();
+       }
+
+       public void runToAddress(IExecutionDMContext context, IAddress address,
+                       boolean skipBreakpoints, RequestMonitor rm) {
+               List<IAddress> addrs = new ArrayList<IAddress>(1);
+               addrs.add(address);
+               runToAddresses(context, addrs, rm);
+       }
+
+       public void canMoveToLine(IExecutionDMContext context, String sourceFile,
+                       int lineNumber, boolean resume, final DataRequestMonitor<Boolean> rm) {
+               // See comment in canRunToLine() for more.
+               rm.setData(true);
+               rm.done();
+               
+               // Return true if we can find one and only one address for the line in the context.
+               //
+//             getLineAddress(context, sourceFile, lineNumber, new DataRequestMonitor<List<IAddress>>(getExecutor(), rm){
+//                     @Override
+//                     protected void handleCompleted() {
+//                             if (! isSuccess())
+//                                     rm.setData(false);
+//                             else {
+//                                     rm.setData(getData().size() == 1);
+//                             }
+//                             rm.done();
+//                     }});
+       }
+
+       public void moveToLine(final IExecutionDMContext context, String sourceFile,
+                       int lineNumber, final boolean resume, final RequestMonitor rm) {
+               getLineAddress(context, sourceFile, lineNumber, new DataRequestMonitor<List<IAddress>>(getExecutor(), rm){
+                       @Override
+                       protected void handleCompleted() {
+                               if (! isSuccess()) {
+                                       rm.setStatus(getStatus());
+                                       rm.done();
+                               }
+                               else {
+                                       List<IAddress> addrs = getData();
+                                       // No, canMoveToLine() does not do sanity check now.
+                                       // We just move to the first address we found, which may or
+                                       // may not be the address user wants. Is it better we return
+                                       // error if "addrs.size() > 1" ? .......03/28/10
+                                       // assert addrs.size() == 1;    // ensured by canMoveToLine().
+                                       moveToAddress(context, addrs.get(0), resume, rm);
+                               }
+                       }});
+       }
+
+       public void canMoveToAddress(IExecutionDMContext context, IAddress address,
+                       boolean resume, DataRequestMonitor<Boolean> rm) {
+               // Allow moving to any address.
+               rm.setData(true);
+               rm.done();
+       }
+
+       public void moveToAddress(IExecutionDMContext context, IAddress address,
+                       boolean resume, RequestMonitor rm) {
+
+               Registers regService = getService(Registers.class);
+               
+               assert(context instanceof ExecutionDMC);
+               ExecutionDMC dmc = (ExecutionDMC)context;
+               
+               String newPC = address.toString(16);
+               
+               if (! newPC.equals(dmc.getPC())) {
+                       try {
+                               // synchronously change PC, so that change occurs before any resume
+                               String regID = getTargetEnvironmentService().getPCRegisterID();
+                               RegisterDMC regDMC = regService.findRegisterDMCByName(dmc, regID);
+                               assert regDMC != null;
+                               
+                               regService.writeRegister(regDMC, newPC, IFormattedValues.HEX_FORMAT);
+                       } catch (CoreException e) {
+                               Status s = new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "Error adjusting the PC register", e);
+                               EDCDebugger.getMessageLogger().log(s);
+                               rm.setStatus(s);
+                               rm.done();
+                               return;
+                       }
+
+                       // update cached PC.
+                       dmc.setPC(newPC);
+               }
+               
+               if (resume)
+                       resume(context, rm);
+               else
+                       rm.done();
+       }
+
+       /**
+        * Get runtime addresses mapped to given source line in given run context.
+        *  
+        * @param context
+        * @param sourceFile
+        * @param lineNumber
+        * @param drm holds an empty list if no address found, or the run context is not suspended.
+        */
+       private void getLineAddress(IExecutionDMContext context,
+                       String sourceFile, int lineNumber, DataRequestMonitor<List<IAddress>> drm) {
+               List<IAddress> addrs = new ArrayList<IAddress>(1);
+               
+               ExecutionDMC dmc = (ExecutionDMC) context;
+               if (dmc == null || ! dmc.isSuspended()) {
+                       drm.setData(addrs);
+                       drm.done();
+                       return;
+               }
+               
+               Modules moduleService = getService(Modules.class);
+
+               moduleService.getLineAddress(dmc, sourceFile, lineNumber, drm);
+       }
+
+       /**
+        * Check if this context is non-container. Only non-container context
+        * (thread and bare device context) can have register, stack frames, etc.
+        * 
+        * @param dmc
+        * @return
+        */
+       static public boolean isNonContainer(IDMContext dmc) {
+               return ! (dmc instanceof IContainerDMContext);
+       }
+       
+       public ThreadExecutionDMC[] getSuspendedThreads()
+       {
+               ExecutionDMC[] dmcs = null;
+               List<ThreadExecutionDMC> result = new ArrayList<ThreadExecutionDMC>();
+               synchronized (dmcsByID)
+               {
+                       Collection<ExecutionDMC> allDMCs = dmcsByID.values();
+                       dmcs = allDMCs.toArray(new ExecutionDMC[allDMCs.size()]);
+               }
+               for (ExecutionDMC executionDMC : dmcs) {
+                       if (executionDMC instanceof ThreadExecutionDMC && executionDMC.isSuspended())
+                               result.add((ThreadExecutionDMC) executionDMC);
+               }
+               return result.toArray(new ThreadExecutionDMC[result.size()]);
+       }
+
+       /**
+        * Utility method for getting a context property using a default value
+        * if missing
+        */
+       private static boolean getProperty(Map<String, Object> properties, String name, boolean defaultValue) {
+               Boolean b = (Boolean)properties.get(name);
+               return (b == null ? defaultValue : b);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Signals.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Signals.java
new file mode 100644 (file)
index 0000000..4c16ce3
--- /dev/null
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+import org.eclipse.cdt.dsf.debug.service.ISignals;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+public class Signals extends AbstractEDCService implements ISignals {
+
+       public Signals(DsfSession session) {
+               super(session, new String[] { ISignals.class.getName(), Signals.class.getName() });
+               // TODO Auto-generated constructor stub
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Snapshots.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Snapshots.java
new file mode 100644 (file)
index 0000000..f1f73a7
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import org.eclipse.cdt.debug.edc.internal.snapshot.Album;
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+import org.eclipse.cdt.debug.edc.services.ISnapshots;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+public class Snapshots extends AbstractEDCService implements ISnapshots {
+
+       public Snapshots(DsfSession session) {
+               super(session, new String[] { Snapshots.class.getName() });
+               session.addServiceEventListener(this, null);
+       }
+
+       @Override
+       public void shutdown(RequestMonitor rm) {
+               getSession().removeServiceEventListener(this);
+               super.shutdown(rm);
+       }
+       
+       @DsfServiceEventHandler
+       public void eventDispatched(final ISuspendedDMEvent e) {
+               if (!this.isSnapshot()) {
+                       final String controlSetting = Album.getSnapshotCreationControl();
+                       if (!controlSetting.equals(Album.CREATE_MANUAL)){
+                               if (e.getReason() != StateChangeReason.SHAREDLIB
+                                               && (controlSetting.equals(Album.CREATE_WHEN_STOPPED) || controlSetting.equals(Album.CREATE_AT_BEAKPOINTS))) {
+                                       if (controlSetting.equals(Album.CREATE_WHEN_STOPPED) || 
+                                                       e.getReason() == StateChangeReason.BREAKPOINT) {
+                                               Album.captureSnapshotForSession(getSession());
+                                       }
+                               }
+                       }
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Symbols.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Symbols.java
new file mode 100644 (file)
index 0000000..59d08dd
--- /dev/null
@@ -0,0 +1,307 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.services.dsf;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.EDCSymbolReader;
+import org.eclipse.cdt.debug.edc.internal.symbols.files.DebugInfoProviderFactory;
+import org.eclipse.cdt.debug.edc.internal.symbols.files.ExecutableSymbolicsReaderFactory;
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+import org.eclipse.cdt.debug.edc.services.IEDCModuleDMContext;
+import org.eclipse.cdt.debug.edc.services.IEDCModules;
+import org.eclipse.cdt.debug.edc.services.IEDCSymbols;
+import org.eclipse.cdt.debug.edc.services.IFrameRegisterProvider;
+import org.eclipse.cdt.debug.edc.services.IFrameRegisters;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.symbols.IDebugInfoProvider;
+import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.debug.edc.symbols.IModuleLineEntryProvider;
+import org.eclipse.cdt.debug.edc.symbols.IModuleScope;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.ISymbol;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+import org.eclipse.cdt.dsf.debug.service.ISymbols;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.debug.core.model.ISourceLocator;
+
+public class Symbols extends AbstractEDCService implements ISymbols, IEDCSymbols {
+       private static Map<IPath, WeakReference<IEDCSymbolReader>> readerCache = new HashMap<IPath, WeakReference<IEDCSymbolReader>>();
+       private ISourceLocator sourceLocator;
+       
+       public ISourceLocator getSourceLocator() {
+               return sourceLocator;
+       }
+
+       public void setSourceLocator(ISourceLocator sourceLocator) {
+               this.sourceLocator = sourceLocator;
+       }
+
+       public Symbols(DsfSession session) {
+               super(session, new String[] { IEDCSymbols.class.getName(), ISymbols.class.getName(), Symbols.class.getName() });
+       }
+
+       public void getSymbols(ISymbolDMContext symCtx, DataRequestMonitor<Iterable<ISymbolObjectDMContext>> rm) {
+               // TODO Auto-generated method stub
+
+       }
+
+       public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
+               // TODO Auto-generated method stub
+
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCSymbols#getFunctionAtAddress(org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext, org.eclipse.cdt.core.IAddress)
+        */
+       public IFunctionScope getFunctionAtAddress(ISymbolDMContext context, IAddress runtimeAddress) {
+               IEDCModules modulesService = getService(Modules.class);
+               IEDCModuleDMContext module = modulesService.getModuleByAddress(context, runtimeAddress);
+               if (module != null) {
+                       IEDCSymbolReader reader = module.getSymbolReader();
+                       if (reader != null) {
+                               IScope scope = reader.getModuleScope().getScopeAtAddress(module.toLinkAddress(runtimeAddress));
+                               while (scope != null && !(scope instanceof IFunctionScope)) {
+                                       scope = scope.getParent();
+                               }
+                               return (IFunctionScope) scope;
+                       }
+               }
+               return null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCSymbols#getFunctionAtAddress(org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext, org.eclipse.cdt.core.IAddress)
+        */
+       public String getSymbolNameAtAddress(ISymbolDMContext context, IAddress runtimeAddress) {
+               IEDCModules modulesService = getService(Modules.class);
+               IEDCModuleDMContext module = modulesService.getModuleByAddress(context, runtimeAddress);
+               if (module != null) {
+                       IEDCSymbolReader reader = module.getSymbolReader();
+                       if (reader != null) {
+                               ISymbol symbol = reader.getSymbolAtAddress(module.toLinkAddress(runtimeAddress));
+                               if (symbol != null)
+                                       return symbol.getName();
+                       }
+               }
+               return null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCSymbols#getLineEntryForAddress(org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext, org.eclipse.cdt.core.IAddress)
+        */
+       public ILineEntry getLineEntryForAddress(ISymbolDMContext context, IAddress runtimeAddress) {
+               IEDCModules modulesService = getService(Modules.class);
+               IEDCModuleDMContext module = modulesService.getModuleByAddress(context, runtimeAddress);
+               if (module != null) {
+                       IEDCSymbolReader reader = module.getSymbolReader();
+                       if (reader != null) {
+                               IAddress linkAddress = module.toLinkAddress(runtimeAddress);
+                               IModuleLineEntryProvider lineEntryProvider = reader.getModuleScope().getModuleLineEntryProvider();
+                               return lineEntryProvider.getLineEntryAtAddress(linkAddress);
+                       }
+               }
+               return null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCSymbols#getLineEntriesForAddressRange(org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext, org.eclipse.cdt.core.IAddress, org.eclipse.cdt.core.IAddress)
+        */
+       public List<ILineEntry> getLineEntriesForAddressRange(ISymbolDMContext context, IAddress start, IAddress end) {
+               List<ILineEntry> lineEntries = new ArrayList<ILineEntry>();
+
+               IEDCModules modulesService = getService(Modules.class);
+               IEDCModuleDMContext module = modulesService.getModuleByAddress(context, start);
+               if (module == null)
+                       return lineEntries;
+
+               IAddress linkStartAddress = module.toLinkAddress(start);
+               IAddress linkEndAddress = module.toLinkAddress(end);
+
+               IEDCSymbolReader reader = module.getSymbolReader();
+               if (reader != null) {
+                       if (linkStartAddress == null)
+                               linkStartAddress = module.getSymbolReader().getModuleScope().getLowAddress();
+                       if (linkEndAddress == null)
+                               linkEndAddress = module.getSymbolReader().getModuleScope().getHighAddress();
+
+                       IModuleScope moduleScope = reader.getModuleScope();
+                       
+                       if (linkEndAddress.compareTo(moduleScope.getHighAddress()) > 0) {
+                               // end address is out of the module sections.
+                               // we'll keep getting source lines until we reach an address
+                               // point where no source line is available.
+                               linkEndAddress = moduleScope.getHighAddress();
+                       }
+
+                       IModuleLineEntryProvider lineEntryProvider = moduleScope.getModuleLineEntryProvider();
+
+                       ILineEntry entry = lineEntryProvider.getLineEntryAtAddress(linkStartAddress);
+                       while (entry != null && entry.getLowAddress().compareTo(linkEndAddress) < 0) {
+                               lineEntries.add(entry);
+                               // FIXME: this shouldn't happen
+                               if (entry.getLowAddress().compareTo(entry.getHighAddress()) >= 0)
+                                       entry = lineEntryProvider.getLineEntryAtAddress(entry.getHighAddress().add(1));
+                               else
+                                       entry = lineEntryProvider.getLineEntryAtAddress(entry.getHighAddress());
+                       }
+               }
+
+               return lineEntries;
+       }
+       
+       /**
+        * Get an accessor for registers in stack frames other than the current one.
+        * <p>
+        * Note: this is not meaningful by itselfis typically used from {@link StackFrameDMC#getFrameRegisters()}.
+        * @param context
+        * @param runtimeAddress
+        * @return {@link IFrameRegisters} or <code>null</code>
+        */
+       public IFrameRegisterProvider getFrameRegisterProvider(ISymbolDMContext context, IAddress runtimeAddress) {
+               Modules modulesService = getService(Modules.class);
+               IEDCModuleDMContext module = modulesService.getModuleByAddress(context, runtimeAddress);
+               if (module != null) {
+                       IEDCSymbolReader reader = module.getSymbolReader();
+                       if (reader != null) {
+                               IFrameRegisterProvider frameRegisterProvider = reader.getModuleScope().getFrameRegisterProvider();
+                               return frameRegisterProvider;
+                       }
+               }
+               return null;
+       }
+
+       public static IEDCSymbolReader getSymbolReader(IPath modulePath) {
+
+               IEDCSymbolReader reader = null;
+               WeakReference<IEDCSymbolReader> cacheEntry = readerCache.get(modulePath);
+               
+               if (cacheEntry != null)
+                       reader = cacheEntry.get();
+
+               if (reader != null) {
+                       if (reader.getSymbolFile() != null
+                                       && reader.getSymbolFile().toFile().exists()
+                                       && reader.getSymbolFile().toFile().lastModified() == reader.getModificationDate()) {
+                               return reader;
+                       }
+
+                       // it's been deleted or modified. remove it from the cache
+                       readerCache.remove(modulePath);
+               }
+
+               IExecutableSymbolicsReader exeReader = ExecutableSymbolicsReaderFactory.createFor(modulePath);
+               if (exeReader != null) {
+                       IDebugInfoProvider debugProvider = DebugInfoProviderFactory.createFor(modulePath, exeReader); // may be null
+                       if (debugProvider != null) {
+                               // if debug info came from a different file, the "executable" may be that symbol file too 
+                               if (!exeReader.getSymbolFile().equals(debugProvider.getExecutableSymbolicsReader().getSymbolFile())) {
+                                       exeReader.dispose();
+                                       exeReader = debugProvider.getExecutableSymbolicsReader();
+                               }
+                       }
+                       reader = new EDCSymbolReader(exeReader, debugProvider);
+               }
+
+               if (reader != null) {
+                       readerCache.put(modulePath, new WeakReference<IEDCSymbolReader>(reader));
+               }
+               
+               return reader;
+       }
+
+       @Override
+       public void shutdown(RequestMonitor rm) {
+               super.shutdown(rm);
+       }
+
+       /**
+        * This is exposed only for testing.
+        */
+       public static void releaseReaderCache() {
+               Collection<WeakReference<IEDCSymbolReader>> readers = readerCache.values();
+               for (WeakReference<IEDCSymbolReader> readerRef : readers) {
+                       IEDCSymbolReader reader = readerRef.get();
+                       if (reader != null)
+                               reader.shutDown();
+               }
+               readerCache.clear();
+       }
+
+       /**
+        * A wrapper method that calls into symbol reader to get runtime address(es)
+        * for a given function name. 
+        * Currently this method use symbol table instead of debug info (e.g. dwarf2)
+        * to get function address. See reason in the implementation.
+        * 
+        * @param module where the runtime address is.
+        * @param functionName
+        * @return list of runtime addresses.
+        */
+       public List<IAddress> getFunctionAddress(IEDCModuleDMContext module, String functionName) {
+               
+               List<IAddress> ret = new ArrayList<IAddress>(2);
+               
+               IEDCSymbolReader symReader = module.getSymbolReader();
+               if (symReader == null)
+                       return ret;
+               
+               // Remove "()" if any
+               int parenIndex = functionName.indexOf('(');
+               if (parenIndex >= 0)
+                       functionName = functionName.substring(0, parenIndex);
+
+               // Supposedly we could call this to get what we need, but this may cause full parse of 
+               // debug info and lead to heap overflow for a large symbol file (over one giga bytes of 
+               // memory required in parsing a 180M symbol file) and chokes the debugger.
+               // So before a good solution is available, we resort to symbol table of the executable.
+               // ................04/02/10
+//                     Collection<IFunctionScope> functions = symReader.getModuleScope().getFunctionsByName(function);
+//                     for (IFunctionScope f : functions) {
+//                             IAddress breakAddr = f.getLowAddress();
+//                     ...
+
+               // assume it's the human-readable name first
+               Collection<ISymbol> symbols = symReader.findUnmangledSymbols(functionName);
+               if (symbols.isEmpty()) {
+                       // else look for a raw symbol
+                       symbols = symReader.findSymbols(functionName);
+               }
+               
+               for (ISymbol symbol : symbols) {
+                       // don't consider zero sized symbol.
+                       if (symbol.getSize() ==  0) 
+                               continue;
+
+                       IAddress addr = symbol.getAddress();
+                       // convert from link to runtime address
+                       addr = module.toRuntimeAddress(addr);
+                       
+                       ret.add(addr);
+               }
+
+               return ret;
+       }
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/Album.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/Album.java
new file mode 100644 (file)
index 0000000..3f8f3eb
--- /dev/null
@@ -0,0 +1,1325 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.snapshot;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.cdt.debug.core.sourcelookup.MappingSourceContainer;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.PathUtils;
+import org.eclipse.cdt.debug.edc.internal.ZipFileUtils;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.cdt.debug.edc.services.Stack;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.snapshot.IAlbum;
+import org.eclipse.cdt.debug.internal.core.sourcelookup.MapEntrySourceContainer;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.DsfSession.SessionEndedListener;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
+import org.eclipse.debug.core.sourcelookup.containers.DirectorySourceContainer;
+import org.eclipse.debug.internal.core.LaunchManager;
+import org.osgi.framework.Bundle;
+import org.osgi.service.prefs.BackingStoreException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * The Album class represents a series of snapshots that record moments in a
+ * debug session. An Album manages the collection of snapshots, common resources
+ * such as source files, persistence, and association with debug sessions.
+ * 
+ * An Album is usually created during a debug session, saved at the conclusion
+ * of the session, and reopened by a launch delegate for a new snapshot debug
+ * session.
+ * 
+ * When an Album is saved it's data and resources are archived in a snapshot
+ * file in a default location. When reopened the contents are expanded into a
+ * temporary directory and used to recreate the debug session.
+ */
+@SuppressWarnings("restriction")
+public class Album extends PlatformObject implements IAlbum {
+
+       // XML element names
+       public static final String SNAPSHOT = "snapshot";
+       private static final String ALBUM = "album";
+       private static final String LAUNCH = "launch";
+       private static final String RESOURCES = "resources";
+       private static final String FILE = "file";
+       private static final String INFO = "info";
+
+       public static final String METADATA = "snapshotMetaData";
+       public static final String SNAPSHOT_LIST = "snapshots";
+
+       private static final String ALBUM_DATA = "album.xml";
+       private static final String ALBUM_VERSION = "100";
+
+       private static String[] DSA_FILE_EXTENSIONS = new String[] {"dsa"};
+
+       // Preferences
+       public static final String PREF_CREATION_CONTROL = "creation_control";
+       public static final String CREATE_MANUAL = "manual";
+       public static final String CREATE_WHEN_STOPPED = "suspend";
+       public static final String CREATE_AT_BEAKPOINTS = "breakpoints";        
+       
+       public static final String PREF_VARIABLE_CAPTURE_DEPTH = "variable_capture_depth";
+       public static final String PLAY_SNAPSHOT_DELAY_TIME = "play_snapshot_delay_time";
+
+       private static final String CAMERA_CLICK_WAV = "/sounds/camera_click.wav";
+       
+       private Document document;
+       private Element albumRootElement;
+
+       private final List<Snapshot> snapshotList = new ArrayList<Snapshot>();
+       private String sessionID = "";
+       private String recordingSessionID = "";
+       private IPath albumRootDirectory;
+       private boolean launchConfigSaved;
+       private String launchType;
+       private HashMap<String, Object> launchProperties;
+       private String launchName = "";
+       private String name;
+       private boolean loaded;
+       private boolean metaDataLoaded;
+       private final Set<IPath> files = new HashSet<IPath>();
+
+       private int currentSnapshotIndex;
+       private IPath location;
+       private boolean resourceListSaved;
+       private boolean metadataSaved;
+       private boolean albumInfoSaved;
+       private String displayName;
+       private boolean playingSnapshots;
+
+       /**
+     * Listener for state changes on albums
+     */
+       protected static List<ISnapshotAlbumEventListener> listeners = Collections.synchronizedList(new ArrayList<ISnapshotAlbumEventListener>());
+
+       private static Map<String, Album> albumsBySessionID = Collections.synchronizedMap(new HashMap<String, Album>());
+       private static Map<String, Album> albumsRecordingBySessionID = Collections.synchronizedMap(new HashMap<String, Album>());       
+       private static Map<IPath, Album> albumsByLocation = Collections.synchronizedMap(new HashMap<IPath, Album>());
+       private static Map<String, Integer> launchNames = Collections.synchronizedMap(new HashMap<String, Integer>());
+
+       private static boolean sessionEndedListenerAdded;
+       private static SessionEndedListener sessionEndedListener = new SessionEndedListener() {
+
+               public void sessionEnded(DsfSession session) {
+                       Album album = albumsRecordingBySessionID.get(session.getId());
+                       if (album == null)
+                               album = albumsBySessionID.get(session.getId());
+                       if (album != null && session.getId().equals(album.getRecordingSessionID())) {
+                               album.saveResources(new NullProgressMonitor());
+                               album.setRecordingSessionID("");
+                       }
+                       synchronized (albumsRecordingBySessionID) {
+                       albumsRecordingBySessionID.remove(session.getId());
+                       }
+                       synchronized (albumsBySessionID) {
+                       albumsBySessionID.remove(session.getId());
+                       }
+
+                       if (album != null) {
+                               for (ISnapshotAlbumEventListener l : new ArrayList<ISnapshotAlbumEventListener>(listeners)) {
+                                       l.snapshotSessionEnded(album, session);
+                               }
+                       }
+               }
+       };
+
+       public interface IAlbumArchiveEntry {
+
+               public String createEntryName(File file);
+
+       }
+
+       public Album() {
+               super();
+               try {
+                       setDocument(DebugPlugin.newDocument());
+                       if (!sessionEndedListenerAdded)
+                               DsfSession.addSessionEndedListener(sessionEndedListener);
+                       sessionEndedListenerAdded = true;
+               } catch (CoreException e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getName()
+        */
+       public String getName() {
+               if (name == null) {
+                       name = getDefaultAlbumName();
+               }
+               return name;
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+
+       public void setDisplayName(String displayName) {
+               this.displayName = displayName;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getDisplayName()
+        */
+       public String getDisplayName() {
+               if (displayName == null || displayName.length() == 0) {
+                       displayName = getName();
+               }
+               return displayName;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getSessionID()
+        */
+       public String getSessionID() {
+               sessionID = "";
+               if (albumsBySessionID != null) {
+                       for (Map.Entry<String, Album> entry : albumsBySessionID.entrySet()){
+                               if (entry.getValue().location != null && entry.getValue().location.equals(getLocation())){
+                                       sessionID = entry.getKey();
+                               }
+                       }
+               }
+               return sessionID;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getRecordingSessionID()
+        */
+       public String getRecordingSessionID() {
+               return recordingSessionID;
+       }
+
+       public void setRecordingSessionID(String sessionID) {
+               this.recordingSessionID = sessionID;
+               if (sessionID.length() > 0)
+                       albumsRecordingBySessionID.put(sessionID, this);
+       }
+
+       public void setSessionID(String sessionID) {
+               this.sessionID = sessionID;
+               if (sessionID.length() > 0)
+                       albumsBySessionID.put(sessionID, this);
+       }
+       
+       /**
+        * Is the album currently open for recording
+        * @param sessionId
+        * @return true if the album is currently being recording by an active debug session
+        */
+       public static boolean isSnapshotSession(String sessionId) {
+               EDCLaunch launch = EDCLaunch.getLaunchForSession(sessionId);
+               return launch != null && launch.isSnapshotLaunch();
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#createSnapshot(org.eclipse.cdt.dsf.service.DsfSession, org.eclipse.cdt.debug.edc.internal.services.dsf.Stack.StackFrameDMC, org.eclipse.core.runtime.IProgressMonitor)
+        */
+       public Snapshot createSnapshot(DsfSession session, StackFrameDMC stackFrame, IProgressMonitor monitor) throws Exception {
+               SubMonitor progress = SubMonitor.convert(monitor, "Creating Snapshot", 10000);
+               configureAlbum();
+               progress.worked(100);
+               
+               if (getLocation() == null || !getLocation().toFile().exists()){
+                               createEmptyAlbum(); 
+               }
+               
+               Snapshot snapshot = new Snapshot(this, session, stackFrame);
+               snapshot.writeSnapshotData(progress.newChild(7900));
+
+               snapshotList.add(snapshot);
+               saveAlbum(progress.newChild(1000));
+               
+               monitor.done();
+               return snapshot;
+       }
+
+       private void configureAlbum() {
+               saveAlbumInfo();
+               saveLaunchConfiguration();
+       }
+
+       private void saveAlbumInfo() {
+               if (!albumInfoSaved) {
+                       Element infoElement = document.createElement(INFO);
+                       infoElement.setAttribute("version", ALBUM_VERSION);
+                       Calendar calendar = Calendar.getInstance();
+                       infoElement.setAttribute("month", Integer.toString(calendar.get(Calendar.MONTH)));
+                       infoElement.setAttribute("day", Integer.toString(calendar.get(Calendar.DATE)));
+                       infoElement.setAttribute("year", Integer.toString(calendar.get(Calendar.YEAR)));
+                       infoElement.setAttribute("hour", Integer.toString(calendar.get(Calendar.HOUR)));
+                       infoElement.setAttribute("minute", Integer.toString(calendar.get(Calendar.MINUTE)));
+                       infoElement.setAttribute("second", Integer.toString(calendar.get(Calendar.SECOND)));
+
+                       Properties systemProps = System.getProperties();
+                       Map<String, Object> infoProps = new HashMap<String, Object>();
+                       Set<Object> systemKeys = systemProps.keySet();
+
+                       for (Object sysKey : systemKeys) {
+                               if (sysKey instanceof String)
+                                       infoProps.put((String) sysKey, systemProps.get(sysKey));
+                       }
+                       Element propsElement = SnapshotUtils.makeXMLFromProperties(document, infoProps);
+                       infoElement.appendChild(propsElement);
+
+                       getAlbumRootElement().appendChild(infoElement);
+                       albumInfoSaved = true;
+               }
+       }
+
+       private void saveResourceList() {
+               if (!resourceListSaved) {
+                       Element resourcesElement = document.createElement(RESOURCES);
+                       for (IPath filePath : files) {
+                               Element fileElement = document.createElement(FILE);
+                               fileElement.setAttribute("path", filePath.toOSString());
+                               resourcesElement.appendChild(fileElement);
+                       }
+                       getAlbumRootElement().appendChild(resourcesElement);
+                       resourceListSaved = true;
+               }
+       }
+
+       private void saveSnapshotMetadata() {
+               if (!metadataSaved || isRecording()) {
+                                       
+                       if (metadataSaved){
+                               // If metatdata is saved, it must be a live debug session so
+                               // we need to add a new snapshot to the snapshot list
+                               NodeList snapMetaDataNode = document.getElementsByTagName(METADATA);
+                               assert snapMetaDataNode.item(0) != null;
+                               document.getDocumentElement().removeChild(snapMetaDataNode.item(0));
+                       }
+                       
+                       Element metadataElement = document.createElement(METADATA);
+
+                       Element albumElement = document.createElement(ALBUM);
+                       albumElement.setAttribute("albumName", this.getDisplayName());
+                       metadataElement.appendChild(albumElement);
+
+                       Element snapshotsElement = document.createElement(SNAPSHOT_LIST);
+                       metadataElement.appendChild(snapshotsElement);
+
+                       for (Snapshot snap : snapshotList) {
+                               Element snapshotMetadataElement = document.createElement(SNAPSHOT);
+                               if (snap.getSnapshotDisplayName().length() == 0) {
+                                       snapshotMetadataElement.setAttribute("displayName", snap.getSnapshotFileName());
+                               } else {
+                                       snapshotMetadataElement.setAttribute("displayName", snap.getSnapshotDisplayName());
+                               }
+                               if (snap.getCreationDate() != null) {
+                                       snapshotMetadataElement.setAttribute("date", snap.getCreationDate().toString());
+                               } else {
+                                       snapshotMetadataElement.setAttribute("date", "unknown");
+                               }
+
+                               snapshotMetadataElement.setAttribute("description", snap.getSnapshotDescription());
+                               snapshotMetadataElement.setAttribute("fileName", snap.getSnapshotFileName());                           
+                               snapshotMetadataElement.setAttribute("referenceLocationSourceFile", snap.getReferenceLocationSourceFile());
+                               snapshotMetadataElement.setAttribute("referenceLocationLineNumber", String.valueOf(snap.getReferenceLocationLineNumber()));
+                               
+                               snapshotsElement.appendChild(snapshotMetadataElement);
+                       }
+                       getAlbumRootElement().appendChild(metadataElement);
+                       metadataSaved = true;
+               }
+       }
+
+       @SuppressWarnings("unchecked")
+       private void saveLaunchConfiguration() {
+               if (!launchConfigSaved) {
+                       EDCLaunch launch = EDCLaunch.getLaunchForSession(getRecordingSessionID());
+                       try {
+                               Map<String, Object> map = launch.getLaunchConfiguration().getAttributes();
+                               Element launchElement = document.createElement(LAUNCH);
+                               launchType = launch.getLaunchConfiguration().getType().getIdentifier();
+                               launchName = launch.getLaunchConfiguration().getName();
+                               Integer count = launchNames.get(launchName);
+                               if (count == null) {
+                                       launchNames.put(launchName, new Integer(0));
+                               }
+                               else {
+                                       count = new Integer(count.intValue() + 1);
+                                       launchNames.put(launchName, count);
+                                       launchName += " (" + count.toString() + ")";
+                               }
+                               launchElement.setAttribute("type", launchType);
+                               launchElement.setAttribute("name", launchName);
+                               Element propsElement = SnapshotUtils.makeXMLFromProperties(document, map);
+                               launchElement.appendChild(propsElement);
+                               getAlbumRootElement().appendChild(launchElement);
+                       } catch (CoreException e) {
+                               EDCDebugger.getMessageLogger().logError(null, e);
+                       }
+                       launchConfigSaved = true;
+               }
+       }
+
+       private static void addZipEntry(ZipOutputStream zipOut, IAlbumArchiveEntry entry, File file)
+                       throws FileNotFoundException, IOException {
+               if (file.exists()) {
+                       if (file.isDirectory()) {
+                               for (File child : file.listFiles()) {
+                                       addZipEntry(zipOut, entry, child);
+                               }
+                       } else {
+                               // Add ZIP entry to output stream.m
+                               String path = ""; //$NON-NLS-1$
+
+                               if (entry != null) {
+                                       path = entry.createEntryName(file);
+                               } else {
+                                       path = file.getName();
+                               }
+
+                               zipOut.putNextEntry(new ZipEntry(path));
+
+                               // Create a buffer for reading the files
+                               byte[] buf = new byte[1024];
+
+                               // Transfer bytes from the file to the ZIP file
+                               // and compress the files
+                               FileInputStream in = new FileInputStream(file);
+                               int len;
+                               while ((len = in.read(buf)) > 0) {
+                                       zipOut.write(buf, 0, len);
+                               }
+
+                               // Complete the entry
+                               zipOut.closeEntry();
+                               in.close();
+                       }
+               }
+       }
+
+       /**
+        * Create and write a full snapshot album from scratch
+        */
+       private void saveAlbum(IProgressMonitor monitor) {
+
+               IPath zipPath = getLocation();
+               ZipOutputStream zipOut = null;
+               try {
+                       SubMonitor progress = SubMonitor.convert(monitor, 2000 + (snapshotList.size() * 1000));
+                       progress.subTask("Saving album data");
+
+                       zipOut = new ZipOutputStream(new FileOutputStream(zipPath.toFile()));
+
+                       zipOut.putNextEntry(new ZipEntry(ALBUM_DATA));
+
+                       saveResourceList();
+                       progress.worked(1000);
+                       saveSnapshotMetadata();
+                       progress.worked(1000);
+
+                       String xml = LaunchManager.serializeDocument(document);
+                       zipOut.write(xml.getBytes("UTF8")); //$NON-NLS-1$
+                       zipOut.closeEntry();
+
+                       for (Snapshot snap : snapshotList) {
+                               zipOut.putNextEntry(new ZipEntry(snap.getSnapshotFileName()));
+                               snap.saveSnapshot(zipOut);
+                               progress.worked(1000);
+                       }
+
+               } catch (Exception e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               } finally {
+                       try {
+                               if (zipOut != null) {
+                                       zipOut.close();
+                               }
+                       } catch (IOException e) {
+                               e.printStackTrace();
+                       }
+               }
+       }
+
+       /**
+        * Create and write a full snapshot album from scratch
+        */
+       private void saveResources(IProgressMonitor monitor) {
+
+               IPath zipPath = getLocation();
+               ZipOutputStream zipOut = null;
+               try {
+                       // TODO: Here's we're just rewriting the entire album again
+                       // Need to just add the resources alone using proper utils
+                       zipOut = new ZipOutputStream(new FileOutputStream(zipPath.toFile()));
+
+                       for (IPath path : files) {
+
+                               IAlbumArchiveEntry entry = new IAlbumArchiveEntry() {
+
+                                       public String createEntryName(File file) {
+                                               StringBuffer entryPath = new StringBuffer();
+
+                                               entryPath.append("Resources/");
+
+                                               IPath filepath = new Path(file.getAbsolutePath());
+
+                                               String deviceName = filepath.getDevice();
+                                               if (deviceName != null) {
+                                                       // Remove the : from the end
+                                                       entryPath.append(deviceName.substring(0, deviceName.length() - 1));
+                                                       entryPath.append("/");
+                                               }
+                                               
+                                               String[] segments = filepath.segments();
+                                               int numSegments = segments.length - 1;
+
+                                               for (int i = 0; i < numSegments; i++) {
+                                                       entryPath.append(segments[i]);
+                                                       entryPath.append("/");
+                                               }
+                                               entryPath.append(file.getName());
+                                               return entryPath.toString();
+                                       }
+                               };
+                               addZipEntry(zipOut, entry, path.toFile());
+                               if (monitor != null) {
+                                       monitor.worked(1);
+                               }
+                       }
+                       zipOut.putNextEntry(new ZipEntry(ALBUM_DATA));
+
+                       saveResourceList();
+                       saveSnapshotMetadata();
+
+                       String xml = LaunchManager.serializeDocument(document);
+                       zipOut.write(xml.getBytes("UTF8")); //$NON-NLS-1$
+                       zipOut.closeEntry();
+
+                       for (Snapshot snap : snapshotList) {
+                               zipOut.putNextEntry(new ZipEntry(snap.getSnapshotFileName()));
+                               snap.saveSnapshot(zipOut);
+                       }
+
+               } catch (Exception e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               } finally {
+                       try {
+                               if (zipOut != null) {
+                                       zipOut.close();
+                               }
+                       } catch (IOException e) {
+                               e.printStackTrace();
+                       }
+               }
+       }
+
+       private String getDefaultAlbumName() {
+               return getLaunchName();
+       }
+
+       public void saveAlbum(IPath path) throws TransformerException, IOException {
+               String xml = LaunchManager.serializeDocument(document);
+               File file = path.toFile();
+               if (!file.exists()) {
+                       file.createNewFile();
+               }
+               FileOutputStream stream = new FileOutputStream(file);
+               stream.write(xml.getBytes("UTF8")); //$NON-NLS-1$
+               stream.close();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#openSnapshot(int)
+        */
+       public void openSnapshot(final int index) {
+
+               final DsfSession session = DsfSession.getSession(sessionID);
+
+               DsfRunnable openIt = new DsfRunnable() {
+                       public void run() {
+                               currentSnapshotIndex = index;
+                               try {
+                                       loadAlbum(false);
+                               } catch (Exception e) {
+                                       EDCDebugger.getMessageLogger().logError(null, e);
+                               }
+                               if (session != null && snapshotList.size() > index) {
+                                       Snapshot snapshot = snapshotList.get(index);
+                                       snapshot.open(session);
+                                       // Fire the event
+                                       for (ISnapshotAlbumEventListener l : new ArrayList<ISnapshotAlbumEventListener>(listeners)) {
+                                               l.snapshotOpened(snapshot);
+                                       }
+                               }
+                       }
+               };
+
+               if (session != null && session.getExecutor() != null)
+               {
+                       if (session.getExecutor().isInExecutorThread())
+                               openIt.run();
+                       else
+                               session.getExecutor().execute(openIt);
+               }
+
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getCurrentSnapshotIndex()
+        */
+       public int getCurrentSnapshotIndex() {
+               return currentSnapshotIndex;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#openNextSnapshot()
+        */
+       public void openNextSnapshot() throws Exception {
+               int nextIndex = currentSnapshotIndex + 1;
+               if (nextIndex >= snapshotList.size())
+                       nextIndex = 0;
+               openSnapshot(nextIndex);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#openPreviousSnapshot()
+        */
+       public void openPreviousSnapshot() throws Exception {
+               int previousIndex = currentSnapshotIndex - 1;
+               if (previousIndex < 0)
+                       previousIndex = snapshotList.size() - 1;
+               openSnapshot(previousIndex);
+       }
+
+       public void loadAlbum(boolean force) throws ParserConfigurationException, SAXException, IOException {
+               if (force)
+                       loaded = false;
+               if (!loaded) {
+                       File albumFile = location.toFile();
+                       setName(albumFile.getName());
+                       
+                       if (!isRecording()){
+                               // not creating the snapshot, so must be snapshot play back     
+                               try {
+                                       ZipFileUtils.unzipFiles(albumFile, getAlbumRootDirectory().toOSString(), new NullProgressMonitor());
+                               } catch (Exception e) {
+                                       EDCDebugger.getMessageLogger().logError(null, e);
+                               }
+                       }
+                       
+                       BufferedInputStream stream = ZipFileUtils.openFile(albumFile, ALBUM_DATA, DSA_FILE_EXTENSIONS);
+                       DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+                       parser.setErrorHandler(new DefaultHandler());
+                       setDocument(parser.parse(new InputSource(stream)));
+
+                       loadAlbumInfo();
+                       loadLaunchConfiguration();
+                       loadResourceList();
+                       try {
+                               loadSnapshotMetadata();
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       } finally {
+                               loaded = true;
+                               ZipFileUtils.unmount();
+                       }
+               }
+       }
+
+       /**
+        * A lightwieght parse to get basic album info and what snapshots are
+        * available.
+        * 
+        * @throws ParserConfigurationException
+        * @throws SAXException
+        * @throws IOException
+        */
+       public void loadAlbumMetada(boolean force) throws Exception {
+               if (force)
+                       metaDataLoaded = false;
+               if (!metaDataLoaded) {
+                       
+                       File albumFile = location.toFile();
+                       setDisplayName(albumFile.getName());
+
+                       BufferedInputStream stream = null;
+                       try {
+                               stream = ZipFileUtils.openFile(albumFile, ALBUM_DATA, DSA_FILE_EXTENSIONS);
+                               DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+                               parser.setErrorHandler(new DefaultHandler());
+                               setDocument(parser.parse(new InputSource(stream)));
+                               loadSnapshotMetadata();
+                               loadLaunchConfiguration(); // need to load launch config in case we need to delete it
+
+                       } catch (Exception e) {
+                               EDCDebugger.getMessageLogger().logError("Failed to load album: " + getName(), e);
+                       } finally {
+                               metaDataLoaded = true;
+                               ZipFileUtils.unmount();
+                       }
+               }
+       }
+
+       private void loadAlbumInfo() {
+               document.getElementsByTagName(INFO).item(0);
+       }
+
+       private void setDocument(Document newDoc)
+       {
+               document = newDoc;
+               albumRootElement = null;
+       }
+       
+       private Element getAlbumRootElement()
+       {
+               if (albumRootElement == null)
+               {
+                       NodeList albumRootElements = document.getElementsByTagName(ALBUM);
+                       if (albumRootElements.getLength() == 0)
+                       {
+                               albumRootElement = document.createElement(ALBUM);
+                               document.appendChild(albumRootElement);
+                       }
+                       else
+                       {
+                               albumRootElement = (Element) albumRootElements.item(0);
+                       }
+               }
+               return albumRootElement;
+       }
+       
+       private void loadResourceList() {
+               NodeList resources = document.getElementsByTagName(RESOURCES);
+               NodeList elementFiles = ((Element) resources.item(0)).getElementsByTagName(FILE);
+               int numFiles = elementFiles.getLength();
+               for (int i = 0; i < numFiles; i++) {
+                       Element fileElement = (Element) elementFiles.item(i);
+                       String elementPath = fileElement.getAttribute("path");
+                       files.add(PathUtils.createPath(elementPath));           // for cross-created snapshot
+               }
+       }
+
+       private void loadSnapshotMetadata() throws Exception {
+               snapshotList.clear();
+               NodeList snapMetaDataNode = document.getElementsByTagName(METADATA);
+
+               if (snapMetaDataNode.getLength() == 0) {
+                       throw new Exception("Invalid or corrupted Album : " + getName());
+               }
+               NodeList albumNameElement = ((Element) snapMetaDataNode.item(0)).getElementsByTagName(ALBUM);
+               Element albumElement = (Element) albumNameElement.item(0);
+               String albumDisplayName = albumElement.getAttribute("albumName");
+
+               setDisplayName(albumDisplayName);
+
+               NodeList elementSnapshots = ((Element) snapMetaDataNode.item(0)).getElementsByTagName(SNAPSHOT);
+               int numSnapshots = elementSnapshots.getLength();
+               for (int i = 0; i < numSnapshots; i++) {
+                       Element snapshotElement = (Element) elementSnapshots.item(i);
+                       String elementDescription = snapshotElement.getAttribute("description");
+                       String elementDate = snapshotElement.getAttribute("date");
+                       String elementDispalyName = snapshotElement.getAttribute("displayName");
+                       String elementFileName = snapshotElement.getAttribute("fileName");
+                       String referenceLocationSourceFile = snapshotElement.getAttribute("referenceLocationSourceFile");
+                       String referenceLocationLineNumber = snapshotElement.getAttribute("referenceLocationLineNumber");
+                       
+                       Snapshot s = new Snapshot(this);
+                       s.setCreationDate(elementDate);
+                       s.setSnapshotFileName(elementFileName);
+                       s.setSnapshotDisplayName(elementDispalyName);
+                       s.setSnapshotDescription(elementDescription);
+                       if (referenceLocationLineNumber.length() > 0){
+                               s.setReferenceLocationLineNumber(Long.parseLong(referenceLocationLineNumber));
+                       }
+                       s.setReferenceLocationSourceFile(referenceLocationSourceFile);
+                       snapshotList.add(s);
+               }
+       }
+
+       private void loadLaunchConfiguration() {
+               NodeList launchElements = document.getElementsByTagName(LAUNCH);
+               Element launchElement = (Element) launchElements.item(0);
+               if (launchElement == null){
+                       return;
+               }
+               launchType = launchElement.getAttribute("type");
+               launchName = launchElement.getAttribute("name");
+
+               Element propElement = (Element) launchElement.getElementsByTagName(SnapshotUtils.PROPERTIES).item(0);
+               launchProperties = new HashMap<String, Object>();
+               try {
+                       SnapshotUtils.initializeFromXML(propElement, launchProperties);
+               } catch (Exception e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+
+       }
+
+       @SuppressWarnings("rawtypes")
+       @Override
+       public Object getAdapter(Class adapter) {
+               if (adapter.equals(Document.class))
+                       return document;
+
+               return super.getAdapter(adapter);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getAlbumRootDirectory()
+        */
+       public IPath getAlbumRootDirectory() {
+               if (albumRootDirectory == null) {
+                       IPath path = EDCDebugger.getDefault().getStateLocation().append("SnapshotAlbums");
+                       String locationName = location.lastSegment();
+                       int extension = locationName.lastIndexOf(".");
+                       if (extension > 0) {
+                               locationName = locationName.substring(0, extension);
+                       }
+                       path = path.append(locationName);
+                       File dir = path.toFile();
+                       if (!dir.exists()) {
+                               dir.mkdirs();
+                       }
+                       albumRootDirectory = path;
+               }
+               return albumRootDirectory;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getLaunchTypeID()
+        */
+       public String getLaunchTypeID() {
+               return launchType;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getLaunchProperties()
+        */
+       public HashMap<String, Object> getLaunchProperties() {
+               return launchProperties;
+       }
+
+       public void setLaunchProperties(HashMap<String, Object> launchProperties) {
+               this.launchProperties = launchProperties;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getLaunchName()
+        */
+       public String getLaunchName() {
+               return launchName;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#playSnapshots(org.eclipse.cdt.dsf.service.DsfSession)
+        */
+       public void playSnapshots() {
+               if (!isPlayingSnapshots())
+               {
+                       Job playSnapshotsJob = new Job("Play Snapshots for Album " + getDisplayName()){
+
+                               @Override
+                               protected IStatus run(IProgressMonitor monitor) {
+                                       try {
+                                               monitor.beginTask("Play Snapshots for Album " + getDisplayName(), IProgressMonitor.UNKNOWN);
+                                               while (isPlayingSnapshots() && !monitor.isCanceled())
+                                               {
+                                                       Album.this.openNextSnapshot();
+                                                       Thread.sleep(getPlaySnapshotInterval());
+                                               }
+                                               setPlayingSnapshots(false);
+                                               monitor.done();
+                                       } catch (Exception e) {
+                                               EDCDebugger.getMessageLogger().logError(null, e);
+                                               return new Status(Status.ERROR, EDCDebugger.PLUGIN_ID, null, e);
+                                       }
+                                       return Status.OK_STATUS;
+                               }
+                               
+                       };
+                       setPlayingSnapshots(true);
+                       playSnapshotsJob.schedule();
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#addFile(org.eclipse.core.runtime.IPath)
+        */
+       public void addFile(IPath path) {
+               files.add(path);
+       }
+
+       public static Album getAlbumByLocation(IPath path) {
+               return albumsByLocation.get(path);
+       }
+
+       public static IAlbum getAlbumBySession(String sessionId) {
+               return albumsBySessionID.get(sessionId);
+       }
+
+       public static Album getRecordingForSession(String sessionId) {
+               return albumsRecordingBySessionID.get(sessionId);
+       }
+
+       public void setLocation(IPath albumPath) {
+               this.location = albumPath;
+               albumsByLocation.put(albumPath, this);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getLocation()
+        */
+       public IPath getLocation() {
+               return location;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#configureSourceLookupDirector(org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector)
+        */
+       public void configureSourceLookupDirector(ISourceLookupDirector director) {
+               MappingSourceContainer sourceContainer = new MappingSourceContainer(getName());
+               configureMappingSourceContainer(sourceContainer);
+               ArrayList<ISourceContainer> containers = new ArrayList<ISourceContainer>(Arrays.asList(director
+                               .getSourceContainers()));
+               containers.add(sourceContainer);
+
+               DirectorySourceContainer directoryContainer = new DirectorySourceContainer(getResourcesDirectory(), true);
+               containers.add(directoryContainer);
+
+               director.setSourceContainers(containers.toArray(new ISourceContainer[containers.size()]));
+       }
+
+       protected IPath getResourcesDirectory()
+       {
+               return getAlbumRootDirectory().append("Resources");
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#configureMappingSourceContainer(org.eclipse.cdt.debug.core.sourcelookup.MappingSourceContainer)
+        */
+       public void configureMappingSourceContainer(MappingSourceContainer mappingContainer) {
+               IPath albumRoot = getResourcesDirectory();
+               List<MapEntrySourceContainer> containers = new ArrayList<MapEntrySourceContainer>();
+               Set<String> devicesAlreadyAdded = new HashSet<String>();
+               String deviceName = null;
+               for (IPath iPath : files) {
+                       deviceName = iPath.getDevice();
+                       if (deviceName != null && !devicesAlreadyAdded.contains(deviceName))
+                       {
+                               String albumRootSuffix = deviceName;
+                if (albumRootSuffix.endsWith(":"))
+                       albumRootSuffix = albumRootSuffix.substring(0, albumRootSuffix.length() - 1);
+                               devicesAlreadyAdded.add(deviceName);
+                            MapEntrySourceContainer newContainer = new MapEntrySourceContainer(PathUtils.createPath(deviceName), albumRoot.append(albumRootSuffix));
+                            containers.add(newContainer);
+                                
+                       }
+               }
+               mappingContainer.addMapEntries(containers.toArray(new MapEntrySourceContainer[containers.size()]));
+       }
+
+       public static void setVariableCaptureDepth(int newSetting) {
+               IEclipsePreferences scope = InstanceScope.INSTANCE.getNode(EDCDebugger.PLUGIN_ID);
+               scope.putInt(PREF_VARIABLE_CAPTURE_DEPTH, newSetting);
+               try {
+                       scope.flush();
+               } catch (BackingStoreException e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+       }
+
+       public static int getVariableCaptureDepth() {
+               return Platform.getPreferencesService().getInt(EDCDebugger.PLUGIN_ID,
+                               PREF_VARIABLE_CAPTURE_DEPTH, 5, null);
+       }
+
+       public static void setPlaySnapshotInterval(int delayInMilliseconds) {
+               IEclipsePreferences scope = InstanceScope.INSTANCE.getNode(EDCDebugger.PLUGIN_ID);
+               scope.putInt(PLAY_SNAPSHOT_DELAY_TIME, delayInMilliseconds);
+               try {
+                       scope.flush();
+               } catch (BackingStoreException e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+       }
+
+       public static int getPlaySnapshotInterval() {
+               return Platform.getPreferencesService().getInt(EDCDebugger.PLUGIN_ID,
+                               PLAY_SNAPSHOT_DELAY_TIME, 5000, null);
+       }
+
+       public static void setSnapshotCreationControl(String newSetting) {
+               IEclipsePreferences scope = InstanceScope.INSTANCE.getNode(EDCDebugger.PLUGIN_ID);
+               scope.put(PREF_CREATION_CONTROL, newSetting);
+               try {
+                       scope.flush();
+               } catch (BackingStoreException e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+       }
+
+       public static String getSnapshotCreationControl() {
+               return Platform.getPreferencesService().getString(EDCDebugger.PLUGIN_ID,
+                               PREF_CREATION_CONTROL, CREATE_MANUAL, null);
+       }
+
+       protected static void playSnapshotSound() {
+               Bundle bundle = Platform.getBundle(EDCDebugger.getUniqueIdentifier());
+               if (bundle == null)
+                       return;
+               
+               URL url = null;
+               try {
+                       url = FileLocator.toFileURL(bundle.getEntry(CAMERA_CLICK_WAV));
+               } catch (IOException e) {
+               } catch (RuntimeException e){
+               }
+               finally {
+                       if (url != null){
+                               File f = new File(url.getFile());
+                               SnapshotUtils.playSoundFile(f);
+                       }
+               }
+               
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getSnapshots()
+        */
+       public List<Snapshot> getSnapshots() {
+               if (snapshotList == null || snapshotList.size() == 0) {
+                       try {
+                               loadAlbumMetada(false);
+                       } catch (Exception e) {
+                               EDCDebugger.getMessageLogger().logError("Failed to load snapshots", e);
+                       }
+               }
+
+               return snapshotList;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#isLoaded()
+        */
+       public boolean isLoaded() {
+               return loaded;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#getIndexOfSnapshot(org.eclipse.cdt.debug.edc.internal.snapshot.Snapshot)
+        */
+       public int getIndexOfSnapshot(Snapshot snap) {
+               return snapshotList.indexOf(snap);
+       }
+
+       public void setCurrentSnapshotIndex(int index) {
+               if (currentSnapshotIndex >= 0 && currentSnapshotIndex < snapshotList.size()) {
+                       currentSnapshotIndex = index;
+               }
+       }
+
+       /**
+        * Update album.xml within the Album's .dsa file with new Snapshot data
+        * 
+        * @param albumName
+        *            - Name of album to display. Use null if value should not be
+        *            updated.
+        * @param snap
+        *            - Specific snapshot to update. Use null is snapshot should not
+        *            be updated.
+        */
+       public void updateSnapshotMetaData(String albumName, Snapshot snap) {
+               NodeList snapMetaDataNode = document.getElementsByTagName(METADATA);
+               
+               // try to update album display name
+               if (albumName != null) {
+                       NodeList albumNameNode = ((Element) snapMetaDataNode.item(0)).getElementsByTagName(ALBUM);
+                       ((Element) albumNameNode.item(0)).setAttribute("albumName", albumName);
+               }
+
+               // try to update snapshot data
+               if (snap != null) {
+
+                       NodeList elementSnapshots = ((Element) snapMetaDataNode.item(0)).getElementsByTagName(SNAPSHOT);
+
+                       int numSnapshots = elementSnapshots.getLength();
+                       for (int i = 0; i < numSnapshots; i++) {
+                               Element currentSnapshotNode = (Element) elementSnapshots.item(i);
+                               String fileName = currentSnapshotNode.getAttribute("fileName");
+                               if (fileName.equals(snap.getSnapshotFileName())) {
+
+                                       currentSnapshotNode.setAttribute("description", snap.getSnapshotDescription());
+                                       currentSnapshotNode.setAttribute("displayName", snap.getSnapshotDisplayName());
+
+                                       break;
+                               }
+                       }
+               }
+
+               saveAlbumData();
+
+               // refresh all data
+               try {
+                       loadAlbumMetada(true);
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+       }
+
+       private void saveAlbumData() {
+               try {
+                       File tempFile = File.createTempFile("album", ".xml");
+                       File tempFile2 = new File(tempFile.getParent() + File.separator + ALBUM_DATA);
+                       tempFile.delete();
+                       if (!tempFile2.exists()) {
+                               tempFile2.delete();
+                       }
+                       tempFile2.createNewFile();
+                       saveAlbum(new Path(tempFile2.toString()));
+                       File[] fileList = { tempFile2 };
+                       ZipFileUtils.addFilesToZip(fileList, getLocation().toFile(), DSA_FILE_EXTENSIONS);
+
+               } catch (IOException e) {
+                       e.printStackTrace();
+               } catch (TransformerException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#deleteSnapshot(org.eclipse.cdt.debug.edc.internal.snapshot.Snapshot)
+        */
+       public void deleteSnapshot(Snapshot snap) {
+
+               NodeList snapMetaDataNode = document.getElementsByTagName(METADATA);
+
+               NodeList elementSnapshotList = ((Element) snapMetaDataNode.item(0)).getElementsByTagName(SNAPSHOT_LIST);
+               NodeList elementSnapshots = ((Element) snapMetaDataNode.item(0)).getElementsByTagName(SNAPSHOT);
+
+               int numSnapshots = elementSnapshots.getLength();
+               for (int i = 0; i < numSnapshots; i++) {
+                       Element currentSnapshotNode = (Element) elementSnapshots.item(i);
+                       String fileName = currentSnapshotNode.getAttribute("fileName");
+                       if (fileName.equals(snap.getSnapshotFileName())) {
+                               elementSnapshotList.item(0).removeChild(currentSnapshotNode);
+                               break;
+                       }
+               }
+
+               snapshotList.remove(snap);
+
+               saveAlbumData();
+
+               // refresh all data
+               try {
+                       loadAlbum(true);
+                       loadAlbumMetada(true);
+               } catch (Exception e) {
+
+               }
+
+               ZipFileUtils.deleteFileFromZip(snap.getSnapshotFileName(), getLocation().toFile(), DSA_FILE_EXTENSIONS);
+       }
+
+       @Override
+       public String toString() {
+               return "Album [name=" + name + ", launchName=" + launchName + ", sessionID=" + sessionID + "]";
+       }
+       
+       public IPath createEmptyAlbum() {
+               IPath zipPath = null;
+               try {
+                       zipPath = SnapshotUtils.getSnapshotsProject().getLocation();
+                       zipPath = zipPath.append(getDefaultAlbumName());
+                       zipPath = zipPath.addFileExtension("dsa");
+                       boolean created =  ZipFileUtils.createNewZip(zipPath.toFile());
+                       
+                       if (created && zipPath.toFile().exists()){
+                               setLocation(zipPath);
+                       } else {
+                               return null;
+                       }
+                       SnapshotUtils.getSnapshotsProject().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
+               } catch (CoreException e) {
+                       EDCDebugger.getMessageLogger().logError(e.getLocalizedMessage(), e);
+               }               
+               return zipPath;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.snapshot.IAlbum#isRecording()
+        */
+       public boolean isRecording() {
+               return recordingSessionID.length() > 0;
+       }
+
+       /**
+        * @noreference This method is not intended to be referenced by clients.
+        */
+       public static void addSnapshotAlbumEventListener(ISnapshotAlbumEventListener listener) {
+               listeners.add(listener);
+       }
+       
+       /**
+        * @noreference This method is not intended to be referenced by clients.
+        */
+       public static void removeSnapshotAlbumEventListener(ISnapshotAlbumEventListener listener) {
+               listeners.remove(listener);
+       }
+
+       public static void captureSnapshotForSession(final DsfSession session) {
+               Job createSnapshotJob = new Job("Creating Debug Snapshot") {
+
+                       @Override
+                       protected IStatus run(final IProgressMonitor monitor) {
+
+                               Query<IFrameDMContext> frameQuery = new Query<IFrameDMContext>() {
+                                       @Override
+                                       protected void execute(
+                                                       DataRequestMonitor<IFrameDMContext> rm) {
+                                               DsfServicesTracker servicesTracker = new DsfServicesTracker(
+                                                               EDCDebugger.getBundleContext(),
+                                                               session.getId());
+                                               try {
+                                                       RunControl runControl = servicesTracker.getService(RunControl.class);
+                                                       IThreadDMContext[] suspendedThreads = runControl.getSuspendedThreads();
+                                                       if (suspendedThreads.length == 0)
+                                                       {
+                                                               rm.setData(null);
+                                                               rm.done();
+                                                       }
+                                                       else
+                                                       {
+                                                               Stack stackService = servicesTracker.getService(Stack.class);
+                                                               if (stackService != null) {
+                                                                       stackService.getTopFrame(suspendedThreads[0], rm);
+                                                               }
+                                                       }
+                                               } finally {
+                                                       servicesTracker.dispose();
+                                               }
+                                       }
+                               };
+
+                               session.getExecutor().execute(frameQuery);
+
+                               IStatus status = Status.OK_STATUS;
+                               try {
+                                       final StackFrameDMC stackFrame = (StackFrameDMC) frameQuery.get();
+
+                                       String sessionId = session.getId();
+                                       Album album = Album.getRecordingForSession(sessionId);
+                                       if (album == null) {
+                                               album = new Album();
+                                               album.setRecordingSessionID(sessionId);
+                                       }
+                                       final Album finalAlbum = album;
+                                       playSnapshotSound();
+
+                                       Query<IStatus> query = new Query<IStatus>() {
+                                               @Override
+                                               protected void execute(final DataRequestMonitor<IStatus> drm) {
+                                                       try {
+                                                               Snapshot newSnapshot = finalAlbum.createSnapshot(session, stackFrame, monitor);
+                                                               // Fire the event to anyone listening
+                                                               for (ISnapshotAlbumEventListener l : new ArrayList<ISnapshotAlbumEventListener>(listeners)) {
+                                                                       l.snapshotCreated(finalAlbum, newSnapshot, session, stackFrame);
+                                                               }
+                                                               drm.setData(Status.OK_STATUS);
+                                                       } catch (Exception e) {
+                                                               Status s = new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "Error creating snapshot.", e);
+                                                               EDCDebugger.getMessageLogger().log(s);
+                                                               drm.setStatus(s);
+                                                       }
+                                                       drm.done();
+                                               }
+                                       };
+
+                                       session.getExecutor().execute(query);
+
+                                       status = query.get();
+                               } catch (Exception e) {
+                                       status = new Status(Status.ERROR, EDCDebugger.PLUGIN_ID, "Error creating snapshot", e);
+                               }
+
+                               return status;
+                       }
+               };
+
+               createSnapshotJob.schedule();
+       }
+
+    public boolean isPlayingSnapshots() {
+               return playingSnapshots;
+       }
+
+       public void setPlayingSnapshots(boolean playingSnapshots) {
+               this.playingSnapshots = playingSnapshots;
+       }
+
+       public void stopPlayingSnapshots() {
+               setPlayingSnapshots(false);
+               openSnapshot(getCurrentSnapshotIndex()); // Reloading the current snapshot will resync the UI.
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/AlbumSourceContainer.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/AlbumSourceContainer.java
new file mode 100644 (file)
index 0000000..143f5c9
--- /dev/null
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.snapshot;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.snapshot.IAlbum;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.sourcelookup.ISourceContainerType;
+import org.eclipse.debug.core.sourcelookup.containers.AbstractSourceContainer;
+
+public class AlbumSourceContainer extends AbstractSourceContainer {
+
+       private IAlbum album;
+
+       public static final String TYPE_ID = EDCDebugger.getUniqueIdentifier() + ".containerType.albumMapping"; //$NON-NLS-1$
+
+       public AlbumSourceContainer(IAlbum album) {
+               this.album = album;
+       }
+
+       public AlbumSourceContainer() {
+       }
+
+       public Object[] findSourceElements(String name) throws CoreException {
+               // TODO Auto-generated method stub
+               return new Object[0];
+       }
+
+       public String getName() {
+               return album.getDisplayName();
+       }
+
+       public ISourceContainerType getType() {
+               return getSourceContainerType(TYPE_ID);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/AlbumSourceContainerType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/AlbumSourceContainerType.java
new file mode 100644 (file)
index 0000000..289cefc
--- /dev/null
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.snapshot;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.containers.AbstractSourceContainerTypeDelegate;
+
+public class AlbumSourceContainerType extends AbstractSourceContainerTypeDelegate {
+
+       public ISourceContainer createSourceContainer(String memento) throws CoreException {
+               return new AlbumSourceContainer();
+       }
+
+       public String getMemento(ISourceContainer container) throws CoreException {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/ISnapshotAlbumEventListener.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/ISnapshotAlbumEventListener.java
new file mode 100644 (file)
index 0000000..0acbd7e
--- /dev/null
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.snapshot;
+
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+public interface ISnapshotAlbumEventListener {
+
+       public void snapshotCreated(Album album, Snapshot snapshot,
+                       DsfSession session, StackFrameDMC stackFrame);
+
+       public void snapshotOpened(Snapshot snapshot);
+
+       public void snapshotSessionEnded(Album album, DsfSession session);
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/Snapshot.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/Snapshot.java
new file mode 100644 (file)
index 0000000..2b44aa4
--- /dev/null
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.snapshot;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+import java.util.zip.ZipOutputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.TransformerException;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.ZipFileUtils;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.snapshot.ISnapshotContributor;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.internal.core.LaunchManager;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.helpers.DefaultHandler;
+
+@SuppressWarnings("restriction")
+public class Snapshot extends PlatformObject {
+       
+       // XML elements
+       public static final String SNAPSHOT = "snapshot";
+       
+       public static final String SNAPSHOT_FILENAME_PREFIX = "snapshot_";
+       
+       private Document document;
+       private Element snapshotRootElement;
+       private DsfSession session;
+       private Album album;
+       private String snapshotFileName;
+       private String snapshotDisplayName;
+
+       private String creationDate;
+
+       private String snapshotDescription;
+       
+       // Reference location information: when a snapshot is created
+       // we record the location in the most recently suspended stack frame.
+       // This is then used to create a default name for the snapshot and
+       // is displayed in the snapshot view.
+       // Of course, when debugging multiple contexts this does not
+       // provide a complete description of the snapshot.
+       
+       private String referenceLocationSourceFile = "";
+       private long referenceLocationLineNumber;
+       
+       /*
+        * Create a snapshot for reading
+        */
+       public Snapshot(Album album){
+               try {
+                       this.album = album;
+                       document = DebugPlugin.newDocument();
+                       snapshotRootElement = document.createElement(SNAPSHOT);
+               } catch (CoreException e) {
+                       e.printStackTrace();
+               }
+       }
+       
+       /**
+        * Create a snapshot with prep for writing to file.
+        * @param album
+        * @param recentStackFrame - 
+        */
+       public Snapshot(Album album, DsfSession session, StackFrameDMC recentStackFrame){
+               try {
+                       assert session != null;
+                       
+                       this.album = album;
+                       this.session = session;
+                       document = DebugPlugin.newDocument();
+                       snapshotRootElement = document.createElement(SNAPSHOT);
+                       document.appendChild(snapshotRootElement);
+                       
+                       if (recentStackFrame == null){
+                               snapshotDisplayName = snapshotFileName;
+                       } else {
+                               snapshotDisplayName = createSnapshotNameFromStackFrameDMC(recentStackFrame);
+                       }
+                       snapshotFileName = SNAPSHOT_FILENAME_PREFIX + System.currentTimeMillis() + ".xml";
+                       creationDate = new Date(System.currentTimeMillis()).toString();
+                       
+                       if (recentStackFrame != null){
+                               File f = new File(recentStackFrame.getSourceFile());
+                               if (f != null){
+                                       setReferenceLocationSourceFile(f.getName());
+                               } 
+                               setReferenceLocationLineNumber(recentStackFrame.getLineNumber());
+                       }
+                       
+               } catch (CoreException e) {
+                       e.printStackTrace();
+               }
+               
+       }
+
+       @SuppressWarnings("rawtypes")
+       @Override
+       public Object getAdapter(Class adapter) {
+               if (adapter.equals(Document.class))
+                       return document;
+
+               return super.getAdapter(adapter);
+       }
+       
+       private static String getServiceFilter(String sessionId) {
+               return ("(" + IDsfService.PROP_SESSION_ID + "=" + sessionId + ")").intern(); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+       }
+
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       public void open(DsfSession session) {
+               ServiceReference[] references;
+               BufferedInputStream stream = null;
+               try {
+                       
+                       stream = ZipFileUtils.openFile(album.getLocation().toFile(), snapshotFileName, new String[] {"dsa"} );
+                       DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+                       parser.setErrorHandler(new DefaultHandler());
+                       
+                       document = parser.parse(new InputSource(stream));
+                       NodeList snapNode = document.getElementsByTagName(SNAPSHOT);
+                       Element snapShotE = (Element)snapNode.item(0);
+                       
+                       references = EDCDebugger.getBundleContext().getServiceReferences(ISnapshotContributor.class.getName(),
+                                       getServiceFilter(session.getId()));
+                       for (ServiceReference serviceReference : references) {
+                               ISnapshotContributor sc = (ISnapshotContributor) EDCDebugger.getBundleContext().getService(
+                                               serviceReference);
+                               sc.loadSnapshot(snapShotE);
+                       }
+                       
+               } catch (Exception e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               } finally {
+                       ZipFileUtils.unmount();
+               }
+       }
+       
+       /**
+        * Write snapshot data.
+        *
+        * @param monitor the progress monitor to use for reporting progress to the user. It is the caller's responsibility
+        to call done() on the given monitor. Accepts null, indicating that no progress should be
+        reported and that the operation cannot be canceled.
+        */
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       public void writeSnapshotData(IProgressMonitor monitor) throws Exception{
+               try {
+                       ServiceReference[] references = EDCDebugger.getBundleContext().getServiceReferences(
+                                       ISnapshotContributor.class.getName(), getServiceFilter(session.getId()));
+                       SubMonitor progress = SubMonitor.convert(monitor, references.length * 1000);
+                       progress.subTask("Writing snapshot data");
+                       for (ServiceReference serviceReference : references) {
+                               if (progress.isCanceled())
+                                       break;
+                               ISnapshotContributor sc = (ISnapshotContributor) EDCDebugger.getBundleContext().getService(
+                                               serviceReference);
+                               Element serviceElement = sc.takeSnapshot(album, document, progress.newChild(1000));
+                               if (serviceElement != null)
+                                       snapshotRootElement.appendChild(serviceElement);
+                       }
+               } catch (InvalidSyntaxException e) {
+                       EDCDebugger.getMessageLogger().logError("Invalid session ID syntax", e); //$NON-NLS-1$
+               } catch (IllegalStateException e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+       }
+       
+       public String getSnapshotFileName(){
+               return snapshotFileName;
+       }
+       
+       public void setSnapshotFileName(String snapshotFileName){
+               this.snapshotFileName = snapshotFileName;
+       }
+       
+       public void saveSnapshot(ZipOutputStream zipOut) throws TransformerException, IOException {
+               String xml = LaunchManager.serializeDocument(document);
+               zipOut.write(xml.getBytes("UTF8")); //$NON-NLS-1$
+               zipOut.closeEntry();
+       }
+       
+       public String getCreationDate(){
+               return creationDate;
+       }
+       
+       public void setCreationDate(String date){
+               this.creationDate = date;
+       }
+
+       /**
+        * Set the display text for the snapshot
+        * @param snapshotDisplayName
+        */
+       public void setSnapshotDisplayName(String snapshotDisplayName) {
+               this.snapshotDisplayName = snapshotDisplayName;
+       }
+
+       /**
+        * Get the display name of the snapshot. If there is no display name, the XML file containing
+        * the snapshot data in the DSA archive will be used.
+        * @return
+        */
+       public String getSnapshotDisplayName() {
+               if (snapshotDisplayName == null || snapshotDisplayName.length() == 0){
+                       snapshotDisplayName = snapshotFileName;
+               }
+               return snapshotDisplayName;
+       }
+       
+       /**
+        * Additional arbitrary notes to describe a particular snapshot
+        * @return
+        */
+       public String getSnapshotDescription() {
+               if (snapshotDescription == null){
+                       snapshotDescription = "";
+               }
+               return snapshotDescription;
+       }
+       
+       /**
+        * Set the snapshot description text.
+        * @param descr
+        */
+       public void setSnapshotDescription(String descr) {
+               snapshotDescription = descr;
+       }
+       
+       /**
+        * Get the album this snapshot belongs to
+        * @return
+        */
+       public Album getAlbum(){
+               return album;
+       }
+       
+       /**
+        * Creates the snapshot name from a stack frame dmc.
+        * 
+        * @param frameDMC the frame dmc
+        * 
+        * @return the snapshot name
+        */
+       public String createSnapshotNameFromStackFrameDMC(StackFrameDMC stackFrame)
+       {
+               assert stackFrame != null;
+               StringBuilder name = new StringBuilder();
+               if (stackFrame.getFunctionName() != null && stackFrame.getFunctionName().length() != 0) {
+                       name.append(stackFrame.getFunctionName());
+                       name.append("() : "); //$NON-NLS-1$
+                       name.append(stackFrame.getLineNumber());
+               } else if (stackFrame.getModuleName() != null && stackFrame.getModuleName().length() != 0) {
+                       name.append(stackFrame.getModuleName());
+               } else if (stackFrame.getInstructionPtrAddress() != null) {
+                       name.append(stackFrame.getInstructionPtrAddress().toHexAddressString());
+               }
+
+               return name.toString(); 
+       }
+
+       public void setReferenceLocationSourceFile(String referenceLocationSourceFile) {
+               assert referenceLocationSourceFile != null;
+               this.referenceLocationSourceFile = referenceLocationSourceFile;
+       }
+
+       public String getReferenceLocationSourceFile() {
+               assert referenceLocationSourceFile != null;
+               return referenceLocationSourceFile;
+       }
+
+       public void setReferenceLocationLineNumber(long referenceLocationLineNumber) {
+               this.referenceLocationLineNumber = referenceLocationLineNumber;
+       }
+
+       public long getReferenceLocationLineNumber() {
+               return referenceLocationLineNumber;
+       }
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/SnapshotLaunchSequence.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/SnapshotLaunchSequence.java
new file mode 100644 (file)
index 0000000..d2b71ea
--- /dev/null
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.snapshot;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.launch.AbstractFinalLaunchSequence;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+public class SnapshotLaunchSequence extends AbstractFinalLaunchSequence {
+
+       private final Step[] steps = new Step[] {
+
+       trackerStep,
+
+       new Step() {
+
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       try {
+                               int snapIndex = getLaunch().getAlbum().getCurrentSnapshotIndex();
+                               getLaunch().getAlbum().openSnapshot(snapIndex);
+                               requestMonitor.done();
+                       } catch (Exception e) {
+                               requestMonitor.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID,
+                                               "Failed to open snapshot. Reason: " + e.getLocalizedMessage()));
+                       }
+               }
+
+       }
+
+       };
+
+       public SnapshotLaunchSequence(DsfExecutor executor, EDCLaunch launch, IProgressMonitor pm) {
+               super(executor, launch, pm, "Configuring Snapshot Launch", "Aborting configuring Snapshot Launch");
+       }
+
+       @Override
+       public Step[] getSteps() {
+               return steps;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.launch.AbstractFinalLaunchSequence#useLocalAgentOnly()
+        */
+       @Override
+       protected boolean useLocalAgentOnly() {
+               return true;
+       }
+       
+       @Override
+       protected void specifyRequiredPeer() {
+               // No TCF agent needed.
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/SnapshotUtils.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/SnapshotUtils.java
new file mode 100644 (file)
index 0000000..524c205
--- /dev/null
@@ -0,0 +1,649 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.snapshot;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.SourceDataLine;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.launch.IEDCLaunchConfigurationConstants;
+import org.eclipse.cdt.debug.edc.snapshot.IAlbum;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class SnapshotUtils extends PlatformObject {
+
+       /**
+        * Constants for XML element names and attributes
+        */
+       public static final String PROPERTIES = "properties"; //$NON-NLS-1$
+       private static final String KEY = "key"; //$NON-NLS-1$
+       private static final String VALUE = "value"; //$NON-NLS-1$
+       private static final String SET_ENTRY = "setEntry"; //$NON-NLS-1$
+       private static final String MAP_ENTRY = "mapEntry"; //$NON-NLS-1$
+       private static final String LIST_ENTRY = "listEntry"; //$NON-NLS-1$
+       private static final String SET_ATTRIBUTE = "setAttribute"; //$NON-NLS-1$
+       private static final String MAP_ATTRIBUTE = "mapAttribute"; //$NON-NLS-1$
+       private static final String LIST_ATTRIBUTE = "listAttribute"; //$NON-NLS-1$
+       private static final String BOOLEAN_ATTRIBUTE = "booleanAttribute"; //$NON-NLS-1$
+       private static final String INT_ATTRIBUTE = "intAttribute"; //$NON-NLS-1$
+       private static final String LONG_ATTRIBUTE = "longAttribute"; //$NON-NLS-1$
+       private static final String BIG_INTEGER_ATTRIBUTE = "bigIntegerAttribute"; //$NON-NLS-1$
+       private static final String STRING_ATTRIBUTE = "stringAttribute"; //$NON-NLS-1$
+       private static final String SERIALIZED_ATTRIBUTE = "serializedAttribute"; //$NON-NLS-1$
+
+       @SuppressWarnings("unchecked")
+       static public Element makeXMLFromProperties(Document doc, Map<String, Object> properties) {
+
+               Element rootElement = doc.createElement(PROPERTIES);
+               Iterator<String> keys = properties.keySet().iterator();
+               while (keys.hasNext()) {
+                       String key = keys.next();
+                       if (key != null) {
+                               Object value = properties.get(key);
+                               if (value == null) {
+                                       continue;
+                               }
+                               Element element = null;
+                               String valueString = null;
+                               try {
+                                       if (value instanceof String) {
+                                               valueString = (String) value;
+                                               element = createKeyValueElement(doc, STRING_ATTRIBUTE, key, valueString);
+                                       } else if (value instanceof Integer) {
+                                               valueString = ((Integer) value).toString();
+                                               element = createKeyValueElement(doc, INT_ATTRIBUTE, key, valueString);
+                                       } else if (value instanceof Long) {
+                                               valueString = ((Long) value).toString();
+                                               element = createKeyValueElement(doc, LONG_ATTRIBUTE, key, valueString);
+                                       } else if (value instanceof BigInteger) {
+                                               valueString = ((BigInteger) value).toString();
+                                               element = createKeyValueElement(doc, BIG_INTEGER_ATTRIBUTE, key, valueString);
+                                       } else if (value instanceof Boolean) {
+                                               valueString = ((Boolean) value).toString();
+                                               element = createKeyValueElement(doc, BOOLEAN_ATTRIBUTE, key, valueString);
+                                       } else if (value instanceof List<?>) {
+                                               element = createListElement(doc, LIST_ATTRIBUTE, key, (List<Object>) value);
+                                       } else if (value instanceof Map<?,?>) {
+                                               element = createMapElement(doc, MAP_ATTRIBUTE, key, (Map<Object, Object>) value);
+                                       } else if (value instanceof HashSet<?>) {
+                                               element = createSetElement(doc, SET_ATTRIBUTE, key, (Set<Object>) value);
+                                       }
+                               } catch (Exception e) { // Don't do anything here, we'll try to handle it as
+                                       // as serialized object. 
+                               }
+                               if (element == null)
+                               {
+                                       try {
+                                               element = createSerializedElement(doc, SERIALIZED_ATTRIBUTE, key, value);
+                                       } catch (IOException e) {EDCDebugger.getMessageLogger().logError("Error adding to snapshot: " + value.toString(), e);};
+                               }
+                               rootElement.appendChild(element);
+                       }
+               }
+               return rootElement;
+       }
+
+       /**
+        * Helper method that creates a 'key value' element of the specified type
+        * with the specified attribute values.
+        */
+       static protected Element createKeyValueElement(Document doc, String elementType, String key, String value) {
+               Element element = doc.createElement(elementType);
+               element.setAttribute(KEY, key);
+               element.setAttribute(VALUE, value);
+               return element;
+       }
+
+       /**
+        * Creates a new <code>Element</code> for the specified
+        * <code>java.util.List</code>
+        * 
+        * @param doc
+        *            the doc to add the element to
+        * @param elementType
+        *            the type of the element
+        * @param setKey
+        *            the key for the element
+        * @param list
+        *            the list to fill the new element with
+        * @return the new element
+        */
+       static protected Element createListElement(Document doc, String elementType, String listKey, List<Object> list) {
+               Element listElement = doc.createElement(elementType);
+               listElement.setAttribute(KEY, listKey);
+               Iterator<Object> iterator = list.iterator();
+               while (iterator.hasNext()) {
+                       String value = (String) iterator.next();
+                       Element element = doc.createElement(LIST_ENTRY);
+                       element.setAttribute(VALUE, value);
+                       listElement.appendChild(element);
+               }
+               return listElement;
+       }
+
+       /**
+        * Creates a new <code>Element</code> for the specified
+        * <code>java.util.Set</code>
+        * 
+        * @param doc
+        *            the doc to add the element to
+        * @param elementType
+        *            the type of the element
+        * @param setKey
+        *            the key for the element
+        * @param set
+        *            the set to fill the new element with
+        * @return the new element
+        * 
+        * @since 3.3
+        */
+       static protected Element createSetElement(Document doc, String elementType, String setKey, Set<Object> set) {
+               Element setElement = doc.createElement(elementType);
+               setElement.setAttribute(KEY, setKey);
+               Element element = null;
+               for (Object object : set) {
+                       element = doc.createElement(SET_ENTRY);
+                       element.setAttribute(VALUE, (String) object);
+                       setElement.appendChild(element);
+               }
+               return setElement;
+       }
+
+       static protected Element createSerializedElement(Document doc, String elementType, String key, Object value) throws IOException {
+               Element element = doc.createElement(elementType);
+               element.setAttribute(KEY, key);
+               element.appendChild(doc.createTextNode(serializeObjectToString(value)));
+               return element;
+       }
+
+       /**
+        * Creates a new <code>Element</code> for the specified
+        * <code>java.util.Map</code>
+        * <p>
+        * NOTE: this creates a <String, String> map from your map -- your ISnapshot#loadSnapshot() implementation
+        * must recover the right types.
+        * @param doc
+        *            the doc to add the element to
+        * @param elementType
+        *            the type of the element
+        * @param setKey
+        *            the key for the element
+        * @param map
+        *            the map to fill the new element with
+        * @return the new element
+        * 
+        */
+       static protected Element createMapElement(Document doc, String elementType, String mapKey, Map<Object, Object> map) {
+               Element mapElement = doc.createElement(elementType);
+               mapElement.setAttribute(KEY, mapKey);
+               for (Map.Entry<Object, Object> entry : map.entrySet()) {
+                       String key = entry.getKey().toString();
+                       String value = entry.getValue() != null ? entry.getValue().toString() : null;
+                       Element element = doc.createElement(MAP_ENTRY);
+                       element.setAttribute(KEY, key);
+                       element.setAttribute(VALUE, value);
+                       mapElement.appendChild(element);
+               }
+               return mapElement;
+       }
+
+       /**
+        * Initializes the mapping of attributes from the XML file
+        * 
+        * @param root
+        *            the root node from the XML document
+        * @throws CoreException
+        */
+       static public void initializeFromXML(Element root, Map<String, Object> properties) throws CoreException {
+               if (root.getNodeName().equalsIgnoreCase(PROPERTIES)) {
+                       NodeList list = root.getChildNodes();
+                       Node node = null;
+                       Element element = null;
+                       String nodeName = null;
+                       for (int i = 0; i < list.getLength(); ++i) {
+                               node = list.item(i);
+                               short nodeType = node.getNodeType();
+                               if (nodeType == Node.ELEMENT_NODE) {
+                                       element = (Element) node;
+                                       nodeName = element.getNodeName();
+                                       try {
+                                               if (nodeName.equalsIgnoreCase(STRING_ATTRIBUTE)) {
+                                                       setStringAttribute(element, properties);
+                                               } else if (nodeName.equalsIgnoreCase(INT_ATTRIBUTE)) {
+                                                       setIntegerAttribute(element, properties);
+                                               } else if (nodeName.equalsIgnoreCase(LONG_ATTRIBUTE)) {
+                                                       setLongAttribute(element, properties);
+                                               } else if (nodeName.equalsIgnoreCase(BIG_INTEGER_ATTRIBUTE)) {
+                                                       setBigIntegerAttribute(element, properties);
+                                               } else if (nodeName.equalsIgnoreCase(BOOLEAN_ATTRIBUTE)) {
+                                                       setBooleanAttribute(element, properties);
+                                               } else if (nodeName.equalsIgnoreCase(LIST_ATTRIBUTE)) {
+                                                       setListAttribute(element, properties);
+                                               } else if (nodeName.equalsIgnoreCase(MAP_ATTRIBUTE)) {
+                                                       setMapAttribute(element, properties);
+                                               } else if (nodeName.equalsIgnoreCase(SET_ATTRIBUTE)) {
+                                                       setSetAttribute(element, properties);
+                                               } else if (nodeName.equalsIgnoreCase(SERIALIZED_ATTRIBUTE)) {
+                                                       setSerializedAttribute(element, properties);
+                                               } else {
+                                                       EDCDebugger.getMessageLogger().logError("Unsupported element: " + nodeName, null);
+                                               }
+                                       } catch (Exception e) {
+                                               // Some integers are longs and so will fail when adding 
+                                               // their properties to the launch configuration. LaunchConfigurationInfo 
+                                               // does not support any number but Integer (no BigInteger or Long)
+                                               // See org.eclipse.debug.internal.core.LaunchConfigurationInfo#getAsXML().
+                                               EDCDebugger.getMessageLogger().logError("Skipping snapshot element.",  e);
+                                       } finally {
+                                               // continue on to the next element
+                                       }
+                               }
+                       }
+               }
+
+       }
+
+       /**
+        * Loads a <code>String</code> from the specified element into the local
+        * attribute mapping
+        * 
+        * @param element
+        *            the element to load from
+        * @throws CoreException
+        */
+       static protected void setStringAttribute(Element element, Map<String, Object> properties) throws CoreException {
+               properties.put(element.getAttribute(KEY), element.getAttribute(VALUE));
+       }
+
+       /**
+        * Loads an <code>Integer</code> from the specified element into the local
+        * attribute mapping
+        * 
+        * @param element
+        *            the element to load from
+        * @throws CoreException
+        */
+       static protected void setIntegerAttribute(Element element, Map<String, Object> properties) throws CoreException {
+               properties.put(element.getAttribute(KEY), new Integer(element.getAttribute(VALUE)));
+       }
+
+       /**
+        * Loads an <code>Long</code> from the specified element into the local
+        * attribute mapping
+        * 
+        * @param element
+        *            the element to load from
+        * @throws CoreException
+        */
+       static protected void setLongAttribute(Element element, Map<String, Object> properties) throws CoreException {
+               properties.put(element.getAttribute(KEY), new Long(element.getAttribute(VALUE)));
+       }
+
+       /**
+        * Loads a serialized <code>Object</code> from the specified element into the local
+        * attribute mapping
+        * 
+        * @param element
+        *            the element to load from
+        * @throws CoreException
+        * @throws IOException 
+        * @throws ClassNotFoundException 
+        * @throws DecoderException 
+        */
+       static protected void setSerializedAttribute(Element element, Map<String, Object> properties) throws CoreException, IOException, ClassNotFoundException, DecoderException {
+               properties.put(element.getAttribute(KEY), createSerializedObjectFromString(element.getFirstChild().getTextContent()));
+       }
+
+       /**
+        * Loads an <code>BigInteger</code> from the specified element into the local
+        * attribute mapping
+        * 
+        * @param element
+        *            the element to load from
+        * @throws CoreException
+        */
+       static protected void setBigIntegerAttribute(Element element, Map<String, Object> properties) throws CoreException {
+               properties.put(element.getAttribute(KEY), new BigInteger(element.getAttribute(VALUE)));
+       }
+       
+       /**
+        * Loads a <code>Boolean</code> from the specified element into the local
+        * attribute mapping
+        * 
+        * @param element
+        *            the element to load from
+        * @throws CoreException
+        */
+       static protected void setBooleanAttribute(Element element, Map<String, Object> properties) throws CoreException {
+               properties.put(element.getAttribute(KEY), Boolean.valueOf(element.getAttribute(VALUE)));
+       }
+
+       /**
+        * Reads a <code>List</code> attribute from the specified XML node and loads
+        * it into the mapping of attributes
+        * 
+        * @param element
+        *            the element to read the list attribute from
+        * @throws CoreException
+        *             if the element has an invalid format
+        */
+       static protected void setListAttribute(Element element, Map<String, Object> properties) throws CoreException {
+               String listKey = element.getAttribute(KEY);
+               NodeList nodeList = element.getChildNodes();
+               int entryCount = nodeList.getLength();
+               List<Object> list = new ArrayList<Object>(entryCount);
+               Node node = null;
+               Element selement = null;
+               for (int i = 0; i < entryCount; i++) {
+                       node = nodeList.item(i);
+                       if (node.getNodeType() == Node.ELEMENT_NODE) {
+                               selement = (Element) node;
+                               if (selement.getNodeName().equalsIgnoreCase(LIST_ENTRY)) {
+                                       String value = selement.getAttribute(VALUE);
+                                       list.add(value);
+                               }
+                       }
+               }
+               properties.put(listKey, list);
+       }
+
+       /**
+        * Reads a <code>Set</code> attribute from the specified XML node and loads
+        * it into the mapping of attributes
+        * 
+        * @param element
+        *            the element to read the set attribute from
+        * @throws CoreException
+        *             if the element has an invalid format
+        * 
+        * @since 3.3
+        */
+       static protected void setSetAttribute(Element element, Map<String, Object> properties) throws CoreException {
+               String setKey = element.getAttribute(KEY);
+               NodeList nodeList = element.getChildNodes();
+               int entryCount = nodeList.getLength();
+               Set<Object> set = new HashSet<Object>(entryCount);
+               Node node = null;
+               Element selement = null;
+               for (int i = 0; i < entryCount; i++) {
+                       node = nodeList.item(i);
+                       if (node.getNodeType() == Node.ELEMENT_NODE) {
+                               selement = (Element) node;
+                               if (selement.getNodeName().equalsIgnoreCase(SET_ENTRY)) {
+                                       set.add(element.getAttribute(VALUE));
+                               }
+                       }
+               }
+               properties.put(setKey, set);
+       }
+
+       /**
+        * Reads a <code>Map</code> attribute from the specified XML node and loads
+        * it into the mapping of attributes
+        * <p>
+        * NOTE: this creates a <String, String> map -- your ISnapshot#loadSnapshot() implementation
+        * must recover the right types.
+        * 
+        * @param element
+        *            the element to read the map attribute from
+        * @throws CoreException
+        *             if the element has an invalid format
+        */
+       static protected void setMapAttribute(Element element, Map<String, Object> properties) throws CoreException {
+               String mapKey = element.getAttribute(KEY);
+               NodeList nodeList = element.getChildNodes();
+               int entryCount = nodeList.getLength();
+               Map<Object, Object> map = new HashMap<Object, Object>(entryCount);
+               Node node = null;
+               Element selement = null;
+               for (int i = 0; i < entryCount; i++) {
+                       node = nodeList.item(i);
+                       if (node.getNodeType() == Node.ELEMENT_NODE) {
+                               selement = (Element) node;
+                               if (selement.getNodeName().equalsIgnoreCase(MAP_ENTRY)) {
+                                       map.put(selement.getAttribute(KEY), selement.getAttribute(VALUE));
+                               }
+                       }
+               }
+               properties.put(mapKey, map);
+       }
+       
+       static public IProject getSnapshotsProject() throws CoreException {
+               IProject snapshotsProject = null;
+               // See if the default project exists
+               String defaultProjectName = "Snapshots";
+               IWorkspace workspace = ResourcesPlugin.getWorkspace();
+               snapshotsProject = workspace.getRoot().getProject(
+                               defaultProjectName);
+               if (snapshotsProject.exists()) {
+                       if (!snapshotsProject.isOpen())
+                               snapshotsProject.open(new NullProgressMonitor());
+               } else {
+                       IProjectDescription description = workspace.newProjectDescription(defaultProjectName);
+                       description.setLocation(null);
+                       try {
+                               snapshotsProject.create(description, new NullProgressMonitor());
+                               snapshotsProject.open(new NullProgressMonitor());
+                       } catch (Exception e) {
+                               EDCDebugger.getMessageLogger().logError(null, e);
+                       }
+               }
+               return snapshotsProject;
+       }
+       
+       // TODO: This was taken from SnapshotLaunchDelegate. Need to refactor properly to make this common....
+       /**
+        * Load an album and launch the session without creating a Snapshot launch configuration. 
+        * Only creates the launch configuration type specified in the album data.
+        */
+       static public boolean launchAlbumSession(Album album){
+               IPath albumPath = album.getLocation();
+
+               try {
+                       if (!album.isLoaded()){
+                               album.loadAlbum(false);
+                       }
+               } catch (Exception e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+                       return false;
+               }
+               
+               ILaunchManager lm = DebugPlugin.getDefault().getLaunchManager();
+               ILaunchConfigurationType launchType = lm.getLaunchConfigurationType(album.getLaunchTypeID());
+               if (launchType == null) {
+                       // Can't launch TODO: Need error or exception
+                       return false;
+               }
+               ILaunchConfiguration proxyLaunchConfig = findExistingLaunchForAlbum(album);
+               if (proxyLaunchConfig == null) {
+                       String lcName = lm.generateLaunchConfigurationName(album.getDisplayName());
+                       ILaunchConfigurationWorkingCopy proxyLaunchConfigWC = null;
+                       try {
+                               proxyLaunchConfigWC = launchType.newInstance(null, lcName);
+                               proxyLaunchConfigWC.setAttributes(album.getLaunchProperties());
+                               proxyLaunchConfigWC.setAttribute(IEDCLaunchConfigurationConstants.ATTR_ALBUM_FILE, albumPath.toOSString());
+                               proxyLaunchConfig = proxyLaunchConfigWC.doSave();
+                               
+                       } catch (CoreException e) {
+                               EDCDebugger.getMessageLogger().logError(null, e);
+                       }
+
+               }
+               
+               if (proxyLaunchConfig != null)
+               {
+                       final ILaunchConfiguration finalProxyLC = proxyLaunchConfig;
+                       Job launchJob = new Job("Launching " + albumPath.toFile().getName()) {
+
+                               @Override
+                               protected IStatus run(IProgressMonitor monitor) {
+                                       try {
+                                               finalProxyLC.launch(ILaunchManager.DEBUG_MODE, new NullProgressMonitor(), false, true);
+                                       } catch (CoreException e) {
+                                               EDCDebugger.getMessageLogger().logError(null, e);
+                                               return Status.CANCEL_STATUS;
+                                       }
+                                       return Status.OK_STATUS;
+                               }
+                       };
+                       launchJob.schedule();
+               }
+               
+               return false;
+       }
+       
+       static public boolean isSnapshotLaunchConfig(ILaunchConfiguration launchConfiguration)
+       {
+               try {
+                       String albumFile = launchConfiguration.getAttribute(IEDCLaunchConfigurationConstants.ATTR_ALBUM_FILE, "");
+                       return albumFile.length() > 0;
+               } catch (CoreException e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+               return false;
+       }
+       
+       static public ILaunchConfiguration findExistingLaunchForAlbum(IAlbum album) {
+               ILaunchManager lm = DebugPlugin.getDefault().getLaunchManager();
+               ILaunchConfigurationType launchType = lm.getLaunchConfigurationType(album.getLaunchTypeID());
+               if (launchType == null){
+                       return null;
+               }
+               
+               try {
+                       ILaunchConfiguration[] configurations = lm.getLaunchConfigurations(launchType);
+                       for (ILaunchConfiguration configuration : configurations) {
+                               if (album.getLocation().toOSString().equals(configuration.getAttribute(
+                                               IEDCLaunchConfigurationConstants.ATTR_ALBUM_FILE, "")))
+                                       return configuration;
+                       }
+               } catch (CoreException e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+               return null;
+       }
+       
+       /**
+        * Taken from org.eclipse.cdt.debug.ui.breakpointactions#SoundAction
+        * @param soundFile
+        */
+       static public void playSoundFile(final File soundFile) {
+
+               class SoundPlayer extends Thread {
+
+                       public void run() {
+                               AudioInputStream soundStream;
+                               try {
+                                       soundStream = AudioSystem.getAudioInputStream(soundFile);
+                                       AudioFormat audioFormat = soundStream.getFormat();
+                                       DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
+                                       SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
+                                       byte[] soundBuffer = new byte[5000];
+                                       sourceDataLine.open(audioFormat);
+                                       sourceDataLine.start();
+                                       int dataCount = 0;
+
+                                       while ((dataCount = soundStream.read(soundBuffer, 0, soundBuffer.length)) != -1) {
+                                               if (dataCount > 0) {
+                                                       sourceDataLine.write(soundBuffer, 0, dataCount);
+                                               }
+                                       }
+                                       sourceDataLine.drain();
+                                       sourceDataLine.close();
+
+                               } 
+                               // Don't report any exceptions, some VMs may not play the sound
+                               catch (UnsupportedAudioFileException e) {
+                               } catch (IOException e) {
+                               } catch (IllegalArgumentException e) {
+                               } catch (LineUnavailableException e) {
+                               } finally {
+                                       
+                               }
+
+                       }
+
+               }
+               
+               if (soundFile.exists()) {
+                       new SoundPlayer().start();
+               }
+       }
+
+       private static String serializeObjectToString(Object value) throws IOException {
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+               ObjectOutputStream oos = new ObjectOutputStream(baos);
+               oos.writeObject(value);
+               return new String(new Hex().encode(baos.toByteArray()));
+       }
+
+       private static Object createSerializedObjectFromString(String objectValue) throws DecoderException, IOException, ClassNotFoundException {
+               final ClassLoader classLoader = EDCDebugger.getDefault().getClass().getClassLoader();
+               ByteArrayInputStream bais = new ByteArrayInputStream(Hex.decodeHex(objectValue.toCharArray()));
+               ObjectInputStream ois = new ObjectInputStream(bais) {
+
+                       @Override
+                       protected Class<?> resolveClass(ObjectStreamClass desc)
+                       throws IOException, ClassNotFoundException {
+                               String name = desc.getName();
+                               try {
+                                       return classLoader.loadClass(name);
+                               } catch (ClassNotFoundException e) {
+                                       return super.resolveClass(desc);
+                               }
+                       }};
+               return ois.readObject();
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ArrayBoundType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ArrayBoundType.java
new file mode 100644 (file)
index 0000000..b995e37
--- /dev/null
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+public class ArrayBoundType extends Type implements IArrayBoundType {
+
+       // bound of this array dimension. E.g., for "int a[7][8]", this would be
+       // either 7 or 8.
+       private final long bound;
+
+       // number of array elements associated with each index of this array
+       // dimension.
+       // E.g., for "int a[7][8]", "a[1]" comprises 8 elements, but "a[1][2]"
+       // comprises 1 element.
+       private long elements;
+
+       // array dimension ordinal. E.g., for "int a[7][8]", "[7]" is index 1 and
+       // "[8]" is index 0;
+       private long dimensionIndex = 0;
+
+       public ArrayBoundType(IScope scope, long arrayBound) {
+               super("", scope, 0, null); //$NON-NLS-1$
+
+               if (arrayBound < 1) {
+                       this.bound = 0;
+                       this.elements = 0;
+               } else {
+                       this.bound = arrayBound;
+                       this.elements = 1;
+               }
+       }
+
+       public long getBoundCount() {
+               return this.bound;
+       }
+
+       public long getElementCount() {
+               return this.elements;
+       }
+
+       public long getDimensionIndex() {
+               return this.dimensionIndex;
+       }
+
+       public void multiplyElementCount(long multiply) {
+               this.elements *= multiply;
+       }
+
+       public void incDimensionIndex() {
+               this.dimensionIndex++;
+       }
+
+       @Override
+       public IType getType() {
+               return null;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ArrayType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ArrayType.java
new file mode 100644 (file)
index 0000000..1586c39
--- /dev/null
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+
+public class ArrayType extends MayBeQualifiedType implements IArrayType {
+
+       protected ArrayList<IArrayBoundType> bounds = new ArrayList<IArrayBoundType>();
+
+       public ArrayType(String name, IScope scope, int byteSize, Map<Object, Object> properties) {
+               super(name, scope, byteSize, properties);
+       }
+
+       public int getBoundsCount() {
+               return bounds.size();
+       }
+
+       public void addBound(IArrayBoundType bound) {
+               // existing array dimensions now represent bound.getBoundCount() times
+               // as many array elements,
+               // and have a higher dimensional position
+               for (IArrayBoundType existingBound : this.bounds) {
+                       existingBound.multiplyElementCount(bound.getBoundCount());
+                       existingBound.incDimensionIndex();
+               }
+               bounds.add(bound);
+               byteSize = 0;   // recalculate
+       }
+
+       public IArrayBoundType[] getBounds() {
+               IArrayBoundType[] boundsArray = new IArrayBoundType[bounds.size()];
+               for (int i = 0; i < bounds.size(); i++) {
+                       boundsArray[i] = bounds.get(i);
+               }
+               return boundsArray;
+       }
+
+       // get the Nth bound. E.g., for "a[X][Y]", getBound(0) returns info for
+       // "[X]"
+       public IArrayBoundType getBound(int index) {
+               if (index >= 0 && index < bounds.size())
+                       return bounds.get(index);
+
+               return null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Type#getByteSize()
+        */
+       @Override
+       public int getByteSize() {
+               if (byteSize == 0) {
+                       if (bounds.size() > 0) {
+                               updateByteSizeFromSubType();
+                               IType subtype = TypeUtils.getStrippedType(getType());
+                               if (subtype instanceof IArrayType) {
+                                       for (IArrayBoundType bound : ((IArrayType)subtype).getBounds())
+                                               byteSize *= bound.getBoundCount();
+                               }
+                       }
+               }
+               return byteSize;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CPPBasicType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CPPBasicType.java
new file mode 100644 (file)
index 0000000..4d0b445
--- /dev/null
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+public class CPPBasicType extends MayBeQualifiedType implements ICPPBasicType {
+
+       private final int baseType;
+       private final int qualifierBits;
+
+       public CPPBasicType(String name, IScope scope, int baseType, int qualifierBits, int byteSize,
+                       Map<Object, Object> properties) {
+               super(name, scope, byteSize, properties);
+               this.baseType = baseType;
+               this.qualifierBits = qualifierBits;
+       }
+
+       public CPPBasicType(String name, int baseType, int qualifierBits, int byteSize) {
+               super(name, null, byteSize, null);
+               this.baseType = baseType;
+               this.qualifierBits = qualifierBits;
+       }
+
+       
+       /**
+        * WARNING: this only works for CPPBasicType itself.  No other types in
+        * the hierarchy implement this correctly.
+        * (non-Javadoc)
+        * @see java.lang.Object#hashCode()
+        */
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 12345;             // super.hashCode();
+               result = prime * result + baseType;
+               result = prime * result + qualifierBits;
+               return result;
+       }
+
+       /**
+        * WARNING: this only works for CPPBasicType itself.  No other types in
+        * the hierarchy implement this correctly.
+        * (non-Javadoc)
+        * @see java.lang.Object#equals(java.lang.Object)
+        */
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               //if (!super.equals(obj))
+               //      return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               // do not test name, since it's essentially random
+               CPPBasicType other = (CPPBasicType) obj;
+               if (baseType != other.baseType)
+                       return false;
+               if (qualifierBits != other.qualifierBits)
+                       return false;
+               return true;
+       }
+
+       public int getQualifierBits() {
+               return this.qualifierBits;
+       }
+
+       public int getBaseType() {
+               return this.baseType;
+       }
+
+       public boolean isLong() {
+               return (this.qualifierBits & ICPPBasicType.IS_LONG) != 0;
+       }
+       
+       public boolean isLongLong() {
+               return (this.qualifierBits & ICPPBasicType.IS_LONG_LONG) != 0;
+       }
+
+       public boolean isShort() {
+               return (this.qualifierBits & ICPPBasicType.IS_SHORT) != 0;
+       }
+
+       public boolean isSigned() {
+               return (this.qualifierBits & ICPPBasicType.IS_SIGNED) != 0;
+       }
+
+       public boolean isUnsigned() {
+               return (this.qualifierBits & ICPPBasicType.IS_UNSIGNED) != 0;
+       }
+       
+       public boolean isComplex() {
+               return (this.qualifierBits & ICPPBasicType.IS_COMPLEX) != 0;
+       }
+
+       @Override
+       public IType getType() {
+               return null;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ClassType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ClassType.java
new file mode 100644 (file)
index 0000000..b852be1
--- /dev/null
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class ClassType extends CompositeType {
+
+       public ClassType(String name, IScope scope, int byteSize, Map<Object, Object> properties) {
+               super(name, scope, ICompositeType.k_class, byteSize, properties, "class"); //$NON-NLS-1$
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CompileUnitScope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CompileUnitScope.java
new file mode 100644 (file)
index 0000000..6c088ce
--- /dev/null
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.symbols.ICompileUnitScope;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.debug.edc.symbols.IModuleScope;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.core.runtime.IPath;
+
+public abstract class CompileUnitScope extends Scope implements ICompileUnitScope {
+
+       protected IPath filePath;
+
+       protected Collection<ILineEntry> lineEntries;
+
+       public CompileUnitScope(IPath filePath, IModuleScope parent, IAddress lowAddress, IAddress highAddress) {
+               super(filePath != null ? filePath.lastSegment() : "", lowAddress, highAddress, parent); //$NON-NLS-1$
+
+               this.filePath = filePath;
+       }
+
+       public IPath getFilePath() {
+               return filePath;
+       }
+
+       public IFunctionScope getFunctionAtAddress(IAddress linkAddress) {
+               IScope scope = getScopeAtAddress(linkAddress);
+               while (scope != null && !(scope instanceof IFunctionScope)) {
+                       scope = scope.getParent();
+               }
+
+               return (IFunctionScope) scope;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.ICompileUnitScope#getFunctions()
+        */
+       public Collection<IFunctionScope> getFunctions() {
+               List<IFunctionScope> functions = new ArrayList<IFunctionScope>(children.size());
+               for (IScope scope : getChildren()) {
+                       if (scope instanceof IFunctionScope)
+                               functions.add((IFunctionScope) scope);
+               }
+               return Collections.unmodifiableCollection(functions);
+       }
+
+
+       /**
+        * Parse the line table data - to be implemented by debug format specific
+        * sub classes.
+        * 
+        * @return the list of line table entries (may be empty)
+        */
+       protected abstract Collection<ILineEntry> parseLineTable();
+
+
+       public Collection<ILineEntry> getLineEntries() {
+               if (lineEntries == null) {
+                       lineEntries = parseLineTable();
+               }
+               return Collections.unmodifiableCollection(lineEntries);
+       }
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append("CompileUnitScope ["); //$NON-NLS-1$
+               builder.append("lowAddress="); //$NON-NLS-1$
+               builder.append(lowAddress);
+               builder.append(", highAddress="); //$NON-NLS-1$
+               builder.append(highAddress);
+               builder.append(", "); //$NON-NLS-1$
+               if (filePath != null) {
+                       builder.append("path="); //$NON-NLS-1$
+                       builder.append(filePath.toOSString());
+                       builder.append(", "); //$NON-NLS-1$
+               }
+               builder.append("]"); //$NON-NLS-1$
+               return builder.toString();
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CompositeType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CompositeType.java
new file mode 100644 (file)
index 0000000..e21f369
--- /dev/null
@@ -0,0 +1,399 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class CompositeType extends MayBeQualifiedType implements ICompositeType {
+       
+       // kind of composite (class, struct, union)
+       private final int key;
+       
+       // composite name without "class ", "struct " or "union " prefix
+       private String baseName;
+
+       // fields in the composite 
+       protected ArrayList<IField> fields = new ArrayList<IField>();
+       
+       // classes inherited from
+       protected ArrayList<IInheritance> inheritances = null;
+       
+       // template parameters
+       protected ArrayList<ITemplateParam> templateParams = null;
+       boolean nameIncludesTemplateParams;
+
+       /**
+        * fields of anonymous union types, with unknown offsets
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfInfoReader#processUnionType()
+        */
+       protected ArrayList<IField> unknownOffsetFields = null;
+
+       protected static class OffsetAndLength {
+               public long offset;
+               public long length;
+       }
+
+       public CompositeType(String name, IScope scope, int key, int byteSize, Map<Object, Object> properties, String prefix) {
+               super(name, scope, byteSize, properties);
+               this.baseName = name;
+               this.name = prefix + " " + name; //$NON-NLS-1$
+               this.key = key;
+               nameIncludesTemplateParams = name.contains("<"); //$NON-NLS-1$
+       }
+
+       public int getKey() {
+               return this.key;
+       }
+
+       public int fieldCount() {
+               if (unknownOffsetFields != null)
+                       setAnonymousUnionOffsets();
+               return fields.size();
+       }
+
+       public void addField(IField field) {
+               if (field.getFieldOffset() < 0) {
+                       if (unknownOffsetFields == null)
+                               unknownOffsetFields = new ArrayList<IField>();
+                       unknownOffsetFields.add(field);
+               } else
+                       fields.add(field);
+       }
+
+       public IField[] getFields() {
+               if (unknownOffsetFields != null)
+                       setAnonymousUnionOffsets();
+               ArrayList<IField> fieldList = new ArrayList<IField>(fields);
+               
+               return fieldList.toArray(new IField[fields.size()]);
+       }
+
+       public void addTemplateParam(ITemplateParam templateParam) {
+               if (templateParams == null) {
+                       templateParams = new ArrayList<ITemplateParam>(2);
+               }
+               templateParams.add(templateParam);
+       }
+
+       public ITemplateParam[] getTemplateParams() {
+               if (templateParams == null)
+                       return new ITemplateParam[0];
+
+               ArrayList<ITemplateParam> templateParamList = new ArrayList<ITemplateParam>(templateParams);
+
+               return templateParamList.toArray(new ITemplateParam[templateParams.size()]);
+       }
+
+       @Override
+       public String getName() {
+               if (templateParams != null && !nameIncludesTemplateParams)
+                       addTemplateStringToNames();
+               return name;
+       }
+       
+       public String getBaseName() {
+               if (templateParams != null && !nameIncludesTemplateParams)
+                       addTemplateStringToNames();
+               return baseName;
+       }
+
+       // add template parameters (e.g. "<Long>") to name and base name
+       private void addTemplateStringToNames() {
+               nameIncludesTemplateParams = true;
+               String templateName = "<"; //$NON-NLS-1$
+               for (int i = 0; i < templateParams.size(); i++) {
+                       templateName += templateParams.get(i).getName();
+                       if (i + 1 < templateParams.size())
+                               templateName += ","; //$NON-NLS-1$
+               }
+               templateName += ">"; //$NON-NLS-1$
+               // remove composite type names (e.g., "class")
+               templateName = templateName.replaceAll("class ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+               templateName = templateName.replaceAll("struct ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+               templateName = templateName.replaceAll("union ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+               name += templateName;
+               baseName += templateName;
+       }
+
+       public int inheritanceCount() {
+               return inheritances == null ? 0 : inheritances.size();
+       }
+
+       public void addInheritance(IInheritance inheritance) {
+               if (inheritances == null)
+                       inheritances = new ArrayList<IInheritance>();
+               inheritances.add(inheritance);
+       }
+
+       public IInheritance[] getInheritances() {
+               if (inheritances == null)
+                       return new IInheritance[0];
+
+               return inheritances.toArray(new IInheritance[inheritances.size()]);
+       }       
+
+       public IField[] findFields(String name) {
+               // For a qualified name containing "::", save the qualifiers to match against
+               String baseFieldName = name;
+               ArrayList<String> nameQualifiers = new ArrayList<String>();
+               
+               if (name.contains("::")) { //$NON-NLS-1$
+                       StringTokenizer st = new StringTokenizer(name, "::", false); //$NON-NLS-1$
+                       while (st.hasMoreTokens()) {
+                               baseFieldName = st.nextToken();
+                               nameQualifiers.add(baseFieldName);
+                       }
+                       
+                       // last token in the array is the base field name
+                       nameQualifiers.remove(nameQualifiers.size() - 1);
+
+                       // if the first nameQualifier is the composite's name, remove it
+                       // E.g., if we're in class foo, change "foo::x" to "x".
+                       if ((nameQualifiers.size() >= 0) && nameQualifiers.get(0).equals(this.baseName))
+                               nameQualifiers.remove(0);
+               }
+
+               // try for a fast exit: match against the non-inherited fields and names of
+               // composites we're inheriting from
+               if (nameQualifiers.size() == 0) {
+                       if (unknownOffsetFields != null)
+                               setAnonymousUnionOffsets();
+                       for (int i = 0; i < fields.size(); i++) {
+                               if (((FieldType) fields.get(i)).getName().equals(baseFieldName)) {
+                                       IField[] foundFields = new IField[1];
+                                       foundFields[0] = fields.get(i);
+                                       return foundFields;
+                               }
+                       }
+                       
+                       if (inheritances != null) {
+                               for (IInheritance inheritance : inheritances) {
+                                       String inheritanceName = inheritance.getName();
+                                       // for templates, remove composite type names (e.g., "class")
+                                       if (inheritanceName.indexOf('<') != -1) {
+                                               inheritanceName = inheritanceName.replaceAll("class ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                                               inheritanceName = inheritanceName.replaceAll("struct ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                                               inheritanceName = inheritanceName.replaceAll("union ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                                       }
+
+                                       if (inheritanceName.equals(baseFieldName)) {
+                                               IField[] foundFields = new IField[1];
+                                               
+                                               // treat the inherited type as a field
+                                               FieldType newField = new FieldType(inheritanceName, scope, this,
+                                                               inheritance.getFieldsOffset(), 0 /* bitSize */, 0 /* bitOffset */,
+                                                               inheritance.getType().getByteSize(), inheritance.getAccessibility(),
+                                                               inheritance.getProperties());
+                                               newField.setType(inheritance.getType());
+
+                                               foundFields[0] = newField;
+                                               return foundFields;
+                                       }
+                               }
+                       }
+               }
+               
+               // check the inherited types
+               if (inheritances == null)
+                       return null;
+
+               ArrayList<IField> matches = new ArrayList<IField>();
+               
+               for (IInheritance inheritance : inheritances) {
+                       if (inheritance.getType() instanceof ICompositeType) {
+                               ICompositeType inheritComposite = (ICompositeType)inheritance.getType();
+                               matches = findInheritedByName(baseFieldName, inheritComposite, inheritComposite.getBaseName(), inheritance.getFieldsOffset(), matches);
+                       }
+               }
+               
+               // eliminate partial matches
+               matches = pruneMatches(nameQualifiers, matches);
+
+               // create the list of all inherited fields
+               IField[] foundFields = null;
+               
+               // gather the names and offsets of the inherited fields
+               if (matches.size() > 0) {
+                       foundFields = new IField[matches.size()];
+                       for (int i = 0; i < matches.size(); i++) {
+                               foundFields[i] = matches.get(i);
+                       }
+               }
+               
+               return foundFields;
+       }
+       
+       /**
+        * From a list of fields whose name matches the one we're looking for, remove those
+        * whose "::" qualifiers do not match. E.g., "foo::x" would match "bar::foo::x", but
+        * it would not match "bar::x" - so "bar::x" would be pruned.
+        *  
+        * @param nameQualifiers qualifiers of the field we're matching against
+        * @param matches list of fields whose base name matches, but whose qualifiers may not match
+        * @return list of fields whose base name and qualifiers match the field we're looking for
+        */
+       private ArrayList<IField> pruneMatches(ArrayList<String> nameQualifiers, ArrayList<IField> matches) {
+               if (nameQualifiers.size() == 0)
+                       return matches;
+
+               for (int i = 0; i < matches.size(); i++) {
+                       ArrayList<String> matchQualifiers = new ArrayList<String>();
+                       String matchName = matches.get(i).getName();
+                       
+                       if (!matchName.contains("::")) //$NON-NLS-1$
+                               continue;
+                       
+                       // tokenize the match's name
+                       StringTokenizer st = new StringTokenizer(matchName, "::", false); //$NON-NLS-1$
+                       while (st.hasMoreTokens()) {
+                               matchQualifiers.add(st.nextToken());
+                       }
+                       
+                       // last token in the array is the base name, which we already know matches
+                       matchQualifiers.remove(matchQualifiers.size() - 1);
+
+                       for (int nameIndex = 0, matchIndex = 0;
+                                       nameIndex < nameQualifiers.size() && matchIndex < matchQualifiers.size();
+                                       nameIndex++) {
+                               // match against each name qualifier, in order
+                               boolean found = false;
+                               while (!found && matchIndex < matchQualifiers.size()) {
+                                       found = nameQualifiers.get(nameIndex).equals(matchQualifiers.get(matchIndex));
+                                       matchIndex++;
+                               }
+                               
+                               // if did not find a qualifier, remove the match
+                               if (!found) {
+                                       matches.remove(i);
+                                       break;
+                               }
+                       }
+               }
+               
+               return matches;
+       }
+
+       /**
+        * Find all inherited fields whose base name, ignoring "::" qualifiers, match the search name
+        * 
+        * @param name name to match
+        * @param composite composite type whose fields or inherited fields may match 
+        * @param prefix string of "::" qualifiers so far
+        * @param offset byte offset of the composite from the composite that inherits from it
+        * @param matches list of matches found so far
+        * @return list of matches 
+        */
+       private ArrayList<IField> findInheritedByName(String name, ICompositeType composite, String prefix, long offset, ArrayList<IField> matches) {
+               IField[] fields = composite.getFields();
+               if (fields != null) {
+                       for (IField field : fields) {
+                               String fieldName = field.getName();
+                               
+                               if (fieldName.equals(name)) {
+                                       // create a field with the prefixed name
+                                       FieldType newField = new FieldType(prefix + "::" + field.getName(), scope, //$NON-NLS-1$
+                                                       composite, offset + field.getFieldOffset(), 0 /* bitSize */, 0 /* bitOffset */,
+                                                       field.getType().getByteSize(), field.getAccessibility(),
+                                                       field.getProperties());
+                                       newField.setType(field.getType());
+                                       matches.add(newField);
+                                       break;
+                               }
+                       }
+               }
+
+               IInheritance[] compositeInheritances = composite.getInheritances(); 
+               if (compositeInheritances.length == 0)
+                       return matches;
+
+               for (IInheritance inheritance : compositeInheritances) {
+                       if (inheritance.getName().equals(name)) {
+                               // treat the inherited type as a field
+                               FieldType newField = new FieldType(inheritance.getName(), scope, this,
+                                               offset + inheritance.getFieldsOffset(), 0 /* bitSize */, 0 /* bitOffset */,
+                                               inheritance.getType().getByteSize(), inheritance.getAccessibility(),
+                                               inheritance.getProperties());
+                               newField.setType(inheritance.getType());
+                       }
+
+                       if (inheritance.getType() instanceof ICompositeType) {
+                               ICompositeType inheritComposite = (ICompositeType)inheritance.getType();
+                               matches = findInheritedByName(name, inheritComposite, prefix + "::" + inheritComposite.getBaseName(), //$NON-NLS-1$
+                                                               offset + inheritance.getFieldsOffset(), matches);
+                       }
+               }
+
+               return matches;
+       }
+
+       /**
+        * Fields with unknown offsets may be between other members or at the end
+        */
+       private void setAnonymousUnionOffsets() {
+               OffsetAndLength[] offsetSizes = new OffsetAndLength[fields.size() + inheritanceCount()];
+               int count = 0;
+               if (fields.size() > 0) {
+                       for ( ; count < fields.size(); count++) {
+                               offsetSizes[count] = new OffsetAndLength();
+                               offsetSizes[count].offset = fields.get(count).getFieldOffset();
+                               offsetSizes[count].length = fields.get(count).getByteSize();
+                       }
+               }
+               
+               if (inheritances != null) {
+                       for (IInheritance inheritance : inheritances) {
+                               offsetSizes[count] = new OffsetAndLength();
+                               offsetSizes[count].offset = inheritance.getFieldsOffset();
+                               offsetSizes[count].length = inheritance.getType().getByteSize();
+                               count++;
+                       }
+               }
+
+               // sort by offsets
+               if (offsetSizes.length > 1) {
+                       boolean sorted;
+                       int passCnt = 1;
+                       do {
+                               sorted = true;
+                               for (int i = 0; i < offsetSizes.length - passCnt; i++) {
+                                       if (offsetSizes[i].offset > offsetSizes[i + 1].offset) {
+                                               OffsetAndLength temp = offsetSizes[i];
+                                               offsetSizes[i] = offsetSizes[i + 1];
+                                               offsetSizes[i + 1] = temp;
+                                               sorted = false;
+                                       }
+                               }
+                               passCnt++;
+                       } while (!sorted && passCnt < offsetSizes.length);
+               }
+
+               // find the offset for each anonymous union's data - between other members or at the end
+               int i = 0;
+               long fieldOffset = 0;
+               for (IField unknownOffsetField : unknownOffsetFields) {
+                       for ( ; i < offsetSizes.length; i++) {
+                               if (fieldOffset < offsetSizes[i].offset)
+                                       break;
+                               fieldOffset = offsetSizes[i].offset + offsetSizes[i].length;
+                       }
+                       unknownOffsetField.setFieldOffset(fieldOffset);
+                       if (i >= offsetSizes.length)
+                               fieldOffset += unknownOffsetField.getByteSize();
+                       fields.add(unknownOffsetField);
+               }
+
+               unknownOffsetFields = null;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ConstType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ConstType.java
new file mode 100644 (file)
index 0000000..6ad9b1e
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+/**
+ * Pseudo-type that represents the const qualifier
+ */
+public class ConstType extends Type implements IConstType {
+
+       public ConstType(IScope scope, Map<Object, Object> properties) {
+               super("const", scope, 0, properties); //$NON-NLS-1$
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Type#getByteSize()
+        */
+       @Override
+       public int getByteSize() {
+               return updateByteSizeFromSubType();
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/EDCSourceFilesProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/EDCSourceFilesProvider.java
new file mode 100644 (file)
index 0000000..8e8e38c
--- /dev/null
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.core.executables.Executable;
+import org.eclipse.cdt.debug.core.executables.ISourceFilesProvider;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Symbols;
+import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class EDCSourceFilesProvider implements ISourceFilesProvider {
+
+       public String[] getSourceFiles(Executable executable, IProgressMonitor monitor) {
+
+               try {
+                       // get cached reader
+                       IEDCSymbolReader reader = Symbols.getSymbolReader(executable.getPath());
+                       if (reader != null) {
+                               // note: don't dispose reader here
+                               return reader.getSourceFiles(monitor);
+                       }
+               } catch (Exception e) {
+               }
+
+               return new String[0];
+       }
+
+       public int getPriority(Executable executable) {
+               // this forces us to be called before the DE source files provider
+               return ISourceFilesProvider.HIGH_PRIORITY + 10;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Enumeration.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Enumeration.java
new file mode 100644 (file)
index 0000000..95f694e
--- /dev/null
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IEnumerator;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class Enumeration extends MayBeQualifiedType implements IEnumeration {
+
+       ArrayList<IEnumerator> enumerators = new ArrayList<IEnumerator>();
+       HashMap<Long, IEnumerator> enumeratorsByConstant = new HashMap<Long, IEnumerator>();
+
+       public Enumeration(String name, IScope scope, int byteSize, Map<Object, Object> properties) {
+               super(name, scope, byteSize, properties);
+               name = "enum"; //$NON-NLS-1$
+       }
+       
+       public int enumeratorCount() {
+               return enumerators.size();
+       }
+
+       public void addEnumerator(IEnumerator enumerator) {
+               enumerators.add(enumerator);
+               enumeratorsByConstant.put(enumerator.getValue(), enumerator);
+       }
+
+       public IEnumerator getEnumeratorByName(String name) {
+               for (int i = 0; i < enumerators.size(); i++) {
+                       if (enumerators.get(i).getName().equals(name))
+                               return enumerators.get(i);
+               }
+               return null;
+       }
+
+       public IEnumerator getEnumeratorByValue(long value) {
+               return this.enumeratorsByConstant.get(new Long(value));
+       }
+
+       public IEnumerator[] getEnumerators() {
+               IEnumerator[] enumeratorArray = new IEnumerator[enumerators.size()];
+               for (int i = 0; i < enumerators.size(); i++) {
+                       enumeratorArray[i] = enumerators.get(i);
+               }
+               return enumeratorArray;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Enumerator.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Enumerator.java
new file mode 100644 (file)
index 0000000..51e3b2d
--- /dev/null
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IEnumerator;
+
+public class Enumerator implements IEnumerator {
+
+       protected final String name;
+       protected final Long value;
+
+       public Enumerator(String name, long value) {
+               this.name = name;
+               this.value = value;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public long getValue() {
+               return value;
+       }
+
+       @Override
+       public String toString() {
+               return "name = " + name + ", value = " + value; //$NON-NLS-1$ //$NON-NLS-2$
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/FieldType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/FieldType.java
new file mode 100644 (file)
index 0000000..3d5b7bf
--- /dev/null
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class FieldType extends Type implements IField {
+
+       private final ICompositeType compositeType;
+       private long fieldOffset;
+       private final int bitSize;
+       private final int bitOffset;
+       private final int accessibility;
+
+       public FieldType(String name, IScope scope, ICompositeType compositeType, long fieldOffset, int bitSize,
+                       int bitOffset, int byteSize, int accessibility, Map<Object, Object> properties) {
+               super(name, scope, byteSize, properties);
+
+               this.compositeType = compositeType;
+               this.fieldOffset = fieldOffset;
+               this.bitSize = bitSize;
+               this.bitOffset = bitOffset;
+               this.accessibility = accessibility;
+       }
+
+       public long getFieldOffset() {
+               return this.fieldOffset;
+       }
+
+       public int getBitSize() {
+               return this.bitSize;
+       }
+
+       public int getBitOffset() {
+               return this.bitOffset;
+       }
+       
+       public int getAccessibility() {
+               return this.accessibility;
+       }
+
+       public ICompositeType getCompositeTypeOwner() {
+               return this.compositeType;
+       }
+
+       public void setFieldOffset(long offset) {
+               this.fieldOffset = offset;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Type#getByteSize()
+        */
+       @Override
+       public int getByteSize() {
+               return updateByteSizeFromSubType();
+       }
+
+       @Override
+       public String toString() {
+               return name + " offset = " + fieldOffset //$NON-NLS-1$
+                               + ", byteSize = " +     getByteSize() //$NON-NLS-1$
+                               + (bitOffset != 0 ? ", bitOffset = " + bitOffset : "") //$NON-NLS-1$ //$NON-NLS-2$
+                               + (bitSize != 0 ? ", bitSize = " + bitSize : "") //$NON-NLS-1$ //$NON-NLS-2$
+                               + ", accessibility = " + //$NON-NLS-1$
+                                       (accessibility == ICompositeType.ACCESS_PRIVATE ?
+                                                       "private" //$NON-NLS-1$
+                                       : (accessibility == ICompositeType.ACCESS_PROTECTED ?
+                                                       "protected" //$NON-NLS-1$
+                                                       : "public")); //$NON-NLS-1$
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/FileLineEntryProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/FileLineEntryProvider.java
new file mode 100644 (file)
index 0000000..324834f
--- /dev/null
@@ -0,0 +1,737 @@
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.PathUtils;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.EDCLineAddresses;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfCompileUnit;
+import org.eclipse.cdt.debug.edc.symbols.ICompileUnitScope;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Manage line table entries of one source file (.c/.cpp/header) in one compile
+ * unit. <br>
+ * This is an internal class used by {@linkplain ModuleLineEntryProvider}.
+ */
+class FileLineEntryProvider implements ILineEntryProvider {
+
+       private List<ILineEntry> lineEntries = new ArrayList<ILineEntry>();
+       private List<ILineEntry> cuEntries   = null;
+
+       /**
+        * Line entries sorted by line number. Line table entries mapped to the same
+        * source line are put together in one entry in this map.
+        * 
+        * Just use TreeMap so line number keys are sorted in ascending order.
+        */
+       private TreeMap<Integer, List<ILineEntry>> lineEntriesByLine = new TreeMap<Integer, List<ILineEntry>>();
+       
+       private TreeMap<IAddress, ILineEntry> lineEntriesByAddress = new TreeMap<IAddress, ILineEntry>();
+
+       private IPath filePath;
+
+       private final ICompileUnitScope compileUnitScope;
+
+       private boolean sorted;
+
+       public FileLineEntryProvider(ICompileUnitScope compileUnitScope, IPath path) {
+               this.compileUnitScope = compileUnitScope;
+               this.filePath = path;
+               this.sorted = true;
+       }
+
+       protected void setCULineEntries(Collection<ILineEntry> entries) {
+               cuEntries = new ArrayList<ILineEntry>(entries);                 
+       }
+
+       protected List<ILineEntry> getCULineEntries() {
+               if (cuEntries == null)
+                       setCULineEntries(compileUnitScope.getLineEntries());
+               return cuEntries;
+       }
+
+       public ICompileUnitScope getCU() {
+               return compileUnitScope;
+       }
+
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               // note: peeking into lowAddress to avoid dynamically parsing stuff while viewing #toString() 
+               return filePath + " at " + ((CompileUnitScope)compileUnitScope).lowAddress  + ": " + lineEntries.size() + " entries"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+       }
+
+       /**
+        * @param entry
+        */
+       public void addLineEntry(ILineEntry entry) {
+               //System.out.println("Adding " + entry + " for " + compileUnitScope);
+               lineEntries.add(entry);
+
+               List<ILineEntry> currentMappings = lineEntriesByLine.get(entry.getLineNumber());
+               if (currentMappings == null) {
+                       currentMappings = new ArrayList<ILineEntry>();
+                       lineEntriesByLine.put(entry.getLineNumber(), currentMappings);          
+               }
+               currentMappings.add(entry);
+
+               ILineEntry currentByAddress = lineEntriesByAddress.get(entry.getLowAddress());
+               
+               if (   currentByAddress == null
+                       || entry.getHighAddress().compareTo(currentByAddress.getHighAddress()) > 0) {
+                       lineEntriesByAddress.put(entry.getLowAddress(), entry);
+               }
+
+               sorted = false;
+       }
+
+       public ILineEntry getLineEntryAtAddress(IAddress linkAddress) {
+               // NOTE: lineEntries can, and does, have multiple entries with the same low address
+               if (!sorted) {
+                       // sort by start address for faster lookup by address
+                       Collections.sort(lineEntries);
+                       sorted = true;
+               }
+               int insertion = getLineEntryInsertionForAddress(linkAddress, lineEntries);
+               if (-1 != insertion)
+                       return lineEntries.get(insertion);
+               return null;
+       }
+
+       private int getLineEntryInsertionForAddress(IAddress linkAddress,
+                       final List<? extends ILineEntry> entriesToSearch) {
+
+               int insertion = Collections.binarySearch(entriesToSearch, linkAddress);
+               ILineEntry newEntry;
+               int newInsertion;
+
+               if (insertion >= 0) {
+                       // line entry's low address exactly matches linkAddress, but if the line
+                       // entry has an empty address range, see if a previous or subsequent
+                       // line entry with the same start address has a nonempty range
+                       ILineEntry entry = entriesToSearch.get(insertion);
+                       
+                       if (entry.getHighAddress().compareTo(entry.getLowAddress()) != 0)
+                               return insertion;
+
+                       if (insertion > 0) {
+                               newInsertion = insertion - 1;
+                               newEntry = entriesToSearch.get(newInsertion);
+                               while (newEntry.getLowAddress().compareTo(entry.getLowAddress()) == 0) {
+                                       if (newEntry.getHighAddress().compareTo(newEntry.getLowAddress()) != 0) {
+                                               return newInsertion;
+                                       }
+                                       if (--newInsertion < 0)
+                                               break;
+                                       newEntry = entriesToSearch.get(newInsertion);
+                               }
+                       }
+
+                       if (insertion < entriesToSearch.size() - 1) {
+                               newInsertion = insertion + 1;
+                               newEntry = entriesToSearch.get(newInsertion);
+                               while (newEntry.getLowAddress().compareTo(entry.getLowAddress()) == 0) {
+                                       if (newEntry.getHighAddress().compareTo(newEntry.getLowAddress()) != 0) {
+                                               return newInsertion;
+                                       }
+                                       if (++newInsertion == entriesToSearch.size())
+                                               break;
+                                       newEntry = lineEntries.get(newInsertion);
+                               }
+                       }
+                       
+                       return insertion;
+               }
+
+               if (insertion == -1) {
+                       return -1;
+               }
+
+               // after a failed binary search, link address is > low address of -insertion-2
+               // so see if a previous entry with the same low address has a nonempty range
+               // that includes linkAddress
+               insertion = -insertion - 2;
+
+               ILineEntry entry = entriesToSearch.get(insertion);
+
+               // low address of entry at insertion cannot match linkAddress
+               if (insertion > 0 && entry.getHighAddress().compareTo(entry.getLowAddress()) == 0) {
+                       newInsertion = insertion - 1;
+                       newEntry = entriesToSearch.get(newInsertion);
+                       while (newEntry.getLowAddress().compareTo(entry.getLowAddress()) == 0) {
+                               if (newEntry.getHighAddress().compareTo(newEntry.getLowAddress()) != 0) {
+                                       if (linkAddress.compareTo(newEntry.getHighAddress()) < 0)
+                                               return newInsertion;
+                               }
+                               if (--newInsertion < 0)
+                                       break;
+                               newEntry = entriesToSearch.get(newInsertion);
+                       }
+               }
+               
+               if (linkAddress.compareTo(entry.getHighAddress()) < 0)
+                       return insertion;
+
+               return -1;
+       }
+
+       public Collection<ILineEntry> getLineEntriesForLines(IPath path, int startLineNumber, int endLineNumber) {
+               // FIXME: ugly drive letter stuff
+               if (!filePath.setDevice(null).equals(path.setDevice(null)) )
+               {
+                       if (!PathUtils.isCaseSensitive() && filePath.toOSString().compareToIgnoreCase(path.toOSString()) != 0)
+                               return Collections.emptyList();                 
+               }
+
+               int lntSize = lineEntries.size();
+               // Note: this may not be the last line:
+               //        lineEntries.get(lntSize-1).getLineNumber();
+               // as I've seen line table like this for a source file
+               // (illustrated by line #s):
+               //     7, 8, 25, 26, 12, 14
+               // where line (7, 8) forms one function, (25,26) one function,
+               // and (12, 14) one function.
+               int endLine = (endLineNumber != -1) ? endLineNumber : 
+                                               lineEntriesByLine.lastKey();
+
+               List<ILineEntry> entries = new ArrayList<ILineEntry>(), startMappings;
+               
+               /* in case the caller has requested something other than a single line,
+                * make certain this doesn't fail if the the caller passes a
+                * startLineNumber that doesn't have a direct mapping in the LNT
+                */
+               for (; null == (startMappings = lineEntriesByLine.get(startLineNumber))
+                          && startLineNumber < endLine
+                        ; ++startLineNumber) {}
+
+               if (startMappings != null) {
+                       if (startLineNumber == endLineNumber) {
+                               entries.addAll(startMappings);
+                       } else if (endLineNumber == -1) {
+                               // return the entries for the rest of the file
+                               entries = lineEntries.subList(lineEntries.indexOf(startMappings.get(0)), lntSize);
+                       } else {
+                               List<ILineEntry> endMappings = lineEntriesByLine.get(endLineNumber);
+                               if (endMappings != null) {
+                                       entries = lineEntries.subList(lineEntries.indexOf(startMappings.get(0)), lineEntries
+                                                       .indexOf(endMappings.get(endMappings.size() - 1)) + 1);
+                               } else {
+                                       // no mapping for end line #. just go to the end of the file
+                                       entries = lineEntries.subList(lineEntries.indexOf(startMappings.get(0)), lntSize);
+                               }
+                       }
+               }
+
+               return Collections.unmodifiableCollection(entries);
+       }
+
+       public ILineEntry getNextLineEntry(ILineEntry entry, boolean collapseInlineFunctions) {
+               if (entry == null || isLastEntryInCU(entry))
+                       return null;
+               IFunctionScope entryFn = compileUnitScope.getFunctionAtAddress(entry.getLowAddress());
+               IFunctionScope container = ignoreInlineFunctions(entryFn);
+               if (container == null)  // relies on ignoreInlineFunctions() to return null if func==null
+                       return null;
+
+               do {    // loop is for continue to retry the next entry in same function
+
+                       // check if there's even a need to do further operations
+                       IAddress desiredAddr = entry.getHighAddress();
+                       if (desiredAddr.compareTo(container.getHighAddress()) > 0)
+                               return null;
+
+                       SortedMap<IAddress, ILineEntry> tailAddrs
+                         = desiredAddr.equals(entry.getLowAddress())   // can be equal due to DWARF generation bug
+                                       ? null : lineEntriesByAddress.tailMap(desiredAddr);
+
+                       // no other lines in this provider; try the CU line entries
+                       if (tailAddrs == null || tailAddrs.isEmpty()) {
+                               // the following case is that we are at the first line of an inline
+                               // that would otherwise be the last line of a function.
+                               if (collapseInlineFunctions && entryFn != container
+                                               && entry.getLowAddress().equals(entryFn.getLowAddress())
+                                               && entryFn.getParent().equals(container))
+                                       return getDifferentLineEntryInCU(container, entry, entryFn.getHighAddress(),
+                                                                                                         collapseInlineFunctions);
+                               else
+                                       return getDifferentLineEntryInCU(entryFn, entry, desiredAddr,
+                                                                                                         collapseInlineFunctions);
+                       }
+
+                       IAddress foundAddr = tailAddrs.firstKey();
+                       ILineEntry next = tailAddrs.get(foundAddr);
+                       IFunctionScope foundFn = compileUnitScope.getFunctionAtAddress(foundAddr);
+
+                       // [1] if the function of our the current instr ptr entry and
+                       // the function at the found addr are identical, then take it!!
+                       // (i.e. we lucked out!!  all lines in the gap 
+                       // in other providers are nested inlines.)
+                       if (entryFn.equals(foundFn)) {
+                               // ... ok, well, line number must be different, too.
+                               if (next.getLineNumber() != entry.getLineNumber())
+                                       return next;
+                               entry = next;           // just pretend this was the entry ...
+                               continue;                       // ... and try again
+
+                       // [2]if the foundAddr is immediately after this entry ... 
+                       } else if (foundAddr.equals(desiredAddr) && foundFn != null) {          // [2]
+
+                               /// ... and it is
+                               // [2a] an inline parent of this inline
+                               // [2b] an inline and a direct sibling (i.e. not a cousin) of this inline
+                               // then take it!!
+                               if (entryFn.getParent().equals(foundFn)                                                 // [2a]
+                                               || entryFn.getParent().equals(foundFn.getParent())) {   // [2b]
+                                       return tailAddrs.get(foundAddr);
+
+                               // ... or if it is
+                               // [2c] the first line of an inline whose next line in the
+                               //      lineEntriesByLine table is identical to next
+                               // then we'll call that good enough
+                               // (you may be reading this if you have an inline function
+                               // in the same file as the parent function invoking it and
+                               // nothing in between; step over is probably broken for you.)
+                               } else if (foundFn.getParent().equals(entryFn)
+                                               && areEntriesAdjacentLines(entry, next)) {
+                                       return next;
+                               }
+
+                       // similar to [2a] & [2b], even if foundAddr shows a gap
+                       // [3] if the current location is an inline, and entry
+                       //     adjacent to the one passed is identical to next
+                       // again, call it good enough for now.
+                       } else if (collapseInlineFunctions
+                                       && (entryFn.getParent().equals(foundFn)
+                                               || entryFn.getParent().equals(container))
+                                       && areEntriesAdjacentLines(entry, next)) {
+                               return next;
+                       }
+
+
+                       // getting here means 1 (or both) of 2 things (both slightly irrelevant)
+                       //
+                       // either:
+                       // a] entryFn is an ancestor of foundFn
+                       // b] there's a gap between the desiredAddr & the foundAddr
+                       //
+                       // in either case, the next entry will be found in 
+                       // this.compileUnitScope.lineEntries .  so get it from there.
+                       return getDifferentLineEntryInCU(entryFn, entry, desiredAddr,
+                                                                                        collapseInlineFunctions);
+
+               } while (true);
+       }
+
+       /**
+        * @param c the child to compare
+        * @param x the function we are seeking to call an ancestor
+        * @return true if there's a function in this linkage where <b>x</b> is an ancestor of <b>c</b>
+        */
+       private static boolean isAncestorFunction(IFunctionScope c, IFunctionScope x) {
+               for (IScope p = c.getParent(); p != null; p = p.getParent())
+                       if (p.equals(x))
+                               return true;
+               return false;
+       }
+
+       static boolean isInlinedFunction(IFunctionScope function) {
+               return function != null && function.getParent() instanceof IFunctionScope;
+       }
+
+       private static IFunctionScope ignoreInlineFunctions(IFunctionScope function) {
+               if (function == null)
+                       return null;
+               
+               while (function.getParent() instanceof IFunctionScope) {
+                       function = (IFunctionScope) function.getParent();
+               }                       
+               return function;
+       }
+       
+       /**
+        * @param entry
+        * @param next
+        */
+       private boolean areEntriesAdjacentLines(ILineEntry entry, ILineEntry next) {
+               if (entry.getLineNumber() == next.getLineNumber())
+                       return false;
+               SortedMap<Integer, List<ILineEntry>> tailLines
+                 = lineEntriesByLine.tailMap(entry.getLineNumber());
+               if (tailLines != null) {
+                       List<ILineEntry> entries = tailLines.get(entry.getLineNumber());
+                       if (entries != null) {
+                               int entryIdx = entries.indexOf(entry);
+                               if (-1 != entryIdx) {
+                                       if (entry.equals(entries.get(0))
+                                                       && ++entryIdx == entries.size()) {
+                                               entries = tailLines.get(next.getLineNumber());
+                                               if (entries != null && next.equals(entries.get(0))) {
+                                                       return true;
+               }       }       }       }       }
+
+               return false;
+       }
+
+       /**
+        * @param entryFn
+        * @param desiredAddr
+        * @return
+        */
+       private ILineEntry getDifferentLineEntryInCU(IFunctionScope entryFn,
+                       ILineEntry origEntry, IAddress desiredAddr,
+                       boolean collapseInlineFunctions) {
+               if (compileUnitScope instanceof DwarfCompileUnit) {     // known to be a sorted list
+                       if (getCULineEntries().isEmpty())
+                               return null;
+                       int insertion = getLineEntryInsertionForAddress(desiredAddr, cuEntries);
+                       if (-1 != insertion)
+                               for (; insertion < cuEntries.size(); ++insertion) {
+                                       ILineEntry next = cuEntries.get(insertion);
+                                       if (isGoodEntry(next, entryFn, origEntry, collapseInlineFunctions))
+                                               return next;
+                       }
+               } else {
+                       boolean firstFound = false;
+                       for (ILineEntry next : getCULineEntries()) {
+                               if (!firstFound && desiredAddr.compareTo(next.getLowAddress()) < 0)
+                                       continue;
+                               else
+                                       firstFound = true;
+
+                               if (isGoodEntry(next, entryFn, origEntry, collapseInlineFunctions))
+                                       return next;
+                       }
+               }
+
+
+               // by deduction, if we don't hit any of those 3 cases and exhaust all
+               // entries in the compuleUnitScope, then every entry after the current
+               // one is some sort of inline nested to the current function (possibly
+               // even several different inlines nested separately, possibly even with
+               // code from the original function at the original line number).
+               // 
+               // in simple terms, it means the step-over that led here
+               // will turn into a step out
+
+               return null;
+       }
+
+       private boolean isGoodEntry(ILineEntry e, IFunctionScope origFn,
+                       ILineEntry origEntry, boolean collapseInlineFunctions) {
+               IFunctionScope nextFn
+                 = compileUnitScope.getFunctionAtAddress(e.getLowAddress());
+
+               if (origFn.equals(nextFn) && e.getLineNumber() != origEntry.getLineNumber())
+                       return true;    // case [1] described in caller getNextLineEntry()
+
+               else if (!collapseInlineFunctions || !isAncestorFunction(nextFn, origFn))
+                       return true;    // case [2] or [3] described in caller getNextLineEntry()
+
+               return false;
+       }
+
+       private boolean isFirstEntryInCU(ILineEntry e) throws IllegalArgumentException {
+               if (e == null)
+                       throw new IllegalArgumentException("isFirstEntryInCU() called with null");
+               int cuEntriesSize = getCULineEntries().size();
+               return (cuEntriesSize > 0 && e.equals(cuEntries.get(0)));                       
+       }
+
+       private boolean isLastEntryInCU(ILineEntry e) throws IllegalArgumentException {
+               if (e == null)
+                       throw new IllegalArgumentException("isFirstEntryInCU() called with null");
+               int cuEntriesSize = getCULineEntries().size();
+               return (cuEntriesSize > 0 && e.equals(cuEntries.get(cuEntriesSize-1)));
+       }
+
+       public ILineEntry getPreviousLineEntry(ILineEntry entry, boolean collapseInlineFunctions) {
+               if (entry == null || isFirstEntryInCU(entry))
+                       return null;
+               IAddress entryAddr = entry.getLowAddress();
+               IFunctionScope func = compileUnitScope.getFunctionAtAddress(entryAddr);
+               IFunctionScope container = ignoreInlineFunctions(func);
+               if (container == null)  // relies on ignoreInlineFunctions() to return null if func==null
+                       return null;
+               SortedMap<IAddress, ILineEntry> headAddrs = lineEntriesByAddress.headMap(entryAddr);
+               if (headAddrs.isEmpty())
+                       return null;
+
+               if (!collapseInlineFunctions)
+                       return getPreviousLineEntryByAddress(entry, container.getLowAddress(), headAddrs);
+
+               IFunctionScope prevFunc = compileUnitScope.getFunctionAtAddress(entryAddr);
+               IFunctionScope prevContainer = ignoreInlineFunctions(prevFunc);
+               if (prevContainer == null || !prevContainer.equals(container)) {
+                       return null;    // relies on ignoreInlineFunctions() to return null if nextFunc==null
+               }
+
+               boolean inline = !func.equals(container);
+               boolean prevInline = !prevFunc.equals(prevContainer);
+               if (inline && prevInline) {
+                       ILineEntry testPrev = headAddrs.get(headAddrs.lastKey());
+
+                       // take the first head in tailAddrs if the function containing entry is
+                       // [1] identical to the function containing the lastKey of headAddrs
+                       //     (i.e. in the same inline; skips nested inlines in other providers)
+                       // [2] an inline parent of this the previous inline
+                       //     && the top addr of testPrev is immediately bottom addr of entry
+                       // [3] an inline and a sibling of this previous inline
+                       //     && the top addr of testPrev is immediately bottom addr of entry
+                       if (func.equals(prevFunc)                                                                                       // [1]
+                               || (testPrev.getHighAddress().equals(entryAddr)
+                                       && (prevFunc.getParent().equals(func)                                           // [2]
+                                               || prevFunc.getParent().equals(func.getParent())))) {   // [3]
+                               return testPrev;
+                       }
+
+                       if (!filePath.equals(compileUnitScope.getFilePath()))
+                               // fall out and force reliance on the provider mapped from the
+                               // compileUnitScope's filePath (i.e. the parent to these inlines)
+                               return null; 
+               }
+
+               SortedMap<Integer, List<ILineEntry>> headLines
+                 = inline
+                               ? lineEntriesByLine.headMap(headAddrs.get(headAddrs.lastKey()).getLineNumber()+1)
+                               : lineEntriesByLine.headMap(entry.getLineNumber());
+
+               while (!headLines.isEmpty()) {
+                       List<ILineEntry> entries = headLines.get(headLines.lastKey());
+                       for (int i = entries.size()-1; i >= 0; --i) {
+                               ILineEntry prev = entries.get(i);
+                               if (!prev.equals(entry)
+                                               && prev.getHighAddress().compareTo(entryAddr) <= 0
+                                               && prev.getLowAddress().compareTo(container.getLowAddress()) >= 0
+                                               && prev.getLineNumber() != entry.getLineNumber()) {
+                                       return prev;
+                               }
+                       }
+                       headLines = headLines.headMap(headLines.lastKey());
+               }
+               return null;
+       }
+
+       /**
+        * @param entry
+        * @param bottom
+        * @param addrEntries
+        * @return
+        */
+       private ILineEntry getPreviousLineEntryByAddress(ILineEntry entry, IAddress bottom,
+                       SortedMap<IAddress, ILineEntry> addrEntries) {
+               while (!addrEntries.isEmpty()) {
+                       ILineEntry prev = addrEntries.get(addrEntries.lastKey());
+                       if (prev == null || prev.getLowAddress().compareTo(bottom) < 0)
+                               break;
+                       if (prev.getLineNumber() != entry.getLineNumber())
+                               return prev;
+                       addrEntries = addrEntries.headMap(prev.getLowAddress());
+               }
+               return null;
+       }
+
+       public ILineEntry getLineEntryInFunction(IAddress linkAddress, IFunctionScope parentFunction) {
+               
+               // get all line entries with low address <= linkAddress
+               SortedMap<IAddress, ILineEntry> subMap = lineEntriesByAddress.headMap(linkAddress.add(1));
+
+               if (subMap.isEmpty())
+               {
+                       // if no line entries have a low address <= linkAddress, but the address is
+                       // definitely in the function, use the first entry
+                       if (parentFunction.getLowAddress().compareTo(linkAddress) >= 0
+                                       && parentFunction.getHighAddress().compareTo(linkAddress) < 0)
+                               return lineEntriesByAddress.values().iterator().next();
+                       return null;
+               }
+
+               // look for an entry that includes linkAddress; if linkAddress is in the gap between
+               // two lineEntriesByAddress entries, assume the gap is due to inlined functions' code
+               ILineEntry entry = subMap.get(subMap.lastKey());
+               
+               if (   entry.getHighAddress().compareTo(linkAddress) >= 0
+                       || subMap.size() < lineEntriesByAddress.size()) {
+                       return entry;
+               }
+
+               return null;
+       }
+
+       /**
+        * ONLY call when caller has 'collapseInlineFunctions == true' and the caller
+        * has failed to get the address in any other way.
+        * 
+        * @param cuScope the scope in which to search for the entry of interest
+        * @param entry the entry in hand, for which the preceding entry is desired
+        * @return a line-entry whose end address is exactly first address of the passed entry
+        */
+       protected ILineEntry getPreviousLineEntryInCU(ILineEntry entry) {
+               IAddress desiredEndAddress = entry.getLowAddress();
+
+               for (ILineEntry testEntry : getCULineEntries()) {
+                       if (!desiredEndAddress.equals(testEntry.getHighAddress()))
+                               continue;
+                       IFunctionScope entryFn
+                         = compileUnitScope.getFunctionAtAddress(entry.getLowAddress());
+                       IScope entryParent = entryFn.getParent();
+
+                       IFunctionScope prevFn
+                         = compileUnitScope.getFunctionAtAddress(testEntry.getLowAddress());
+                       if (isInlinedFunction(entryFn)
+                               && (isAncestorFunction(entryFn, prevFn)
+                                       || entryParent != null && entryParent.equals(prevFn.getParent()))) {
+                               return testEntry;
+                       }
+                       if (isAncestorFunction(prevFn, entryFn)) {
+                               // TODO: add logic to get entry at start of testEntry
+                               // something like:
+                               //      dp {
+                               //              desiredEndAddress = testEntry.getLowAddress();
+                               //              testEntry = getPreviousLineEntryInCU(cuScope, testEntry, null);
+                               //              get back to where the function for testEntry is a sibling or
+                               //              ancestor of entryFn
+                               //      } while (testEntry != null)
+                               // 
+                               // but this is mostly here to help with step-out while standing
+                               // on first instruction of inline coinciding with source, so fix later
+                       }
+                       break;  // got the address of interest; just wasn't useful as we wanted 
+               }
+               return null;
+       }
+
+       /*
+        * Find code line for the anchor in one compile unit.
+        * The returned value should only contain one entry.
+        * 
+        * (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider#findClosestLineWithCode(org.eclipse.core.runtime.IPath, int, int)
+        */
+       public List<ILineAddresses> findClosestLineWithCode(IPath sourceFile,
+                       int anchorLine, int neighbor_limit) {
+               List<ILineAddresses> ret = new ArrayList<ILineAddresses>(1);
+               
+               // FIXME: ugly drive letter stuff
+               if (!filePath.setDevice(null).equals(sourceFile.setDevice(null)) )
+               {
+                       if (!PathUtils.isCaseSensitive() && filePath.toOSString().compareToIgnoreCase(sourceFile.toOSString()) != 0)
+                               return ret;                     
+               }
+
+               EDCLineAddresses codeLine = null;
+               
+               codeLine = getLineAddresses(anchorLine);
+               if (codeLine != null) {
+                       // The anchor itself has code
+                       ret.add(codeLine);
+                       return ret;
+               }
+               
+               int limit;
+
+               // Anchor has no code, but there are code lines above the anchor. 
+               // find the closest one.
+               EDCLineAddresses candidate_above = null;
+               if (anchorLine > lineEntriesByLine.firstKey()) {
+                       if (neighbor_limit == -1)
+                               limit = lineEntriesByLine.firstKey();
+                       else {
+                               limit = anchorLine - neighbor_limit;
+                               if (limit < lineEntriesByLine.firstKey())
+                                       limit = lineEntriesByLine.firstKey();
+                       }
+                       
+                       for (int i = anchorLine-1; i >= limit; i--) {
+                               candidate_above = getLineAddresses(i);
+                               if (candidate_above != null)
+                                       break;
+                       }
+               }
+               
+               // there are code lines below the anchor. 
+               // find the closest one.
+               EDCLineAddresses candidate_below = null;
+               if (anchorLine < lineEntriesByLine.lastKey()) {
+                       if (neighbor_limit == -1)
+                               limit = lineEntriesByLine.lastKey();
+                       else {
+                               limit = anchorLine + neighbor_limit;
+                               if (limit > lineEntriesByLine.lastKey())
+                                       limit = lineEntriesByLine.lastKey();
+                       }
+                       
+                       for (int i = anchorLine+1; i <= limit; i++) {
+                               candidate_below = getLineAddresses(i);
+                               if (candidate_below != null)
+                                       break;
+                       }
+               }
+               
+               if (candidate_above == null)
+                       codeLine = candidate_below;
+               else {
+                       if (candidate_below == null)
+                               codeLine = candidate_above;
+                       else {
+                               int distance_above = anchorLine - candidate_above.getLineNumber();
+                               int distance_below = candidate_below.getLineNumber() - anchorLine;
+                               
+                               if (distance_above == distance_below)
+                                       codeLine = candidate_below;
+                               else 
+                                       codeLine = (distance_above < distance_below)? candidate_above : candidate_below;
+                       }
+               }
+               
+               if (codeLine != null)
+                       ret.add(codeLine);
+               
+               return ret;
+       }
+
+       /**
+        * Create EDCLineAddresses object for a line if it has code.
+        * @param line
+        * @return null if the line has no code.
+        */
+       private EDCLineAddresses getLineAddresses(int line) {
+               if (! lineEntriesByLine.containsKey(line))
+                       return null;
+               
+               List<IAddress> line_addrs = new ArrayList<IAddress>();
+               int lastColumn = -2;
+
+               for (ILineEntry e : lineEntriesByLine.get(line)) {
+                       /*
+                        * When there is more than one line mapping for the source line:
+                        * 
+                        * If they are multiple logical code segments for the same source
+                        * line, but in different columns, only remember address of the
+                        * first entry.
+                        * 
+                        * If they are templates or inline functions, the column will be the
+                        * same, and we record addresses of all entries.
+                        */
+                       int entryColumn = e.getColumnNumber();
+                       if (line_addrs.size() == 0 || lastColumn == entryColumn)
+                               line_addrs.add(e.getLowAddress());
+
+                       lastColumn = entryColumn;
+               }
+
+               return new EDCLineAddresses(line, line_addrs);
+       }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/FunctionScope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/FunctionScope.java
new file mode 100644 (file)
index 0000000..d91fca1
--- /dev/null
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+import org.eclipse.core.runtime.IPath;
+
+public class FunctionScope extends Scope implements IFunctionScope {
+
+       protected ILocationProvider frameBaseLocationProvider;
+       protected List<IVariable> parameters = new ArrayList<IVariable>();
+       private int declLine;
+       private int declColumn;
+       private IPath declFile;
+
+       public FunctionScope(String name, IScope parent, IAddress lowAddress, IAddress highAddress,
+                       ILocationProvider frameBaseLocationProvider) {
+               super(name, lowAddress, highAddress, parent);
+
+               this.frameBaseLocationProvider = frameBaseLocationProvider;
+       }
+
+       public Collection<IVariable> getParameters() {
+               return Collections.unmodifiableCollection(parameters);
+       }
+
+       public ILocationProvider getFrameBaseLocation() {
+               return frameBaseLocationProvider;
+       }
+
+       public Collection<IVariable> getVariablesInTree() {
+               List<IVariable> variables = new ArrayList<IVariable>();
+               variables.addAll(super.getVariables());
+
+               // check for variables in children as well
+               for (IScope child : children) {
+                       if (child instanceof IFunctionScope)
+                               variables.addAll(((IFunctionScope) child).getVariablesInTree());
+                       else if (child instanceof ILexicalBlockScope)
+                               variables.addAll(((ILexicalBlockScope) child).getVariablesInTree());
+                       else
+                               variables.addAll(child.getVariables());
+               }
+
+               return variables;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IFunctionScope#getScopedVariables(org.eclipse.cdt.core.IAddress)
+        */
+       public Collection<IVariable> getScopedVariables(IAddress linkAddress) {
+               // Unfortunately, lexical blocks and inlined functions may span several scopes or use ranges;
+               // don't #getScopeAtAddress() and go up the parent chain, but iterate them top-down.
+               
+               List<IVariable> scoped = new ArrayList<IVariable>();
+               List<String> varNames = new ArrayList<String>();
+
+               recurseGetScopedVariables(this, scoped, varNames, linkAddress);
+
+               return scoped;
+       }
+               
+       protected static void recurseGetScopedVariables(IScope scope, List<IVariable> scoped, List<String> varNames, IAddress linkAddress) {
+               long scopeOffset = linkAddress.add(scope.getLowAddress().getValue().negate()).getValue().longValue();
+
+               for (IVariable var : scope.getVariables()) {
+                       if (scopeOffset >= var.getStartScope() && var.getLocationProvider().isLocationKnown(linkAddress)) {
+                               String varName = var.getName();
+                               if (!varNames.contains(varName)) {
+                                       scoped.add(var);
+                                       varNames.add(varName);
+                               }
+                       }
+               }
+
+               boolean isFunctionScope = (scope instanceof IFunctionScope); 
+               if (isFunctionScope) {
+                       for (IVariable var : ((FunctionScope) scope).getParameters()) {
+                               if (scopeOffset >= var.getStartScope() && var.getLocationProvider().isLocationKnown(linkAddress)) {
+                                       String varName = var.getName();
+                                       if (!varNames.contains(varName)) {
+                                               scoped.add(var);
+                                               varNames.add(varName);
+                                       }
+                               }
+                       }
+               }
+
+               for (IScope kid : scope.getChildren()) {
+                       // notice this is > instead of >= like caller getScopedVariables() ...
+                       // thus stepping out of scope to next instr won't result in scoped variables still being seen
+                       if (kid.getLowAddress().compareTo(linkAddress) <= 0 && kid.getHighAddress().compareTo(linkAddress) > 0)
+                               recurseGetScopedVariables(kid, scoped, varNames, linkAddress);
+                       else if (isFunctionScope && linkAddress.compareTo(kid.getHighAddress()) == 0)
+                               recurseGetScopedVariables(kid, scoped, varNames, kid.getHighAddress());
+                       else if (kid instanceof ILexicalBlockScope) {
+                               // RVCT 4.x Dwarf lexical blocks may contain local variables whose live ranges extend
+                               // beyond the bounds of their enclosing lexical blocks, so check lexical block variables
+                               recurseGetLexicalBlockVariables(kid, scoped, varNames, linkAddress);
+                       }       
+               }
+       }
+
+       /**
+        * Find lexical block variables whose lifetimes include the given address, whether or not the address is
+        * inside the lexical block. 
+        * Note: RVCT 4.x Dwarf lexical blocks may contain local variables whose live ranges extend beyond
+        *       the bounds of their enclosing lexical blocks
+        **/
+       private static void recurseGetLexicalBlockVariables(IScope scope, List<IVariable> scoped, List<String> varNames, IAddress linkAddress) {
+               if (!(scope instanceof ILexicalBlockScope))
+                       return;
+
+               for (IVariable var : scope.getVariables()) {
+                       ILocationProvider locationProvider = var.getLocationProvider();
+                       if (!locationProvider.lifetimeMustMatchScope() && locationProvider.isLocationKnown(linkAddress)) {
+                               String varName = var.getName();
+                               if (!varNames.contains(varName)) {
+                                       scoped.add(var);
+                                       varNames.add(varName);
+                               }
+                       }
+               }
+
+               for (IScope kid : scope.getChildren()) {
+                       recurseGetLexicalBlockVariables(kid, scoped, varNames, linkAddress);
+               }
+       }
+
+       public void addParameter(IVariable parameter) {
+               parameters.add(parameter);
+       }
+
+       public IPath getDeclFile() {
+               return declFile;
+       }
+       
+       public void setDeclFile(IPath declFile) {
+               this.declFile = declFile;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IFunctionScope#getDeclLine()
+        */
+       public int getDeclLine() {
+               return declLine;
+       }
+       
+       public void setDeclLine(int declLine) {
+               this.declLine = declLine;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IFunctionScope#getDeclColumn()
+        */
+       public int getDeclColumn() {
+               return declColumn;
+       }
+       
+       public void setDeclColumn(int declColumn) {
+               this.declColumn = declColumn;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#addChild(org.eclipse.cdt.debug.edc.internal.symbols.IScope)
+        */
+       @Override
+       public void addChild(IScope scope) {
+               super.addChild(scope);
+               
+               if (scope instanceof IFunctionScope)
+                       addLineInfoToParent(scope);
+       }
+       
+
+       public void setLocationProvider(ILocationProvider locationProvider) {
+               this.frameBaseLocationProvider = locationProvider;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IAggregate.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IAggregate.java
new file mode 100644 (file)
index 0000000..36b5979
--- /dev/null
@@ -0,0 +1,14 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+public interface IAggregate {
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IArrayBoundType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IArrayBoundType.java
new file mode 100644 (file)
index 0000000..c2aa3dc
--- /dev/null
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+public interface IArrayBoundType {
+
+       /** bound of this array dimension. E.g., for "int a[7][8]", this would be
+        * either 7 or 8.
+        */
+       public long getBoundCount();
+
+       /**  number of array elements associated with each index of this array
+        *  dimension.
+        *      E.g., for "int a[7][8]", "a[1]" comprises 8 elements, but "a[1][2]"
+        * comprises 1 element.
+        */
+       public long getElementCount();
+
+       /** array dimension ordinal. E.g., for "int a[7][8]", "[7]" is index 1 and
+        * "[8]" is index 0;
+        */
+       public long getDimensionIndex();
+
+       public void multiplyElementCount(long multiply);
+
+       public void incDimensionIndex();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IArrayType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IArrayType.java
new file mode 100644 (file)
index 0000000..bf0bc44
--- /dev/null
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IArrayType extends IType, IAggregate {
+
+       /**
+        * get the type that this is an array of
+        */
+       public IType getType();
+
+       public int getBoundsCount();
+
+       public void addBound(IArrayBoundType bound);
+
+       public IArrayBoundType[] getBounds();
+
+       // get the Nth bound. E.g., for "a[X][Y]", getBound(0) returns info for
+       // "[X]"
+       public IArrayBoundType getBound(int index);
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IBasicType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IBasicType.java
new file mode 100644 (file)
index 0000000..f9bff25
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+/**
+ * Interface for basic types.
+ * 
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IBasicType extends IType {
+
+       public static final int t_unspecified = IASTSimpleDeclSpecifier.t_unspecified;
+       public static final int t_void = IASTSimpleDeclSpecifier.t_void;
+       public static final int t_char = IASTSimpleDeclSpecifier.t_char;
+       public static final int t_int = IASTSimpleDeclSpecifier.t_int;
+       public static final int t_float = IASTSimpleDeclSpecifier.t_float;
+       public static final int t_double = IASTSimpleDeclSpecifier.t_double;
+
+       /**
+        * This returns the built-in type for the declaration. The type is then
+        * refined by qualifiers for signed/unsigned and short/long. The type could
+        * also be unspecified which usually means int.
+        * 
+        */
+       public int getBaseType();
+
+       public boolean isSigned();
+
+       public boolean isUnsigned();
+
+       public boolean isShort();
+
+       public boolean isLong();
+       
+       public boolean isLongLong();
+       
+       public boolean isComplex();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ICPPBasicType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ICPPBasicType.java
new file mode 100644 (file)
index 0000000..0ff2fec
--- /dev/null
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ICPPBasicType extends IBasicType {
+
+       public static final int IS_LONG      = 1;
+       public static final int IS_SHORT     = 1 << 1;
+       public static final int IS_SIGNED    = 1 << 2;
+       public static final int IS_UNSIGNED  = 1 << 3;
+       public static final int IS_COMPLEX   = 1 << 4; // for gpp-types
+       public static final int IS_IMAGINARY = 1 << 5; // for gpp-types
+       public static final int IS_LONG_LONG = 1 << 6; // for gpp-types
+       public static final int LAST = IS_LONG_LONG;
+
+       // Extra types
+       public static final int t_bool    = ICPPASTSimpleDeclSpecifier.t_bool;
+       public static final int t_wchar_t = ICPPASTSimpleDeclSpecifier.t_wchar_t;
+
+       /**
+        * @return a combination of qualifiers.
+        */
+       public int getQualifierBits();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ICompositeType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ICompositeType.java
new file mode 100644 (file)
index 0000000..62c8cb4
--- /dev/null
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+public interface ICompositeType extends IType, IAggregate {
+       
+       // accessibility of an inherited class or of a composite's field
+       public static int ACCESS_PUBLIC    = 0;
+       public static int ACCESS_PROTECTED = 1;
+       public static int ACCESS_PRIVATE   = 2;
+
+       public static final int k_class  = ICPPASTCompositeTypeSpecifier.k_class;
+       public static final int k_struct = IASTCompositeTypeSpecifier.k_struct;
+       public static final int k_union  = IASTCompositeTypeSpecifier.k_union;
+
+       /**
+        * Kind of composite (class, struct, union)
+        * 
+        * @return kind
+        */
+       public int getKey();
+
+       /**
+        * Number of fields/enumerators in composite
+        * 
+        * @return count
+        */
+       public int fieldCount();
+
+       /**
+        * Add a field/member to the end of the list of fields or enumerators
+        * Intended for use by a debug information parser.
+        * 
+        * @param field
+        *            field to add
+        */
+       public void addField(IField field);
+
+       /**
+        * Get an array of fields/enumerators in composite
+        * 
+        * @return array of fields/enumerators, or IField.EMPTY_FIELD_ARRAY if no
+        *         fields/enumerators
+        */
+       public IField[] getFields();
+
+       /**
+        * Add a template parameter to the end of the list of template parameters
+        * Intended for use by a debug information parser.
+        * 
+        * @param templateParam
+        *            template parameter to add
+        */
+       public void addTemplateParam(ITemplateParam templateParam);
+
+       /**
+        * Get an array of template parameters in composite
+        * 
+        * @return array of template parameters, or empty array if no
+        *         template parameters
+        */
+       public ITemplateParam[] getTemplateParams();
+
+       /**
+        * Find the composite fields/members with the given name
+        * 
+        * @param name field name, which may contain "::" separators
+        * @return array of matching fields if any exist, or null otherwise
+        */
+       public IField[] findFields(String name);
+
+       /**
+        * Number of classes and structs from which the composite inherits
+        * 
+        * @return count
+        */
+       public int inheritanceCount();
+
+       /**
+        * Add an inherited-from class or struct to the end of the list
+        * of inherited-from classes and structs
+        * Intended for use by a debug information parser.
+        * 
+        * @param inheritance
+        *            information about class/struct from which this
+        *            composite inherits
+        */
+       public void addInheritance(IInheritance inheritance);
+       
+       /**
+        * Get an array of inherited-from classes/structs for composite
+        * 
+        * @return array of information about classes and structs from which this
+        * composite inherits, or an empty array if nothing is inherited
+        */
+       public IInheritance[] getInheritances();
+       
+       /**
+        * Get the name without a type prefix (e.g., "foo" instead of "class foo")
+        * 
+        * @return composite name without a type 
+        */
+       public String getBaseName();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IConstType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IConstType.java
new file mode 100644 (file)
index 0000000..cdd2051
--- /dev/null
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+/**
+ * Interface used to identify pseudo-types that represent const qualifiers
+ * 
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IConstType extends IQualifierType {
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IEnumeration.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IEnumeration.java
new file mode 100644 (file)
index 0000000..254d26b
--- /dev/null
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IEnumerator;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+public interface IEnumeration extends IType {
+
+       public int enumeratorCount();
+
+       public void addEnumerator(IEnumerator enumerator);
+
+       public IEnumerator getEnumeratorByName(String name);
+
+       public IEnumerator getEnumeratorByValue(long value);
+
+       /**
+        * returns an array of the IEnumerators declared in this enumeration
+        */
+       IEnumerator[] getEnumerators();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IField.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IField.java
new file mode 100644 (file)
index 0000000..14fc09c
--- /dev/null
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IField extends IType {
+
+       public static final IField[] EMPTY_FIELD_ARRAY = new IField[0];
+
+       public long getFieldOffset();
+
+       public int getBitSize();
+
+       public int getBitOffset();
+       
+       public int getAccessibility();
+
+       // member offset may need to be computed
+       public void setFieldOffset(long offset);
+
+       /**
+        * Returns the composite type that owns the field.
+        */
+       ICompositeType getCompositeTypeOwner();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IForwardTypeReference.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IForwardTypeReference.java
new file mode 100644 (file)
index 0000000..76bb601
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+
+/**
+ *     This represents a type which is a proxy for an unparsed type. 
+ */
+public interface IForwardTypeReference extends IType {
+       /** Realize (if needed) and return the actual type */
+       IType getReferencedType();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IInheritance.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IInheritance.java
new file mode 100644 (file)
index 0000000..86fe9b8
--- /dev/null
@@ -0,0 +1,57 @@
+/*******************************************************************************
+
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+public interface IInheritance extends IType {
+
+       /**
+        * Get offset to inherited fields
+        * 
+        * @return offset within inherited type to the fields inherited 
+        */
+       public long getFieldsOffset();
+       
+       /**
+        * Get type of accessibility to inherited fields (public, protected, or private)
+        * 
+        * @return type of accessibility (one of: {@link ICompositeType}'s
+        * ACCESS_PUBLIC, ACCESS_PROTECTED, or ACCESS_PRIVATE)
+        */
+       public int getAccessibility();
+
+       /**
+        * Get properties
+        * 
+        * @return general map of type properties
+        */
+       public Map<Object, Object> getProperties();
+
+       /**
+        * Get type inherited from
+        * 
+        * @return type
+        */
+       public IType getType();
+
+       /**
+        * Set type inherited from
+        * 
+        * @param type
+        *           type inherited from
+        */
+       public void setType(IType type);
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ILexicalBlockScope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ILexicalBlockScope.java
new file mode 100644 (file)
index 0000000..c8e2d51
--- /dev/null
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Collection;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+
+/**
+ * Interface representing a lexical block scope. A lexical block is a block of
+ * code inside of a function. A lexical block may contain other lexical blocks
+ * as children.
+ */
+public interface ILexicalBlockScope extends IScope {
+
+       /**
+        * Gets the list of variables in this scope and any child scopes
+        * 
+        * @return unmodifiable list of variables which may be empty
+        */
+       Collection<IVariable> getVariablesInTree();
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IMayBeQualifedType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IMayBeQualifedType.java
new file mode 100644 (file)
index 0000000..85d2397
--- /dev/null
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+public interface IMayBeQualifedType extends IType {
+
+       /**
+        * Whether this is a const type
+        * 
+        * @return true only if this is a const type
+        */
+       public boolean isConst();
+
+       /**
+        * Whether this is a volatile type
+        * 
+        * @return true only if this is a volatile type
+        */
+       public boolean isVolatile();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IPointerType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IPointerType.java
new file mode 100644 (file)
index 0000000..119982f
--- /dev/null
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+/**
+ * Interface for pointer types
+ */
+public interface IPointerType extends IType {
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IQualifierType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IQualifierType.java
new file mode 100644 (file)
index 0000000..5b68cab
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+/**
+ * Interface used to identify pseudo-types that represent qualifiers
+ * 
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IQualifierType extends IType {
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IReferenceType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IReferenceType.java
new file mode 100644 (file)
index 0000000..beea795
--- /dev/null
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+public interface IReferenceType extends IType {
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IRuntimeSection.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IRuntimeSection.java
new file mode 100644 (file)
index 0000000..05eb66e
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.core.IAddress;
+
+public interface IRuntimeSection extends ISection {
+
+       static final String PROPERTY_RUNTIME_ADDRESS = "runtime_address"; //$NON-NLS-1$
+
+       /**
+        * Get the base runtime address of the section
+        * 
+        * @return the base runtime address
+        */
+       IAddress getRuntimeAddress();
+
+       /**
+        * Relocates the section to the given runtime base address
+        * 
+        * @param runtimeAddress
+        *            the relocated base address of the section
+        */
+       void relocate(IAddress runtimeAddress);
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ISection.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ISection.java
new file mode 100644 (file)
index 0000000..ce9f748
--- /dev/null
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+
+/**
+ * Interface representing a section in memory. It is segment in Elf file and a
+ * section in PE file.
+ */
+public interface ISection {
+
+       /**
+        * Commonly known properties of a section
+        */
+       static final String PROPERTY_ID = "id"; //$NON-NLS-1$
+       static final String PROPERTY_SIZE = "size"; //$NON-NLS-1$
+       static final String PROPERTY_LINK_ADDRESS = "link_address"; //$NON-NLS-1$
+       /** Canonical section name: one of NAME_TEXT, NAME_DATA, NAME_RODATA, or NAME_BSS */
+       static final String PROPERTY_NAME = "name"; //$NON-NLS-1$
+       
+       /* TODO: not used
+       static final String PROPERTY_READABLE = "readable";
+       static final String PROPERTY_WRITABLE = "writable";
+       static final String PROPERTY_EXECUTABLE = "executable";
+        */
+       
+       static final String NAME_TEXT = ".text"; //$NON-NLS-1$
+       static final String NAME_DATA = ".data"; //$NON-NLS-1$
+       static final String NAME_RODATA = ".rodata"; // read only data //$NON-NLS-1$
+       static final String NAME_BSS = ".bss"; // uninitialized data //$NON-NLS-1$
+
+       /**
+        * Get the section id
+        * 
+        * @return the section id
+        */
+       int getId();
+
+       /**
+        * Get the section size
+        * 
+        * @return the section size
+        */
+       long getSize();
+
+       /**
+        * Get the base link address of the section
+        * 
+        * @return the base link address
+        */
+       IAddress getLinkAddress();
+
+       /**
+        * Get the properties of the section
+        * 
+        * @return the section properties
+        */
+       Map<String, Object> getProperties();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ISubroutineType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ISubroutineType.java
new file mode 100644 (file)
index 0000000..db9607b
--- /dev/null
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+/**
+ * 
+ */
+public interface ISubroutineType extends IType {
+       // TODO (parameters)  (for now, only gathers the return type)
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ITemplateParam.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ITemplateParam.java
new file mode 100644 (file)
index 0000000..01ee044
--- /dev/null
@@ -0,0 +1,17 @@
+/*******************************************************************************
+
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+public interface ITemplateParam extends IType {
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ITypedef.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ITypedef.java
new file mode 100644 (file)
index 0000000..f7308e6
--- /dev/null
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITypedef extends IType {
+
+       /**
+        * Get the type that this is the typedef of
+        * 
+        * @return typedef'ed type
+        */
+       public IType getType();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/InheritanceType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/InheritanceType.java
new file mode 100644 (file)
index 0000000..dfdc42e
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class InheritanceType extends Type implements IInheritance {
+
+       // access type of inheritance
+       private final int accessibility;
+
+       // offset in inherited class to the inherited fields 
+       private final long fieldsOffset;
+       
+       public InheritanceType(IScope scope, int accessibility, long inheritanceOffset, Map<Object, Object> properties) {
+               super("", scope, 0, properties); //$NON-NLS-1$
+               this.accessibility = accessibility;
+               this.fieldsOffset = inheritanceOffset;
+       }
+       
+       public int getAccessibility() {
+               return this.accessibility;
+       }
+       
+       public long getFieldsOffset() {
+               return this.fieldsOffset;
+       }
+       
+       @Override
+       public String getName() {
+               if (getType() instanceof ICompositeType)
+                       return ((ICompositeType) getType()).getBaseName();
+
+               if (getType() == null)
+                       return "$"; //$NON-NLS-1$  // do not confuse expression formatter
+               else
+                       return getType().getName();
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/InvalidVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/InvalidVariableLocation.java
new file mode 100644 (file)
index 0000000..cb24243
--- /dev/null
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.symbols.IInvalidVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+public class InvalidVariableLocation implements IInvalidVariableLocation {
+
+       private String message;
+
+       public InvalidVariableLocation(String message) {
+               if (message == null)
+                       this.message = ""; //$NON-NLS-1$
+               else
+                       this.message = message;
+       }
+
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return "Invalid: " + getMessage(); //$NON-NLS-1$
+       }
+       
+       
+       public String getMessage() {
+               return this.message;
+       }
+
+       public void setMessage(String message) {
+               if (message == null)
+                       this.message = ""; //$NON-NLS-1$
+               else
+                       this.message = message;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#readValue()
+        */
+       public BigInteger readValue(int bytes) throws CoreException {
+               throw EDCDebugger.newCoreException(message);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#addOffset(long)
+        */
+       public IVariableLocation addOffset(long offset) {
+               return this;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#getLocationName(org.eclipse.cdt.dsf.service.DsfServicesTracker)
+        */
+       public String getLocationName() {
+               return ""; //$NON-NLS-1$
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#getAddress()
+        */
+       public IAddress getAddress() {
+               return null;
+       }
+
+       public void writeValue(int bytes, BigInteger value) throws CoreException {
+               throw EDCDebugger.newCoreException(SymbolsMessages.InvalidVariableLocation_CannotWriteInvalidLocation);
+       }
+
+       public IDMContext getContext() {
+               return null;
+       }
+
+       public EDCServicesTracker getServicesTracker() {
+               return null;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/LexicalBlockScope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/LexicalBlockScope.java
new file mode 100644 (file)
index 0000000..5137664
--- /dev/null
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+
+public class LexicalBlockScope extends Scope implements ILexicalBlockScope {
+
+       public LexicalBlockScope(String name, IScope parent, IAddress lowAddress, IAddress highAddress) {
+               super(name, lowAddress, highAddress, parent);
+       }
+
+       public Collection<IVariable> getVariablesInTree() {
+               List<IVariable> variables = new ArrayList<IVariable>();
+               variables.addAll(super.getVariables());
+
+               // check for variables in children as well
+               for (IScope child : children) {
+                       if (child instanceof IFunctionScope)
+                               variables.addAll(((IFunctionScope) child).getVariablesInTree());
+                       else if (child instanceof ILexicalBlockScope)
+                               variables.addAll(((ILexicalBlockScope) child).getVariablesInTree());
+                       else
+                               variables.addAll(child.getVariables());
+               }
+
+               return variables;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/LineEntry.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/LineEntry.java
new file mode 100644 (file)
index 0000000..efdc4b2
--- /dev/null
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.core.runtime.IPath;
+
+public class LineEntry implements ILineEntry {
+
+       protected IPath filePath;
+       protected int lineNumber;
+       protected int columnNumber;
+       protected IAddress lowAddress;
+       protected IAddress highAddress;
+
+       public LineEntry(IPath filePath, int lineNumber, int columnNumber, IAddress lowAddress, IAddress highAddress) {
+               this.filePath = filePath;
+               this.lineNumber = lineNumber;
+               this.columnNumber = columnNumber;
+               this.lowAddress = lowAddress;
+               this.highAddress = highAddress;
+       }
+
+       public IPath getFilePath() {
+               return filePath;
+       }
+
+       public int getLineNumber() {
+               return lineNumber;
+       }
+
+       public int getColumnNumber() {
+               return columnNumber;
+       }
+
+       public IAddress getLowAddress() {
+               return lowAddress;
+       }
+
+       public IAddress getHighAddress() {
+               return highAddress;
+       }
+
+       public void setHighAddress(IAddress highAddress) {
+               this.highAddress = highAddress;
+       }
+
+       public int compareTo(Object o) {
+               if (o instanceof ILineEntry) {
+                       // some entries have low==high
+                       int diff = lowAddress.compareTo(((ILineEntry) o).getLowAddress());
+                       if (diff != 0)
+                               return diff;
+                       if (highAddress != null && ((ILineEntry) o).getHighAddress() != null)
+                               return highAddress.compareTo(((ILineEntry) o).getHighAddress());
+                       return 0;
+               } else if (o instanceof IAddress) {
+                       return lowAddress.compareTo(o);
+               }
+
+               return 0;
+       }
+
+       @Override
+       public String toString() {
+               return "LineEntry [lowAddress="
+                               + (lowAddress != null ? lowAddress.toHexAddressString() : "null")
+                               + ", highAddress="
+                               + (highAddress != null ? highAddress.toHexAddressString() : "null")
+                               + ((filePath != null) ? ", path=" + filePath.toOSString() + ", " : ", ")
+                               + "line=" + lineNumber + ", column=" + columnNumber
+                               + "]" ; //$NON-NLS-1$
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/MayBeQualifiedType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/MayBeQualifiedType.java
new file mode 100644 (file)
index 0000000..174dccf
--- /dev/null
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+public class MayBeQualifiedType extends Type implements IMayBeQualifedType {
+       boolean qualifiersChecked = false;
+       boolean isConst = false;
+       boolean isVolatile = false;
+
+       public MayBeQualifiedType(String name, IScope scope, int byteSize, Map<Object, Object> properties) {
+               super(name, scope, byteSize, properties);
+       }
+
+       public boolean isConst() {
+               if (!qualifiersChecked)
+                       checkQualifiers();
+               return isConst;
+       }
+
+       public boolean isVolatile() {
+               if (!qualifiersChecked)
+                       checkQualifiers();
+               return isVolatile;
+       }
+
+       /**
+        * Check whether the type is qualified. If so, set the proper booleans.
+        */
+       private void checkQualifiers() {
+               IType checkedType = getType();  // so it will be resolved
+               while (checkedType != null && (checkedType instanceof IQualifierType)) {
+                       isConst    |= checkedType instanceof ConstType;
+                       isVolatile |= checkedType instanceof VolatileType;
+                       checkedType = checkedType.getType();
+               }
+               qualifiersChecked = true;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/MemoryVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/MemoryVariableLocation.java
new file mode 100644 (file)
index 0000000..0418415
--- /dev/null
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.MemoryUtils;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Memory;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.symbols.IMemoryVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.debug.core.model.MemoryByte;
+
+public class MemoryVariableLocation implements IMemoryVariableLocation {
+
+       protected IAddress address;
+       protected boolean isRuntimeAddress;
+       protected EDCServicesTracker tracker;
+       private IDMContext context;
+
+       public MemoryVariableLocation(EDCServicesTracker tracker, IDMContext context, BigInteger addressValue,
+                       boolean isRuntimeAddress) {
+               initialize(tracker,context,addressValue,isRuntimeAddress, false);
+       }
+
+       public MemoryVariableLocation(EDCServicesTracker tracker, IDMContext context, BigInteger addressValue,
+                       boolean isRuntimeAddress, boolean checkNonLocalConstVariable) {
+               // checkConstVariableAddress should only be true for global or static (non-local) constant variables
+               initialize(tracker,context,addressValue,isRuntimeAddress, checkNonLocalConstVariable);
+       }
+
+       private void initialize(EDCServicesTracker tracker, IDMContext context, BigInteger addressValue,
+                       boolean isRuntimeAddress, boolean checkNonLocalConstVariable)  {
+               this.tracker = tracker;
+               this.context = context;
+               BigInteger MAXADDR = BigInteger.valueOf(0xffffffffL);
+               ITargetEnvironment targetEnvironment = tracker.getService(ITargetEnvironment.class);
+               if (targetEnvironment != null && targetEnvironment.getPointerSize() == 8) {
+                       MAXADDR = BigInteger.valueOf(0xffffffffffffffffL);
+               }
+               this.address = new Addr64(addressValue.and(MAXADDR));
+               this.isRuntimeAddress = isRuntimeAddress;
+
+               if (checkNonLocalConstVariable)
+                       checkNonLocalConstVariableAddr();
+       }
+       
+       /**
+        * Since a global or static constant variable may be either at a fixed ROM address or at a runtime address,
+        * and a compiler may not know which is correct when generating debug info, check the address   
+        */
+       private void checkNonLocalConstVariableAddr() {
+               // TODO: Instead of this, query whether the constant variable's address is a fixed or runtime address
+
+               // Try reading a byte at the supposed address, and, if that fails, switch the sense of this.isRuntimeAddress
+               IAddress theAddress = address;
+               if (!isRuntimeAddress) {
+                       StackFrameDMC frame = DMContexts.getAncestorOfType(context, StackFrameDMC.class);
+                       if (frame == null) {
+                               isRuntimeAddress = !isRuntimeAddress;
+                               return;
+                       }
+                       theAddress = frame.getModule().toRuntimeAddress(theAddress);
+               }
+               
+               ExecutionDMC exeDMC = DMContexts.getAncestorOfType(context, ExecutionDMC.class);
+               
+               Memory memoryService = tracker.getService(Memory.class);
+               ArrayList<MemoryByte> memBuffer = new ArrayList<MemoryByte>(1);
+               IStatus memGetStatus = memoryService.getMemory(exeDMC, theAddress, memBuffer, 1, 1);
+               if (!memGetStatus.isOK()) {
+                       isRuntimeAddress = !isRuntimeAddress;
+                       return;
+               }
+
+               if (!memBuffer.get(0).isReadable()) {
+                       isRuntimeAddress = !isRuntimeAddress;
+                       return;
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return "0x" + Long.toHexString(address.getValue().longValue()) + //$NON-NLS-1$
+                               (isRuntimeAddress ? "" : " (link address)"); //$NON-NLS-1$ //$NON-NLS-2$
+       }
+       
+       public IAddress getAddress() {
+               try {
+                       return getRealAddress();
+               } catch (CoreException e) {
+                       return null;
+               }
+       }
+
+       public boolean isRuntimeAddress() {
+               return isRuntimeAddress;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#readValue()
+        */
+       public BigInteger readValue(int varSize) throws CoreException {
+               IAddress theAddress = address;
+               if (!isRuntimeAddress) {
+                       theAddress = getRealAddress();
+               }
+               
+               ExecutionDMC exeDMC = DMContexts.getAncestorOfType(context, ExecutionDMC.class);
+               
+               Memory memoryService = tracker.getService(Memory.class);
+               ArrayList<MemoryByte> memBuffer = new ArrayList<MemoryByte>();
+               IStatus memGetStatus = memoryService.getMemory(exeDMC, theAddress, memBuffer, varSize, 1);
+               if (!memGetStatus.isOK()) {
+                       throw EDCDebugger.newCoreException(MessageFormat.format(
+                                       SymbolsMessages.MemoryVariableLocation_CannotReadAddrFormat, theAddress.toHexAddressString()));
+               }
+
+               // check each byte
+               for (int i = 0; i < memBuffer.size(); i++) {
+                       if (!memBuffer.get(i).isReadable())
+                               throw EDCDebugger.newCoreException(MessageFormat.format(
+                                       SymbolsMessages.MemoryVariableLocation_CannotReadAddrFormat, theAddress.add(i).getValue().toString(16)));
+               }
+
+               MemoryByte[] memArray = memBuffer.toArray(new MemoryByte[varSize]);
+               
+               return MemoryUtils.convertByteArrayToUnsignedLong(
+                               memArray, getEndian());
+       }
+
+       private int getEndian() {
+               ITargetEnvironment targetEnvironment = tracker.getService(ITargetEnvironment.class);
+               int endian = MemoryUtils.LITTLE_ENDIAN;
+               if (targetEnvironment != null)
+                       endian = targetEnvironment.isLittleEndian(context) ? MemoryUtils.LITTLE_ENDIAN : MemoryUtils.BIG_ENDIAN;
+               return endian;
+       }
+
+       /**
+        * @return
+        * @throws CoreException
+        */
+       private IAddress getRealAddress() throws CoreException {
+               IAddress theAddress = address;
+               if (!isRuntimeAddress) {
+                       StackFrameDMC frame = DMContexts.getAncestorOfType(context, StackFrameDMC.class);
+                       if (frame == null) 
+                               throw EDCDebugger.newCoreException(SymbolsMessages.MemoryVariableLocation_CannotFindFrame);
+                       theAddress = frame.getModule().toRuntimeAddress(theAddress);
+               }
+               return theAddress;
+       }
+       
+       public IVariableLocation addOffset(long offset) {
+               return new MemoryVariableLocation(tracker, context, 
+                               address.getValue().add(BigInteger.valueOf(offset)), isRuntimeAddress);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#getLocationName(org.eclipse.cdt.dsf.service.DsfServicesTracker)
+        */
+       public String getLocationName() {
+               if (!isRuntimeAddress) {
+                       try {
+                               return SymbolsMessages.MemoryVariableLocation_Hex + Long.toHexString(getRealAddress().getValue().longValue());
+                       } catch (CoreException e) {
+                               return SymbolsMessages.MemoryVariableLocation_Hex + Long.toHexString(address.getValue().longValue()) + SymbolsMessages.MemoryVariableLocation_LinkTime; // should not happen
+                       }
+               } else {
+                       return SymbolsMessages.MemoryVariableLocation_Hex + Long.toHexString(address.getValue().longValue());
+               }
+       }
+
+       public void writeValue(final int bytes, BigInteger value) throws CoreException {
+               final byte[] buffer = MemoryUtils.convertSignedBigIntToByteArray(value, getEndian(), bytes);
+               final IAddress theAddress = !isRuntimeAddress ? getRealAddress() : address;
+               final ExecutionDMC exeDMC = DMContexts.getAncestorOfType(context, ExecutionDMC.class);
+           final Memory memory = tracker.getService(Memory.class);
+               IStatus status = memory.setMemory(exeDMC, theAddress, 1, bytes, buffer);
+               if (!status.isOK()) {
+                       throw EDCDebugger.newCoreException(MessageFormat.format(
+                                       SymbolsMessages.MemoryVariableLocation_CannotWriteAddrFormat, theAddress.toHexAddressString()), status.getException());
+               }
+       }
+
+       public IDMContext getContext() {
+               return context;
+       }
+
+       public EDCServicesTracker getServicesTracker() {
+               return tracker;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ModuleLineEntryProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ModuleLineEntryProvider.java
new file mode 100644 (file)
index 0000000..5dc14f8
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.PathUtils;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.EDCLineAddresses;
+import org.eclipse.cdt.debug.edc.symbols.ICompileUnitScope;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider;
+import org.eclipse.cdt.debug.edc.symbols.IModuleLineEntryProvider;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * This class holds a conglomeration of line entry data for an entire
+ * module.  
+ */
+public class ModuleLineEntryProvider implements IModuleLineEntryProvider {
+       
+       /**
+        *      basically, a typedef of {@link ArrayList}&lt;{@link FileLineEntryProvider}&gt;
+        */
+       private final class FileLineEntryProviders extends ArrayList<FileLineEntryProvider> {
+               private static final long serialVersionUID = -2157263701372708990L;             
+       }
+
+       /**
+        *      basically, a typedef of {@link HashMap}&lt;{@link IPath},{@link FileLineEntryProvider}&gt;
+        */
+       private final class PathToLineEntryMap extends HashMap<IPath, FileLineEntryProviders> {
+               private static final long serialVersionUID = 7064789571684986782L;
+       }
+
+       // CUs we've already considered
+       private Set<ICompileUnitScope> parsedCUs = new HashSet<ICompileUnitScope>();
+       // mapping to find info for a given path
+       private PathToLineEntryMap pathToLineEntryMap = new PathToLineEntryMap();
+       // all known providers
+       private FileLineEntryProviders fileProviders = new FileLineEntryProviders();
+       // cached array of providers
+       private FileLineEntryProvider[] fileProviderArray;
+
+       public ModuleLineEntryProvider() {
+
+       }
+
+       
+       /**
+        * Add the line entries from a compilation unit to the mapper.
+        * @param scope
+        */
+       public void addCompileUnit(ICompileUnitScope cu) {
+               if (parsedCUs.contains(cu))
+                       return;
+               
+               parsedCUs.add(cu);
+               
+               Collection<ILineEntry> lineEntries = cu.getLineEntries();
+               
+               if (lineEntries.size() > 0) {
+                       // files created for this compile unit scope (union of all CUs in this.lineEntryMap)
+                       // (kept because we visit the same file a lot in this function)
+                       Map<IPath, FileLineEntryProvider> fileProviders = new HashMap<IPath, FileLineEntryProvider>(4);
+                       
+                       // go through each entry and extract entries for each file.
+                       //
+                       // allocate one FileLineEntryProvider per CU
+                       //
+                       for (ILineEntry entry : lineEntries) {
+                               IPath path = entry.getFilePath();
+                               
+                               FileLineEntryProvider provider = fileProviders.get(path);
+                               if (provider == null) {
+                                       // This will look for an existing one and create a 
+                                       // new one if none exits.
+                                       provider = getFileLineProviderForCU(cu, path);
+                                       provider.setCULineEntries(lineEntries);
+                                       fileProviders.put(path, provider);
+                               }
+       
+                               provider.addLineEntry(entry);
+                       }
+               }
+               
+               // then, look for lines provided by decl file/line/column entries
+               for (IScope child : cu.getChildren()) {
+                       addCompileUnitChild(cu, child);
+               }
+       }
+
+
+
+       /**
+        * Add (or update) a compile unit child entry (function) by adding a
+        * line entry for its declaration location, which may differ from the
+        * first line inside the function to which the low PC refers. 
+        * @param cu
+        * @param child
+        */
+       public void addCompileUnitChild(ICompileUnitScope cu, IScope child) {
+               if (child instanceof IFunctionScope) {
+                       IFunctionScope func = (IFunctionScope) child;
+                       IPath declFile = func.getDeclFile();
+                       
+                       if (declFile != null) {
+                               // this is the slow path for dynamic parsing
+                               FileLineEntryProvider provider
+                                 = getFileLineProviderForCU(cu, declFile);
+                               
+                               int declLine = func.getDeclLine();
+                               int declColumn = func.getDeclColumn();
+                               
+                               // is there already an entry at this line?
+                               Collection<ILineEntry> curEntries
+                                 = provider.getLineEntriesForLines(declFile, declLine, declLine);
+                               if (curEntries.isEmpty()) {
+                                       // no, add one, and make it range from our start to the first actual line
+                                       
+                                       LineEntry entry
+                                         = new LineEntry(declFile, declLine, declColumn,
+                                                                         func.getLowAddress(), func.getLowAddress());
+                                       provider.addLineEntry(entry);
+                               }
+                       }
+               }       
+       }
+
+
+       private FileLineEntryProvider getFileLineProviderForCU(
+                       ICompileUnitScope cu, IPath declFile) {
+               FileLineEntryProviders providers = pathToLineEntryMap.get(declFile);
+               if (providers != null) {
+                       for (FileLineEntryProvider p : providers) {
+                               if (p.getCU().equals(cu)) {
+                                       return p;
+                               }
+                       }
+               }
+               FileLineEntryProvider provider = new FileLineEntryProvider(cu, declFile);
+               registerFileLineEntryProvider(declFile, provider);
+               return provider;
+       }
+
+
+
+       private void registerFileLineEntryProvider(IPath path,
+                       FileLineEntryProvider provider) {
+               FileLineEntryProviders fileEntries = pathToLineEntryMap.get(path);
+               if (fileEntries == null) {
+                       fileEntries = new FileLineEntryProviders();
+                       pathToLineEntryMap.put(path, fileEntries);
+               }
+               fileEntries.add(provider);
+               fileProviders.add(provider);
+               fileProviderArray = null;
+       }
+       
+       /**
+        * Get the line entry providers for the given source file.  
+        * @path sourceFile the absolute path to the source file
+        * @return the unmodifiable list of providers for the file, possibly empty.
+        */
+       public Collection<ILineEntryProvider> getLineEntryProvidersForFile(IPath sourceFile) {
+               List<? extends ILineEntryProvider> cus = pathToLineEntryMap.get(sourceFile);
+               if (cus != null)
+                       return Collections.unmodifiableCollection(cus);
+               
+               for (Map.Entry<IPath, FileLineEntryProviders> entry : pathToLineEntryMap.entrySet()) {
+                       if (!PathUtils.isCaseSensitive() && entry.getKey().toOSString().compareToIgnoreCase(sourceFile.toOSString()) == 0) {
+                               cus = entry.getValue();
+                               pathToLineEntryMap.put(sourceFile, entry.getValue());
+                               return Collections.unmodifiableCollection(cus);
+                       }
+               }
+               
+               for (Map.Entry<IPath, FileLineEntryProviders> entry : pathToLineEntryMap.entrySet()) {
+                       if (entry.getKey().equals(sourceFile)) {
+                               cus = entry.getValue();
+                               return Collections.unmodifiableCollection(cus);
+                       }
+               }
+               
+               return Collections.emptyList();
+       }
+
+
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.ILineEntryProvider#getLineEntriesForLines(org.eclipse.core.runtime.IPath, int, int)
+        */
+       public Collection<ILineEntry> getLineEntriesForLines(IPath file,
+                       int startLineNumber, int endLineNumber) {
+               FileLineEntryProviders matches = pathToLineEntryMap.get(file);
+               if (matches == null)
+                       return Collections.emptyList();
+               
+               List<ILineEntry> ret = null;
+               for (FileLineEntryProvider provider : matches) {
+                       Collection<ILineEntry> entries
+                         = provider.getLineEntriesForLines(file, startLineNumber, endLineNumber);
+                       if (!entries.isEmpty()) {
+                               if (ret == null)
+                                       ret = new ArrayList<ILineEntry>(entries);
+                               else
+                                       ret.addAll(entries);
+                       }
+               }
+               if (ret == null)
+                       return Collections.emptyList();
+               
+               return ret;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.ILineEntryProvider#getLineEntryAtAddress(org.eclipse.cdt.core.IAddress)
+        */
+       public ILineEntry getLineEntryAtAddress(IAddress linkAddress) {
+               // scanning files can introduce new file providers; avoid ConcurrentModificationException
+               if (fileProviderArray == null) {
+                       fileProviderArray = fileProviders.toArray(new FileLineEntryProvider[fileProviders.size()]);
+               }
+               for (FileLineEntryProvider provider : fileProviderArray) {
+                       // Narrow down the search to avoid iterating potentially hundreds
+                       // of duplicates of the same file 
+                       // (e.g. for stl_vector.h, expanded N times for N std::vector<T> uses).
+                       // (Don't use #getScopeAtAddress() since this preparses too much.)
+                       if (provider.getCU().getLowAddress().compareTo(linkAddress) <= 0
+                                       && provider.getCU().getHighAddress().compareTo(linkAddress) > 0) {
+                               ILineEntry entry = provider.getLineEntryAtAddress(linkAddress);
+                               if (entry != null
+
+                                       /*      FIXME: sigh ...
+                                        *
+                                        *      yet another RVCT DWARF inlined LNT entry generation bug ...
+                                        *
+                                        *      we just can't have entry.highAddr == entry.lowAddr!
+                                        *
+                                        *      that just TOTALLY ruins the illusion of stepping.
+                                        *
+                                        *      see, if we pass back the address we're on,
+                                        *      no step-over range will get created,
+                                        *      and the debugger will just run ...
+                                        *              
+                                        *      ... and that's just NotGood-TM .
+                                        */
+                                               && !entry.getLowAddress().equals(entry.getHighAddress())
+
+                                               ) {
+                                       return entry;
+                               }
+                       }
+               }
+               return null;
+       }
+
+
+       public ILineEntry getLineEntryInFunction(IAddress linkAddress, IFunctionScope parentFunction) {
+               ILineEntry functionEntry = getLineEntryAtAddress(parentFunction.getLowAddress());
+               if (functionEntry == null)
+                       return null;
+               Collection<ILineEntryProvider> parentProviders
+                 = getLineEntryProvidersForFile(functionEntry.getFilePath());
+               for (ILineEntryProvider iLineEntryProvider : parentProviders) {
+                       if (iLineEntryProvider instanceof FileLineEntryProvider) {
+                               ILineEntry entry
+                                 = ((FileLineEntryProvider)iLineEntryProvider).getLineEntryInFunction(linkAddress, parentFunction);
+                               if (entry != null)
+                                       return entry;
+                       }
+               }
+               return null;
+       }
+
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.ILineEntryProvider#getNextLineEntry(org.eclipse.cdt.debug.edc.internal.symbols.ILineEntry)
+        */
+       public ILineEntry getNextLineEntry(final ILineEntry entry, final boolean collapseInlineFunctions) {
+               if (entry == null)
+                       return null;
+
+               final IAddress entryLowAddr = entry.getLowAddress();
+               final IAddress entryHighAddr = entry.getHighAddress();
+               final IPath entryPath = entry.getFilePath();
+               FileLineEntryProviders matches = pathToLineEntryMap.get(entryPath);
+               if (matches == null)
+                       return null;
+
+               // avoid possible concurrent access if we read new files while searching
+               FileLineEntryProvider[] matchArray = matches.toArray(new FileLineEntryProvider[matches.size()]);
+
+               for (FileLineEntryProvider provider : matchArray) {
+                       ICompileUnitScope cuScope = provider.getCU();
+                       // Narrow down the search to avoid iterating potentially hundreds of duplicates of the same file 
+                       // (e.g. for stl_vector.h, expanded N times for N std::vector<T> uses).
+                       // (Don't use #getScopeAtAddress() since this preparses too much.).
+                       if (cuScope.getLowAddress().compareTo(entryLowAddr) <= 0
+                                       // NOTE: high addrs for both scope & line entries are inclusive: thus >= 0
+                                       && cuScope.getHighAddress().compareTo(entryHighAddr) >= 0) {
+
+                               // provider.getNextLineEntry() returns null for only 1 reason:
+                               // 1) there are no more entries at all for the compileUnitScope
+                               //
+                               // so there's no need to continue looking in other providers
+                               return provider.getNextLineEntry(entry, collapseInlineFunctions);
+                       }
+               }
+
+               return null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.ILineEntryProvider#getPreviousLineEntry
+        */
+       public ILineEntry getPreviousLineEntry(ILineEntry entry,
+                       boolean collapseInlineFunctions) {
+               if (entry == null)
+                       return null;
+
+               FileLineEntryProviders matches = pathToLineEntryMap.get(entry.getFilePath());
+               if (matches != null) {
+                       final IAddress entryLowAddr  = entry.getLowAddress();
+                       final IAddress entryHighAddr = entry.getHighAddress();
+                       boolean entryIsInline = false, inlineEstablished = false;
+
+                       // avoid possible concurrent access if we read new files while searching
+                       FileLineEntryProvider[] matchArray = matches.toArray(new FileLineEntryProvider[matches.size()]);
+
+                       for (FileLineEntryProvider provider : matchArray) {
+                               ICompileUnitScope cuScope = provider.getCU();
+                               // Narrow down the search to avoid iterating potentially hundreds of duplicates of the same file 
+                               // (e.g. for stl_vector.h, expanded N times for N std::vector<T> uses).
+                               // (Don't use #getScopeAtAddress() since this preparses too much.).
+                               //
+                               // 
+                               if (cuScope.getLowAddress().compareTo(entryLowAddr) <= 0
+                                               // NOTE: high addrs for both scope & line entries are inclusive: thus >= 0
+                                               && cuScope.getHighAddress().compareTo(entryHighAddr) >= 0) {
+                                       if (!inlineEstablished) {
+                                               entryIsInline = FileLineEntryProvider.isInlinedFunction(cuScope.getFunctionAtAddress(entryLowAddr));
+                                               inlineEstablished = true;
+                                       }
+                                       ILineEntry prev = provider.getPreviousLineEntry(entry, collapseInlineFunctions);
+                                       if (prev == null && collapseInlineFunctions && entryIsInline) {
+                                               // retry with the provider mapped from the compileUnitScope.filePath
+                                               return provider.getPreviousLineEntryInCU(entry);
+                                       }
+
+                                       if (prev != null) {     // in case there's another provider
+                                               return prev;
+                                       }
+                               }
+                       }
+               }
+               return null;
+       }
+
+       /*
+        * (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider#findClosestLineWithCode(org.eclipse.core.runtime.IPath, int, int)
+        */
+       public List<ILineAddresses> findClosestLineWithCode(IPath sourceFile,
+                       int anchorLine, int neighbor_limit) {
+               List<ILineAddresses> ret = new ArrayList<ILineAddresses>(1);
+
+               /* Check all compile units in the module for code line.
+                 */ 
+               Collection<? extends ILineEntryProvider> fileProviders = 
+                       getLineEntryProvidersForFile(sourceFile);
+               if (fileProviders.isEmpty())
+                       return ret;
+
+               for (ILineEntryProvider fileProvider : fileProviders) {
+                       
+                       // Find code line in one CU using the source file
+                       List<ILineAddresses> la = fileProvider.findClosestLineWithCode(sourceFile, anchorLine, neighbor_limit);
+                       if (la.isEmpty())
+                               continue;
+                       assert (la.size() == 1);
+                       ILineAddresses newCodeLine = la.get(0);
+                       
+                       if (ret.isEmpty())
+                               ret.add(newCodeLine);
+                       else {
+                               boolean merged = false;
+                               for (ILineAddresses e : ret)
+                                       if (newCodeLine.getLineNumber() == e.getLineNumber()) {
+                                               ((EDCLineAddresses)e).addAddress(newCodeLine.getAddress());
+                                               merged = true;
+                                               break;
+                                       }
+                       
+                               if (!merged)
+                                       ret.add(newCodeLine);
+                       }
+               }
+               
+               return ret;
+       }
+
+
+       public boolean hasSourceFile(IPath sourceFile) {
+               Collection<? extends ILineEntryProvider> fileProviders = 
+                       getLineEntryProvidersForFile(sourceFile);
+               return fileProviders != null && ! fileProviders.isEmpty();
+       }
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/PointerType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/PointerType.java
new file mode 100644 (file)
index 0000000..4ba1294
--- /dev/null
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class PointerType extends MayBeQualifiedType implements IPointerType {
+
+       public PointerType(String name, IScope scope, int byteSize, Map<Object, Object> properties) {
+               super(name, scope, byteSize, properties);
+       }
+
+       // create an internal pointer for expression evaluation
+       public PointerType() {
+               super("", null, 0, null); //$NON-NLS-1$
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ReferenceType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ReferenceType.java
new file mode 100644 (file)
index 0000000..ce308d5
--- /dev/null
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class ReferenceType extends Type implements IReferenceType {
+       
+       public ReferenceType(String name, IScope scope, int byteSize, Map<Object, Object> properties) {
+               super(name, scope, byteSize, properties);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/RegisterOffsetVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/RegisterOffsetVariableLocation.java
new file mode 100644 (file)
index 0000000..b5cfd3b
--- /dev/null
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
+import org.eclipse.cdt.debug.edc.symbols.IRegisterOffsetVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+public class RegisterOffsetVariableLocation extends RegisterVariableLocation implements IRegisterOffsetVariableLocation {
+
+       protected final long offset;
+       private int addressSize;
+
+       public RegisterOffsetVariableLocation(EDCServicesTracker tracker, IDMContext context, String name, int id, long offset) {
+               super(tracker, context, name, id);
+               this.offset = offset;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.RegisterVariableLocation#toString()
+        */
+       @Override
+       public String toString() {
+               return super.toString() + " + " + getOffset(); //$NON-NLS-1$
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IRegisterOffsetVariableLocation#getOffset()
+        */
+       public long getOffset() {
+               return offset;
+       }
+       
+       public BigInteger readValue(int bytes) throws CoreException {
+               BigInteger regval = super.readValue(bytes);
+               return regval.add(BigInteger.valueOf(offset));
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.RegisterVariableLocation#addOffset(long)
+        */
+       @Override
+       public IVariableLocation addOffset(long offset) {
+               return new RegisterOffsetVariableLocation(tracker, context, name, id, offset + this.offset);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.RegisterVariableLocation#getLocationName(org.eclipse.cdt.dsf.service.DsfServicesTracker)
+        */
+       @Override
+       public String getLocationName() {
+               try {
+                       if (addressSize == 0) {
+                               addressSize = 4;
+                               ITargetEnvironment targetEnvironment = tracker.getService(ITargetEnvironment.class);
+                               if (targetEnvironment != null)
+                                       addressSize = targetEnvironment.getPointerSize();
+                       }
+                       BigInteger regval = super.readValue(addressSize);
+                       regval = regval.add(BigInteger.valueOf(offset));
+                       return SymbolsMessages.RegisterOffsetVariableLocation_Hex + Long.toHexString(regval.longValue());
+               } catch (CoreException e) {
+                       // fallback
+                       return super.getLocationName() + (offset < 0 ? SymbolsMessages.RegisterOffsetVariableLocation_Positive : SymbolsMessages.RegisterOffsetVariableLocation_Negative ) + Math.abs(offset);
+               }
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.RegisterVariableLocation#getAddress()
+        */
+       @Override
+       public IAddress getAddress() {
+               return null;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/RegisterVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/RegisterVariableLocation.java
new file mode 100644 (file)
index 0000000..439b504
--- /dev/null
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.services.Registers;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.symbols.IRegisterVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+public class RegisterVariableLocation implements IRegisterVariableLocation {
+
+       protected String name;
+       protected int id;
+       protected final IDMContext context;
+       protected final EDCServicesTracker tracker;
+
+       public RegisterVariableLocation(EDCServicesTracker tracker, IDMContext context, String name, int id) {
+               this.tracker = tracker;
+               this.context = context;
+               this.name = name;
+               this.id = id;
+               if (name == null) {
+                       Registers registerservice = tracker.getService(Registers.class);
+                       this.name = registerservice.getRegisterNameFromCommonID(getRegisterID());
+               } 
+       }
+       
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return getRegisterName() != null ? getRegisterName() : "R" + id + //$NON-NLS-1$
+                               (context instanceof StackFrameDMC && ((StackFrameDMC) context).getLevel() > 0 ?
+                                               " (level " + ((StackFrameDMC) context).getLevel() + ")" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+       }
+       
+       public String getRegisterName() {
+               return name;
+       }
+
+       public int getRegisterID() {
+               return id;
+       }
+
+       public BigInteger readValue(int bytes) throws CoreException {
+               if (context instanceof StackFrameDMC)
+                       return ((StackFrameDMC)context).getFrameRegisters().getRegister(id, bytes);
+               else
+                       throw EDCDebugger.newCoreException(SymbolsMessages.RegisterVariableLocation_CannotReadFramelessRegister);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#addOffset(long)
+        */
+       public IVariableLocation addOffset(long offset) {
+               return new RegisterOffsetVariableLocation(tracker, context, name, id, offset);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#getLocationName(org.eclipse.cdt.dsf.service.DsfServicesTracker)
+        */
+       public String getLocationName() {
+               return "$" + getRegisterName(); //$NON-NLS-1$
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#getAddress()
+        */
+       public IAddress getAddress() {
+               return null;
+       }
+       
+       public IDMContext getContext() {
+               return context;
+       }
+       
+       public EDCServicesTracker getServicesTracker()
+       {
+               return tracker;
+       }
+       public void writeValue(int bytes, BigInteger value) throws CoreException {
+               if (context instanceof StackFrameDMC)
+                       ((StackFrameDMC)context).getFrameRegisters().writeRegister(id, bytes, value);
+               else
+                       throw EDCDebugger.newCoreException(SymbolsMessages.RegisterVariableLocation_CannotWriteFramelessRegister);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/RuntimeSection.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/RuntimeSection.java
new file mode 100644 (file)
index 0000000..887fd17
--- /dev/null
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.text.MessageFormat;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+
+public class RuntimeSection implements IRuntimeSection {
+
+       private ISection section;
+       // the relocated address of the section at runtime
+       private IAddress runtimeAddress;
+
+       public RuntimeSection(ISection section) {
+               this.section = section;
+               // the section may not get relocted, so set the runtime
+               // address to be the link address
+               runtimeAddress = section.getLinkAddress();
+       }
+
+       public int getId() {
+               return section.getId();
+       }
+
+       public long getSize() {
+               return section.getSize();
+       }
+
+       public IAddress getLinkAddress() {
+               return section.getLinkAddress();
+       }
+
+       public Map<String, Object> getProperties() {
+               return section.getProperties();
+       }
+
+       public IAddress getRuntimeAddress() {
+               return runtimeAddress;
+       }
+
+       public void relocate(IAddress runtimeAddress) {
+               this.runtimeAddress = runtimeAddress;
+       }
+
+       @Override
+       public String toString() {
+               return MessageFormat.format("[sectionID={0}, link address={1}, runtime address={2}]", getId(), getLinkAddress().toHexAddressString(), //$NON-NLS-1$
+                               runtimeAddress.toHexAddressString());
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               RuntimeSection other = (RuntimeSection) obj;
+               if (!getLinkAddress().equals(other.getLinkAddress()))
+                       return false;
+               if (!getRuntimeAddress().equals(other.getRuntimeAddress()))
+                       return false;
+               if (getId() != other.getId())
+                       return false;
+               return true;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Scope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Scope.java
new file mode 100644 (file)
index 0000000..d404c3d
--- /dev/null
@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.RangeList;
+import org.eclipse.cdt.debug.edc.symbols.ICompileUnitScope;
+import org.eclipse.cdt.debug.edc.symbols.IEnumerator;
+import org.eclipse.cdt.debug.edc.symbols.IModuleScope;
+import org.eclipse.cdt.debug.edc.symbols.IRangeList;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+import org.eclipse.cdt.debug.edc.symbols.IRangeList.Entry;
+import org.eclipse.cdt.utils.Addr32;
+import org.eclipse.cdt.utils.Addr64;
+
+public abstract class Scope implements IScope {
+
+       protected String name;
+       protected IAddress lowAddress;
+       protected IAddress highAddress;
+       protected IScope parent;
+       protected List<IScope> children = new ArrayList<IScope>();
+       protected List<IVariable> variables = new ArrayList<IVariable>();
+       protected List<IEnumerator> enumerators = new ArrayList<IEnumerator>();
+       private TreeMap<IRangeList.Entry, IScope> addressToScopeMap;
+       
+       protected IRangeList rangeList;
+
+       public Scope(String name, IAddress lowAddress, IAddress highAddress, IScope parent) {
+               this.name = name;
+               this.lowAddress = lowAddress;
+               this.highAddress = highAddress;
+               this.parent = parent;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public IAddress getLowAddress() {
+               return lowAddress;
+       }
+
+       public IAddress getHighAddress() {
+               return highAddress;
+       }
+
+       /**
+        * Tell whether the address range for the scope is empty.
+        * @return flag
+        */
+       public boolean hasEmptyRange() {
+               return (lowAddress == null || highAddress == null)
+               || (lowAddress.isZero() && highAddress.isZero())
+               || (lowAddress.getValue().longValue() == -1 && highAddress.isZero()); // TODO: remove this case
+       }
+
+       /**
+        * Return the list of non-contiguous ranges for this scope.
+        * @return list or <code>null</code>
+        */
+       public IRangeList getRangeList() {
+               return rangeList;
+       }
+
+       public void setLowAddress(IAddress lowAddress) {
+               this.lowAddress = lowAddress;
+       }
+
+       public void setHighAddress(IAddress highAddress) {
+               this.highAddress = highAddress;
+       }
+
+       public void setRangeList(IRangeList ranges) {
+               this.rangeList = ranges;
+               setLowAddress(new Addr32(rangeList.getLowAddress()));
+               setHighAddress(new Addr32(rangeList.getHighAddress()));
+       }
+       
+       public IScope getParent() {
+               return parent;
+       }
+
+       public Collection<IScope> getChildren() {
+               return Collections.unmodifiableCollection(children);
+       }
+
+       public Collection<IVariable> getVariables() {
+               return Collections.unmodifiableCollection(variables);
+       }
+
+       public Collection<IEnumerator> getEnumerators() {
+               return Collections.unmodifiableCollection(enumerators);
+       }
+
+       public IScope getScopeAtAddress(IAddress linkAddress) {
+               // see if it's in this scope
+               if (linkAddress.compareTo(lowAddress) >= 0 && linkAddress.compareTo(highAddress) < 0) {
+                       
+                       ensureScopeRangeLookup();
+                       
+                       long addr = linkAddress.getValue().longValue();
+                       IRangeList.Entry addressEntry = new IRangeList.Entry(addr, addr);
+                       SortedMap<Entry,IScope> tailMap = addressToScopeMap.tailMap(addressEntry);
+                       
+                       if (tailMap.isEmpty())
+                               return this;
+                       
+                       IScope child = tailMap.values().iterator().next();
+                       if (linkAddress.compareTo(child.getLowAddress()) >= 0 
+                                       && linkAddress.compareTo(child.getHighAddress()) < 0) {
+                               return child.getScopeAtAddress(linkAddress);
+                       }
+                       
+                       return this;
+               }
+
+               return null;
+       }
+
+       /**
+        * Make sure our mapping of address range to scope is valid. 
+        */
+       private void ensureScopeRangeLookup() {
+               if (addressToScopeMap == null) {
+                       addressToScopeMap = new TreeMap<Entry, IScope>();
+                       
+                       for (IScope scope : children) {
+                               addScopeRange(scope);
+                       }
+                       //System.out.println("Mapping for " + getName()+ ": "+ addressToScopeMap.size() + " entries");
+               }
+       }
+
+       /**
+        * @param scope
+        */
+       private void addScopeRange(IScope scope) {
+               IRangeList ranges = scope.getRangeList();
+               if (ranges != null) {
+                       for (IRangeList.Entry entry : ranges) {
+                               addressToScopeMap.put(entry, scope);
+                       }
+               } else {
+                       addressToScopeMap.put(new IRangeList.Entry(
+                                               scope.getLowAddress().getValue().longValue(), 
+                                               scope.getHighAddress().getValue().longValue()),
+                                       scope);
+               }
+       }
+
+       /**
+        * Adds the given scope as a child of this scope
+        * 
+        * @param scope
+        */
+       public void addChild(IScope scope) {
+               children.add(scope);
+               if (addressToScopeMap != null) {
+                       addScopeRange(scope);
+               }
+       }
+
+       /**
+        * Adds the given variable to this scope
+        * 
+        * @param variable
+        */
+       public void addVariable(IVariable variable) {
+               variables.add(variable);
+       }
+
+       /**
+        * Adds the given variable to this scope
+        * 
+        * @param variable
+        */
+       public void addEnumerator(IEnumerator enumerator) {
+               enumerators.add(enumerator);
+       }
+
+       public int compareTo(Object o) {
+               if (o instanceof IScope) {
+                       return lowAddress.compareTo(((IScope) o).getLowAddress());
+               } else if (o instanceof IAddress) {
+                       return lowAddress.compareTo(o);
+               }
+               return 0;
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append("Scope ["); //$NON-NLS-1$
+               if (rangeList != null) {
+                       builder.append("ranges="); //$NON-NLS-1$
+                       builder.append(rangeList);
+               } else {
+                       builder.append("lowAddress="); //$NON-NLS-1$
+                       builder.append(lowAddress != null ? lowAddress.toHexAddressString() : "null");
+                       builder.append(", highAddress="); //$NON-NLS-1$
+                       builder.append(highAddress != null ? highAddress.toHexAddressString() : "null");
+               }
+               builder.append(", "); //$NON-NLS-1$
+               if (name != null) {
+                       builder.append("name="); //$NON-NLS-1$
+                       builder.append(name);
+                       builder.append(", "); //$NON-NLS-1$
+               }
+               builder.append("]"); //$NON-NLS-1$
+               return builder.toString();
+       }
+
+       public void fixupRanges(IAddress baseAddress) {
+               // compile unit scopes not generated by the compiler so
+               // figure it out from the functions
+               IAddress newLowAddress = Addr64.MAX;
+               IAddress newHighAddress = Addr64.ZERO;
+               boolean any = false;
+               
+               for (IScope kid : getChildren()) {
+                       // the compiler may generate (bad) low/high pc's which are not
+                       // in the actual module space for some functions. to work
+                       // around this, only honor addresses that are above the
+                       // actual link address
+                       if (kid.hasEmptyRange()) {
+                               continue;
+                       }
+                       
+                       if (kid.getLowAddress().compareTo(baseAddress) > 0) {
+                               if (kid.getLowAddress().compareTo(newLowAddress) < 0) {
+                                       newLowAddress = kid.getLowAddress();
+                                       any = true;
+                               }
+
+                               if (kid.getHighAddress().compareTo(newHighAddress) > 0) {
+                                       newHighAddress = kid.getHighAddress();
+                                       any = true;
+                               }
+                       }
+               }
+
+               if (any) {
+                       //System.out.println("Needed to fix up ranges for " + getName());
+                       lowAddress = newLowAddress; 
+                       highAddress = newHighAddress;
+                       rangeList = null;
+               } else {
+                       if (lowAddress == null) {
+                               lowAddress = highAddress = Addr32.ZERO;
+                       }
+               }
+       }
+       
+       /**
+        * Merge the code range(s) from the given scope into this one.
+        * @param scope
+        */
+       protected void mergeScopeRange(IScope scope) {
+               if (hasEmptyRange()) {
+                       // copy range
+                       if (scope.getRangeList() != null) {
+                               setRangeList(scope.getRangeList());
+                       } else {
+                               setLowAddress(scope.getLowAddress());
+                               setHighAddress(scope.getHighAddress());
+                       }
+               } else {
+                       if (scope.getLowAddress() != null && scope.getLowAddress().compareTo(lowAddress) < 0
+                                       && !scope.getLowAddress().isZero())             // ignore random 0 entries 
+                       {
+                               if (rangeList != null) {
+                                       if (scope.getRangeList() != null) {
+                                               // TODO: merge properly
+                                               rangeList = null;
+                                       } else {
+                                               ((RangeList)rangeList).addLowRange(scope.getLowAddress().getValue().longValue());
+                                       }
+                               }
+                               lowAddress = scope.getLowAddress();
+                       }
+                       if (scope.getHighAddress() != null && scope.getHighAddress().compareTo(highAddress) > 0) {
+                               if (rangeList != null) {
+                                       if (scope.getRangeList() != null) {
+                                               // TODO: merge properly
+                                               rangeList = null;
+                                       } else {
+                                               ((RangeList)rangeList).addHighRange(scope.getHighAddress().getValue().longValue());
+                                       }
+                               }
+                               highAddress = scope.getHighAddress();
+                       }       
+               }
+       }
+       
+       protected void addLineInfoToParent(IScope scope) {
+               IScope cu = parent;
+               while (cu != null) {
+                       if (cu instanceof ICompileUnitScope && cu.getParent() instanceof IModuleScope) {
+                               IModuleScope module = (IModuleScope) cu.getParent();
+                               ModuleLineEntryProvider provider = (ModuleLineEntryProvider) module.getModuleLineEntryProvider();
+                               provider.addCompileUnitChild((ICompileUnitScope) cu, scope);
+                               break;
+                       }
+                       cu = cu.getParent();
+               }
+       }
+
+       /**
+        * 
+        */
+       public void dispose() {
+               for (IScope scope : children)
+                       scope.dispose();
+               children.clear();
+               for (IVariable var : variables)
+                       var.dispose();
+               variables.clear();
+               enumerators.clear();
+               if (addressToScopeMap != null)
+                       addressToScopeMap.clear();
+               rangeList = null;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Section.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Section.java
new file mode 100644 (file)
index 0000000..222be38
--- /dev/null
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+
+public class Section implements ISection {
+
+       private final int id;
+
+       private final long size;
+
+       // the address generated by the linker
+       private final IAddress linkAddress;
+
+       private final Map<String, Object> properties;
+
+       public Section(int id, long size, IAddress linkAddress, Map<String, Object> properties) {
+               this.id = id;
+               this.size = size;
+               this.linkAddress = linkAddress;
+               this.properties = new HashMap<String, Object>(properties); // make a
+                                                                                                                                       // copy
+       }
+
+       public int getId() {
+               return id;
+       }
+
+       public long getSize() {
+               return size;
+       }
+
+       public IAddress getLinkAddress() {
+               return linkAddress;
+       }
+
+       public Map<String, Object> getProperties() {
+               return properties;
+       }
+
+       @Override
+       public String toString() {
+               return MessageFormat.format("[sectionID={0}, link address={1}]", id, linkAddress.toHexAddressString()); //$NON-NLS-1$);
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               Section other = (Section) obj;
+               if (linkAddress != other.linkAddress)
+                       return false;
+               if (id != other.id)
+                       return false;
+               return true;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/StructType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/StructType.java
new file mode 100644 (file)
index 0000000..78c07b3
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class StructType extends CompositeType {
+
+       public StructType(String name, IScope scope, int byteSize, Map<Object, Object> properties) {
+               super(name, scope, ICompositeType.k_struct, byteSize, properties, "struct"); //$NON-NLS-1$
+       }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/SubroutineType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/SubroutineType.java
new file mode 100644 (file)
index 0000000..37c1b2f
--- /dev/null
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class SubroutineType extends Type implements ISubroutineType {
+
+       public SubroutineType(IScope scope, Map<Object, Object> properties) {
+               super("", scope, 0, properties); //$NON-NLS-1$
+       }
+
+       // create an internal pointer for expression evaluation
+       public SubroutineType() {
+               super("", null, 0, null); //$NON-NLS-1$
+       }
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Symbol.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Symbol.java
new file mode 100644 (file)
index 0000000..ed6de1b
--- /dev/null
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.symbols.ISymbol;
+
+public class Symbol implements ISymbol {
+
+       protected String name;
+       protected IAddress address;
+       protected long size;
+
+       public Symbol(String name, IAddress address, long size) {
+               this.name = name;
+               this.address = address;
+               this.size = size;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public IAddress getAddress() {
+               return address;
+       }
+
+       public long getSize() {
+               return size;
+       }
+
+       public int compareTo(Object o) {
+               if (o instanceof Symbol) {
+                       return address.compareTo(((Symbol) o).address);
+               } else if (o instanceof IAddress) {
+                       return address.compareTo(o);
+               }
+               return 0;
+       }
+       
+       @Override
+       public String toString() {
+               return "name=" + name + //$NON-NLS-1$
+                               ", address=0x" + Long.toHexString(address.getValue().longValue()) + //$NON-NLS-1$
+                               ", size=" + size; //$NON-NLS-1$
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/SymbolsMessages.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/SymbolsMessages.java
new file mode 100644 (file)
index 0000000..928d1cc
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.osgi.util.NLS;
+
+public class SymbolsMessages extends NLS {
+       private static final String BUNDLE_NAME = "org.eclipse.cdt.debug.edc.internal.symbols.SymbolsMessages"; //$NON-NLS-1$
+
+       public static String InvalidVariableLocation_CannotWriteInvalidLocation;
+
+       public static String MemoryVariableLocation_CannotFindFrame;
+       public static String MemoryVariableLocation_CannotReadAddrFormat;
+       public static String MemoryVariableLocation_CannotWriteAddrFormat;
+       public static String MemoryVariableLocation_Hex;
+       public static String MemoryVariableLocation_LinkTime;
+
+       public static String RegisterOffsetVariableLocation_Hex;
+       public static String RegisterOffsetVariableLocation_Negative;
+       public static String RegisterOffsetVariableLocation_Positive;
+       public static String RegisterVariableLocation_CannotReadFramelessRegister;
+       public static String RegisterVariableLocation_CannotWriteFramelessRegister;
+
+       public static String ValueVariableLocation_CannotModifyDerivedValue;
+       public static String ValueVariableLocation_NoValueAvailable;
+
+       static {
+               // initialize resource bundle
+               NLS.initializeMessages(BUNDLE_NAME, SymbolsMessages.class);
+       }
+
+       private SymbolsMessages() {
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/SymbolsMessages.properties b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/SymbolsMessages.properties
new file mode 100644 (file)
index 0000000..d0695c4
--- /dev/null
@@ -0,0 +1,23 @@
+###############################################################################
+# Copyright (c) 2010 Nokia and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Nokia - Initial API and implementation
+###############################################################################
+InvalidVariableLocation_CannotWriteInvalidLocation=Can't write to an invalid variable location
+MemoryVariableLocation_CannotFindFrame=Cannot find frame
+MemoryVariableLocation_CannotReadAddrFormat=cannot read address {0}
+MemoryVariableLocation_CannotWriteAddrFormat=cannot write address {0}
+MemoryVariableLocation_Hex=0x
+MemoryVariableLocation_LinkTime=\ (link time)
+RegisterOffsetVariableLocation_Hex=0x
+RegisterOffsetVariableLocation_Negative=\ - 
+RegisterOffsetVariableLocation_Positive=\ + 
+RegisterVariableLocation_CannotReadFramelessRegister=cannot read register without frame
+RegisterVariableLocation_CannotWriteFramelessRegister=cannot write register without frame
+ValueVariableLocation_CannotModifyDerivedValue=cannot modify derived value
+ValueVariableLocation_NoValueAvailable=no value available
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/TemplateParamType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/TemplateParamType.java
new file mode 100644 (file)
index 0000000..1a549e7
--- /dev/null
@@ -0,0 +1,72 @@
+/*******************************************************************************
+
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
+
+public class TemplateParamType implements ITemplateParam {
+
+       final String name;
+       IType type;
+       
+       public TemplateParamType(String name, IType type) {
+               this.name = name;
+               this.type = type;
+       }
+
+       public String getName() {
+               if (name == null || name.length() == 0) {
+                       getType();
+                       return TypeUtils.getFullTypeName(type);
+               } else {
+                       return this.name;
+               }
+       }
+
+       public IType getType() {
+               if (this.type instanceof IForwardTypeReference) {
+                       this.type = ((IForwardTypeReference) this.type).getReferencedType();
+               }
+
+               IType nextType = this.type;
+               while (nextType != null) {
+                       if (nextType instanceof IForwardTypeReference)
+                               nextType = ((IForwardTypeReference) nextType).getReferencedType();
+                       nextType = nextType.getType();
+               }
+               
+               return this.type;
+       }
+
+       public IScope getScope() {
+               return null;
+       }
+
+       public int getByteSize() {
+               return 0;
+       }
+
+       public Map<Object, Object> getProperties() {
+               return null;
+       }
+
+       public void setType(IType type) {
+       }
+
+       public void dispose() {
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Type.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Type.java
new file mode 100644 (file)
index 0000000..5204c57
--- /dev/null
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+
+public class Type implements IType {
+
+       /** This property key maps to an {@link IForwardTypeReference} object */
+       public static final String TYPE_REFERENCE = "type_reference"; //$NON-NLS-1$
+       
+       protected String name;
+       protected IScope scope;
+       protected int byteSize;
+       protected IType type; // subtype, if any, maybe IForwardTypeReference
+       protected Map<Object, Object> properties;       // may be null
+
+       public Type(String name, IScope scope, int byteSize, Map<Object, Object> properties) {
+               this.name = name;
+               this.scope = scope;
+               this.byteSize = byteSize;
+               this.properties = properties;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IType#dispose()
+        */
+       public void dispose() {
+               properties = null;
+               scope = null;
+               type = null;
+       }
+       
+       public String getName() {
+               return name;
+       }
+
+       public IScope getScope() {
+               return scope;
+       }
+
+       public int getByteSize() {
+               return byteSize;
+       }
+
+       public Map<Object, Object> getProperties() {
+               return properties;
+       }
+
+       public IType getType() {
+               if (type == null && properties != null) {
+                       type = (IType) properties.get(TYPE_REFERENCE);
+               }
+               if (type instanceof IForwardTypeReference) {
+                       type = ((IForwardTypeReference) type).getReferencedType();
+               }
+               return type;
+       }
+
+       public void setType(IType type) {
+               this.type = type;
+       }
+
+       public void setScope(IScope scope) {
+               this.scope = scope;
+       }
+       
+       protected int updateByteSizeFromSubType() {
+               if (byteSize == 0) {
+                       IType theType = getType();
+                       if (theType != null)
+                               byteSize = theType.getByteSize();
+               }
+               return byteSize;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/TypedefType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/TypedefType.java
new file mode 100644 (file)
index 0000000..abb1f53
--- /dev/null
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class TypedefType extends MayBeQualifiedType implements ITypedef {
+
+       public TypedefType(String name, IScope scope, Map<Object, Object> properties) {
+               super(name, scope, 0, properties);
+       }
+
+       @Override
+       public String getName() {
+               return name;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Type#getByteSize()
+        */
+       @Override
+       public int getByteSize() {
+               return updateByteSizeFromSubType();
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/UnionType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/UnionType.java
new file mode 100644 (file)
index 0000000..1719eb3
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+public class UnionType extends CompositeType {
+
+       public UnionType(String name, IScope scope, int byteSize, Map<Object, Object> properties) {
+               super(name, scope, ICompositeType.k_union, byteSize, properties, "union"); //$NON-NLS-1$
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ValueVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ValueVariableLocation.java
new file mode 100644 (file)
index 0000000..2f00934
--- /dev/null
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.symbols.IValueVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * This is an actual value, calculated from somewhere, which does not have a location.
+ */
+public class ValueVariableLocation implements IValueVariableLocation {
+
+       private BigInteger value;
+
+       public ValueVariableLocation(BigInteger value) {
+               this.value = value;
+       }
+
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return "0x" + Long.toHexString(value.longValue()); //$NON-NLS-1$
+       }
+       
+       
+       public BigInteger readValue(int bytes) throws CoreException {
+               if (value == null)
+                       throw EDCDebugger.newCoreException(SymbolsMessages.ValueVariableLocation_NoValueAvailable);
+               return value;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#addOffset(long)
+        */
+       public IVariableLocation addOffset(long offset) {
+               return new ValueVariableLocation(value.add(BigInteger.valueOf(offset)));
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#getLocationName(org.eclipse.cdt.dsf.service.DsfServicesTracker)
+        */
+       public String getLocationName() {
+               return ""; //$NON-NLS-1$
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariableLocation#getAddress()
+        */
+       public IAddress getAddress() {
+               return null;
+       }
+
+       public void writeValue(int bytes, BigInteger value) throws CoreException {
+               throw EDCDebugger.newCoreException(SymbolsMessages.ValueVariableLocation_CannotModifyDerivedValue);
+       }
+
+       public IDMContext getContext() {
+               return null;
+       }
+
+       public EDCServicesTracker getServicesTracker() {
+               return null;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Variable.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Variable.java
new file mode 100644 (file)
index 0000000..f7d66db
--- /dev/null
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+import org.eclipse.core.runtime.IPath;
+
+
+public class Variable implements IVariable {
+
+       protected String name;
+       protected IScope scope;
+       protected IType type;
+       protected ILocationProvider locationProvider;
+       protected long startScope;
+       protected boolean isDeclared;
+       protected IPath definingFile;
+
+       
+       public Variable(String name, IScope scope, IType type, ILocationProvider locationProvider, boolean isDeclared, IPath definingFile) {
+               this.name = name;
+               this.scope = scope;
+               this.type = type;
+               this.locationProvider = locationProvider;
+               this.isDeclared = isDeclared;
+               this.definingFile = definingFile;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IVariable#dispose()
+        */
+       public void dispose() {
+               type = null;
+               locationProvider = null;
+               scope = null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IVariable#getName()
+        */
+       public String getName() {
+               return name;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IVariable#getScope()
+        */
+       public IScope getScope() {
+               return scope;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IVariable#getType()
+        */
+       public IType getType() {
+               if (type instanceof IForwardTypeReference)
+                       type = ((IForwardTypeReference) type).getReferencedType();
+               
+               return type;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IVariable#getLocationProvider()
+        */
+       public ILocationProvider getLocationProvider() {
+               return locationProvider;
+       }
+
+       public void setStartScope(long start) {
+               this.startScope = start;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IVariable#getStartScope()
+        */
+       public long getStartScope() {
+               return startScope;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IVariable#isDeclared()
+        */
+       public boolean isDeclared() {
+               return isDeclared;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IVariable#getDefiningFile()
+        */
+       public IPath getDefiningFile() {
+               return definingFile;
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append("Var ["); //$NON-NLS-1$
+               if (name != null) {
+                       builder.append(name);
+               }
+               if (scope != null) {
+                       builder.append(", "); //$NON-NLS-1$
+                       builder.append("scope="); //$NON-NLS-1$
+                       builder.append(scope.getName());
+               }
+               builder.append("]"); //$NON-NLS-1$
+               return builder.toString();
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/VolatileType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/VolatileType.java
new file mode 100644 (file)
index 0000000..1757625
--- /dev/null
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols;
+
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+
+/**
+ * Pseudo-type that represents the volatile qualifier
+ */
+public class VolatileType extends Type implements IQualifierType {
+
+       public VolatileType(IScope scope, Map<Object, Object> properties) {
+               super("volatile", scope, 0, properties); //$NON-NLS-1$
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Type#getByteSize()
+        */
+       @Override
+       public int getByteSize() {
+               return updateByteSizeFromSubType();
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfCompileUnit.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfCompileUnit.java
new file mode 100644 (file)
index 0000000..203fb99
--- /dev/null
@@ -0,0 +1,291 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.symbols.CompileUnitScope;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.AttributeList;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.CompilationUnitHeader;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.debug.edc.symbols.IModuleScope;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+import org.eclipse.core.runtime.IPath;
+
+public class DwarfCompileUnit extends CompileUnitScope {
+
+       protected DwarfDebugInfoProvider provider;
+       protected AttributeList attributes;
+       private List<IPath> fileList;
+       private boolean rangesDirty;
+
+       // computation unit header
+       protected final CompilationUnitHeader header;
+       
+       // whether the computation unit has been parsed to find variables and children with address ranges
+       protected boolean parsedForVarsAndAddresses = false;
+       
+       // whether the computation unit has been parsed to find types
+       protected boolean parsedForTypes = false;
+
+       
+       public DwarfCompileUnit(DwarfDebugInfoProvider provider, IModuleScope parent, IPath filePath,
+                       IAddress lowAddress, IAddress highAddress, CompilationUnitHeader header, boolean hasChildren,
+                       AttributeList attributes) {
+               super(filePath, parent, lowAddress, highAddress);
+
+               this.provider = provider;
+               this.attributes = attributes;
+               this.header = header;
+               
+               // if there are no children, say the children have been parsed
+               if (!hasChildren) {
+                       this.parsedForVarsAndAddresses = true;
+                       this.parsedForTypes = true;
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.lang.Object#hashCode()
+        */
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 1;
+               result = prime * result + header.debugInfoOffset;
+               result = prime * result + provider.getSymbolFile().hashCode();
+               return result;
+       }
+
+       /* (non-Javadoc)
+        * @see java.lang.Object#equals(java.lang.Object)
+        */
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               DwarfCompileUnit other = (DwarfCompileUnit) obj;
+               if (header.debugInfoOffset != other.header.debugInfoOffset)
+                       return false;
+               if (!provider.getSymbolFile().equals(other.provider.getSymbolFile()))
+                       return false;
+               return true;
+       }
+
+       public AttributeList getAttributeList() {
+               return attributes;
+       }
+       
+       @Override
+       protected Collection<ILineEntry> parseLineTable() {
+               DwarfInfoReader reader = new DwarfInfoReader(provider);
+               fileList = new ArrayList<IPath>();
+               return reader.parseLineTable(this, attributes, fileList);
+       }
+       
+       public void setLowAddress(IAddress address) {
+               this.lowAddress = address;
+       }
+
+       public void setHighAddress(IAddress address) {
+               this.highAddress = address;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getLowAddress()
+        */
+       @Override
+       public IAddress getLowAddress() {
+               // the address is known in the compile unit tag;
+               // if anything inside is outside that range, it's a bug.
+               return super.getLowAddress();
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getHighAddress()
+        */
+       @Override
+       public IAddress getHighAddress() {
+               // the address is known in the compile unit tag;
+               // if anything inside is outside that range, it's a bug.
+               return super.getHighAddress();
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.CompileUnitScope#getFunctionAtAddress(org.eclipse.cdt.core.IAddress)
+        */
+       @Override
+       public IFunctionScope getFunctionAtAddress(IAddress linkAddress) {
+               if (rangesDirty) {
+                       fixupRanges();
+               }
+               ensureParsedForAddresses();
+               return super.getFunctionAtAddress(linkAddress);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.CompileUnitScope#getFunctions()
+        */
+       @Override
+       public Collection<IFunctionScope> getFunctions() {
+               ensureParsedForAddresses();
+               return super.getFunctions();
+       }
+       
+       /**
+        * For compilers that don't generate compile unit scopes, e.g. GCCE with
+        * dlls, this fixes up the low and high addresses of the compile unit based
+        * on the function scopes
+        */
+       protected void fixupRanges() {
+               
+               // fix up scope addresses in case compiler doesn't generate them.
+               if (hasEmptyRange() && parsedForVarsAndAddresses) {
+                       fixupRanges(provider.getBaseLinkAddress());
+               }
+
+               rangesDirty = false;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getChildren()
+        */
+       @Override
+       public Collection<IScope> getChildren() {
+               return super.getChildren();
+       }
+       
+       public void setAttributes(AttributeList attributes) {
+               this.attributes = attributes;
+       }
+
+       public boolean isParsedForAddresses() {
+               return parsedForVarsAndAddresses;
+       }
+
+       public boolean isParsedForVariables() {
+               return parsedForVarsAndAddresses;
+       }
+
+       public boolean isParsedForTypes() {
+               return parsedForTypes;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getVariables()
+        */
+       @Override
+       public Collection<IVariable> getVariables() {
+               ensureParsedForVariables();
+               return super.getVariables();
+       }
+
+       public void setParsedForAddresses(boolean parsedForAddresses) {
+               this.parsedForVarsAndAddresses = parsedForAddresses;
+       }
+
+       public void setParsedForVariables(boolean parsedForVariables) {
+               this.parsedForVarsAndAddresses = parsedForVariables;
+       }
+
+       public void setParsedForTypes(boolean parsedForTypes) {
+               this.parsedForTypes = parsedForTypes;
+       }
+
+       private void ensureParsedForAddresses() {
+               if (!parsedForVarsAndAddresses) {
+                       DwarfInfoReader reader = new DwarfInfoReader(provider);
+                       reader.parseCompilationUnitForAddresses(this);
+               }
+       }
+       
+       /**
+        * Get the file path for a file number
+        * @param declFileNum
+        * @return IPath for the file, or <code>null</code>
+        */
+       public IPath getFileEntry(int declFileNum) {
+               if (fileList == null)
+                       parseLineTable();
+               if (declFileNum <= 0 || declFileNum > fileList.size())
+                       return null;
+               return fileList.get(declFileNum - 1);
+       }
+       
+       private void ensureParsedForVariables() {
+               if (!parsedForVarsAndAddresses) {
+                       DwarfInfoReader reader = new DwarfInfoReader(provider);
+                       reader.parseCompilationUnitForAddresses(this);
+               }
+       }
+       
+       @Override
+       public IScope getScopeAtAddress(IAddress linkAddress) {
+               ensureParsedForAddresses();
+               return super.getScopeAtAddress(linkAddress);
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append("DwarfCompileUnit [");
+               
+               builder.append("SymFile=");
+               builder.append(provider.getSymbolFile().lastSegment());
+               
+               builder.append(", SectionOffset=0x");
+               builder.append(Integer.toHexString(header.debugInfoOffset));
+               
+               builder.append(", lowAddr=");
+               builder.append(lowAddress != null ? lowAddress.toHexAddressString() : null);
+               
+               builder.append(", highAddr=");
+               builder.append(highAddress != null ? highAddress.toHexAddressString() : null);
+               if (filePath != null) {
+                       builder.append(", path=");
+                       builder.append(filePath.toOSString());
+               }
+               builder.append(", parsedForVarsAndAddresses=");
+               builder.append(parsedForVarsAndAddresses);
+               builder.append(", parsedForTypes=");
+               builder.append(parsedForTypes);
+               builder.append("]\n");
+               return builder.toString();
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#addChild(org.eclipse.cdt.debug.edc.internal.symbols.IScope)
+        */
+       @Override
+       public void addChild(IScope scope) {
+               super.addChild(scope);
+               
+               // if we don't know our scope yet...
+               if (hasEmptyRange()) {
+                       rangesDirty = true;
+               } else {
+                       // the CU may have an incomplete idea of its scope; fit the new scope in
+                       mergeScopeRange(scope);
+               }
+
+               addLineInfoToParent(scope);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfConstants.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfConstants.java
new file mode 100644 (file)
index 0000000..11512e1
--- /dev/null
@@ -0,0 +1,636 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+/**
+ * DWARF constant.
+ */
+public class DwarfConstants {
+
+       /* Tags. */
+
+       public final static int DW_TAG_array_type = 0x01;
+       public final static int DW_TAG_class_type = 0x02;
+       public final static int DW_TAG_entry_point = 0x03;
+       public final static int DW_TAG_enumeration_type = 0x04;
+       public final static int DW_TAG_formal_parameter = 0x05;
+       public final static int DW_TAG_imported_declaration = 0x08;
+       public final static int DW_TAG_label = 0x0a;
+       public final static int DW_TAG_lexical_block = 0x0b;
+       public final static int DW_TAG_member = 0x0d;
+       public final static int DW_TAG_pointer_type = 0x0f;
+       public final static int DW_TAG_reference_type = 0x10;
+       public final static int DW_TAG_compile_unit = 0x11;
+       public final static int DW_TAG_string_type = 0x12;
+       public final static int DW_TAG_structure_type = 0x13;
+       public final static int DW_TAG_subroutine_type = 0x15;
+       public final static int DW_TAG_typedef = 0x16;
+       public final static int DW_TAG_union_type = 0x17;
+       public final static int DW_TAG_unspecified_parameters = 0x18;
+       public final static int DW_TAG_variant = 0x19;
+       public final static int DW_TAG_common_block = 0x1a;
+       public final static int DW_TAG_common_inclusion = 0x1b;
+       public final static int DW_TAG_inheritance = 0x1c;
+       public final static int DW_TAG_inlined_subroutine = 0x1d;
+       public final static int DW_TAG_module = 0x1e;
+       public final static int DW_TAG_ptr_to_member_type = 0x1f;
+       public final static int DW_TAG_set_type = 0x20;
+       public final static int DW_TAG_subrange_type = 0x21;
+       public final static int DW_TAG_with_stmt = 0x22;
+       public final static int DW_TAG_access_declaration = 0x23;
+       public final static int DW_TAG_base_type = 0x24;
+       public final static int DW_TAG_catch_block = 0x25;
+       public final static int DW_TAG_const_type = 0x26;
+       public final static int DW_TAG_constant = 0x27;
+       public final static int DW_TAG_enumerator = 0x28;
+       public final static int DW_TAG_file_type = 0x29;
+       public final static int DW_TAG_friend = 0x2a;
+       public final static int DW_TAG_namelist = 0x2b;
+       public final static int DW_TAG_namelist_item = 0x2c;
+       public final static int DW_TAG_packed_type = 0x2d;
+       public final static int DW_TAG_subprogram = 0x2e;
+       public final static int DW_TAG_template_type_param = 0x2f; // called DW_TAG_template_type_parameter in DWARF 3
+       public final static int DW_TAG_template_value_param = 0x30; // called DW_TAG_template_value_parameter in DWARF 3
+       public final static int DW_TAG_thrown_type = 0x31;
+       public final static int DW_TAG_try_block = 0x32;
+       public final static int DW_TAG_variant_part = 0x33;
+       public final static int DW_TAG_variable = 0x34;
+       public final static int DW_TAG_volatile_type = 0x35;
+       public final static int DW_TAG_dwarf_procedure = 0x36; // DWARF 3
+       public final static int DW_TAG_restrict_type = 0x37; // DWARF 3
+       public final static int DW_TAG_interface_type = 0x38; // DWARF 3
+       public final static int DW_TAG_namespace = 0x39; // DWARF 3
+       public final static int DW_TAG_imported_module = 0x3a; // DWARF 3
+       public final static int DW_TAG_unspecified_type = 0x3b; // DWARF 3
+       public final static int DW_TAG_partial_unit = 0x3c; // DWARF 3
+       public final static int DW_TAG_imported_unit = 0x3d; // DWARF 3
+       public final static int DW_TAG_condition = 0x3f; // DWARF 3
+       public final static int DW_TAG_shared_type = 0x40; // DWARF 3
+       public final static int DW_TAG_lo_user = 0x4080;
+       public final static int DW_TAG_MIPS_loop = 0x4081;
+       public final static int DW_TAG_format_label = 0x4101;
+       public final static int DW_TAG_function_template = 0x4102;
+       public final static int DW_TAG_class_template = 0x4103;
+       public final static int DW_TAG_hi_user = 0xffff;
+
+       /* Children determination encodings. */
+       public final static int DW_CHILDREN_no = 0;
+       public final static int DW_CHILDREN_yes = 1;
+
+       /* DWARF attributes encodings. */
+       public final static short DW_AT_sibling = 0x01;
+       public final static short DW_AT_location = 0x02;
+       public final static short DW_AT_name = 0x03;
+       public final static short DW_AT_ordering = 0x09;
+       public final static short DW_AT_subscr_data = 0x0a;
+       public final static short DW_AT_byte_size = 0x0b;
+       public final static short DW_AT_bit_offset = 0x0c;
+       public final static short DW_AT_bit_size = 0x0d;
+       public final static short DW_AT_element_list = 0x0f;
+       public final static short DW_AT_stmt_list = 0x10;
+       public final static short DW_AT_low_pc = 0x11;
+       public final static short DW_AT_high_pc = 0x12;
+       public final static short DW_AT_language = 0x13;
+       public final static short DW_AT_member = 0x14;
+       public final static short DW_AT_discr = 0x15;
+       public final static short DW_AT_discr_value = 0x16;
+       public final static short DW_AT_visibility = 0x17;
+       public final static short DW_AT_import = 0x18;
+       public final static short DW_AT_string_length = 0x19;
+       public final static short DW_AT_common_reference = 0x1a;
+       public final static short DW_AT_comp_dir = 0x1b;
+       public final static short DW_AT_const_value = 0x1c;
+       public final static short DW_AT_containing_type = 0x1d;
+       public final static short DW_AT_default_value = 0x1e;
+       public final static short DW_AT_inline = 0x20;
+       public final static short DW_AT_is_optional = 0x21;
+       public final static short DW_AT_lower_bound = 0x22;
+       public final static short DW_AT_producer = 0x25;
+       public final static short DW_AT_prototyped = 0x27;
+       public final static short DW_AT_return_addr = 0x2a;
+       public final static short DW_AT_start_scope = 0x2c;
+       public final static short DW_AT_stride_size = 0x2e;
+       public final static short DW_AT_upper_bound = 0x2f;
+       public final static short DW_AT_abstract_origin = 0x31;
+       public final static short DW_AT_accessibility = 0x32;
+       public final static short DW_AT_address_class = 0x33;
+       public final static short DW_AT_artificial = 0x34;
+       public final static short DW_AT_base_types = 0x35;
+       public final static short DW_AT_calling_convention = 0x36;
+       public final static short DW_AT_count = 0x37;
+       public final static short DW_AT_data_member_location = 0x38;
+       public final static short DW_AT_decl_column = 0x39;
+       public final static short DW_AT_decl_file = 0x3a;
+       public final static short DW_AT_decl_line = 0x3b;
+       public final static short DW_AT_declaration = 0x3c;
+       public final static short DW_AT_discr_list = 0x3d;
+       public final static short DW_AT_encoding = 0x3e;
+       public final static short DW_AT_external = 0x3f;
+       public final static short DW_AT_frame_base = 0x40;
+       public final static short DW_AT_friend = 0x41;
+       public final static short DW_AT_identifier_case = 0x42;
+       public final static short DW_AT_macro_info = 0x43;
+       public final static short DW_AT_namelist_items = 0x44;
+       public final static short DW_AT_priority = 0x45;
+       public final static short DW_AT_segment = 0x46;
+       public final static short DW_AT_specification = 0x47;
+       public final static short DW_AT_static_link = 0x48;
+       public final static short DW_AT_type = 0x49;
+       public final static short DW_AT_use_location = 0x4a;
+       public final static short DW_AT_variable_parameter = 0x4b;
+       public final static short DW_AT_virtuality = 0x4c;
+       public final static short DW_AT_vtable_elem_location = 0x4d;
+       public final static short DW_AT_allocated = 0x4e; // DWARF 3
+       public final static short DW_AT_associated = 0x4f; // DWARF 3
+       public final static short DW_AT_data_location = 0x50; // DWARF 3
+       public final static short DW_AT_byte_stride = 0x51; // DWARF 3
+       public final static short DW_AT_entry_pc = 0x52; // DWARF 3
+       public final static short DW_AT_use_UTF8 = 0x53; // DWARF 3
+       public final static short DW_AT_extension = 0x54; // DWARF 3
+       public final static short DW_AT_ranges = 0x55; // DWARF 3
+       public final static short DW_AT_trampoline = 0x56; // DWARF 3
+       public final static short DW_AT_call_column = 0x57; // DWARF 3
+       public final static short DW_AT_call_file = 0x58; // DWARF 3
+       public final static short DW_AT_call_line = 0x59; // DWARF 3
+       public final static short DW_AT_description = 0x5a; // DWARF 3
+       public final static short DW_AT_binary_scale = 0x5b; // DWARF 3
+       public final static short DW_AT_decimal_scale = 0x5c; // DWARF 3
+       public final static short DW_AT_small = 0x5d; // DWARF 3
+       public final static short DW_AT_decimal_sign = 0x5e; // DWARF 3
+       public final static short DW_AT_digit_count = 0x5f; // DWARF 3
+       public final static short DW_AT_picture_string = 0x60; // DWARF 3
+       public final static short DW_AT_mutable = 0x61; // DWARF 3
+       public final static short DW_AT_threads_scaled = 0x62; // DWARF 3
+       public final static short DW_AT_explicit = 0x63; // DWARF 3
+       public final static short DW_AT_object_pointer = 0x64; // DWARF 3
+       public final static short DW_AT_endianity = 0x65; // DWARF 3
+       public final static short DW_AT_elemental = 0x66; // DWARF 3
+       public final static short DW_AT_pure = 0x67; // DWARF 3
+       public final static short DW_AT_recursive = 0x68; // DWARF 3
+       public final static short DW_AT_lo_user = 0x2000;
+       public final static short DW_AT_MIPS_fde = 0x2001;
+       public final static short DW_AT_MIPS_loop_begin = 0x2002;
+       public final static short DW_AT_MIPS_tail_loop_begin = 0x2003;
+       public final static short DW_AT_MIPS_epilog_begin = 0x2004;
+       public final static short DW_AT_MIPS_loop_unroll_factor = 0x2005;
+       public final static short DW_AT_MIPS_software_pipeline_depth = 0x2006;
+       public final static short DW_AT_MIPS_linkage_name = 0x2007;
+       public final static short DW_AT_MIPS_stride = 0x2008;
+       public final static short DW_AT_MIPS_abstract_name = 0x2009;
+       public final static short DW_AT_MIPS_clone_origin = 0x200a;
+       public final static short DW_AT_MIPS_has_inlines = 0x200b;
+       public final static short DW_AT_MIPS_stride_byte = 0x200c;
+       public final static short DW_AT_MIPS_stride_elem = 0x200d;
+       public final static short DW_AT_MIPS_ptr_dopetype = 0x200e;
+       public final static short DW_AT_MIPS_allocatable_dopetype = 0x200f;
+       public final static short DW_AT_MIPS_assumed_shape_dopetype = 0x2010;
+       public final static short DW_AT_MIPS_assumed_size = 0x2011;
+       public final static short DW_AT_sf_names = 0x2101;
+       public final static short DW_AT_src_info = 0x2102;
+       public final static short DW_AT_mac_info = 0x2103;
+       public final static short DW_AT_src_coords = 0x2104;
+       public final static short DW_AT_body_begin = 0x2105;
+       public final static short DW_AT_body_end = 0x2106;
+       public final static short DW_AT_hi_user = 0x3fff;
+
+       /* DWARF form encodings. */
+       public final static int DW_FORM_addr = 0x01;
+       public final static int DW_FORM_block2 = 0x03;
+       public final static int DW_FORM_block4 = 0x04;
+       public final static int DW_FORM_data2 = 0x05;
+       public final static int DW_FORM_data4 = 0x06;
+       public final static int DW_FORM_data8 = 0x07;
+       public final static int DW_FORM_string = 0x08;
+       public final static int DW_FORM_block = 0x09;
+       public final static int DW_FORM_block1 = 0x0a;
+       public final static int DW_FORM_data1 = 0x0b;
+       public final static int DW_FORM_flag = 0x0c;
+       public final static int DW_FORM_sdata = 0x0d;
+       public final static int DW_FORM_strp = 0x0e;
+       public final static int DW_FORM_udata = 0x0f;
+       public final static int DW_FORM_ref_addr = 0x10;
+       public final static int DW_FORM_ref1 = 0x11;
+       public final static int DW_FORM_ref2 = 0x12;
+       public final static int DW_FORM_ref4 = 0x13;
+       public final static int DW_FORM_ref8 = 0x14;
+       public final static int DW_FORM_ref_udata = 0x15;
+       public final static int DW_FORM_indirect = 0x16;
+       
+       /* Since DWARF4 */
+       public final static int DW_FORM_sec_offset = 0x17;
+       public final static int DW_FORM_exprloc = 0x18;
+       public final static int DW_FORM_flag_present = 0x19;
+       public final static int DW_FORM_ref_sig8 = 0x20;
+       /* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
+       public final static int DW_FORM_GNU_addr_index = 0x1f01;
+       public final static int DW_FORM_GNU_str_index = 0x1f02;
+       /* Extensions for DWZ multifile.
+          See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open . */      
+       public final static int DW_FORM_GNU_ref_alt = 0x1f20;
+       public final static int DW_FORM_GNU_strp_alt = 0x1f21;
+       
+
+       /* DWARF location operation encodings. */
+       public final static int DW_OP_addr = 0x03; /* Constant address. */
+       public final static int DW_OP_deref = 0x06;
+       public final static int DW_OP_const1u = 0x08; /* Unsigned 1-byte constant. */
+       public final static int DW_OP_const1s = 0x09; /* Signed 1-byte constant. */
+       public final static int DW_OP_const2u = 0x0a; /* Unsigned 2-byte constant. */
+       public final static int DW_OP_const2s = 0x0b; /* Signed 2-byte constant. */
+       public final static int DW_OP_const4u = 0x0c; /* Unsigned 4-byte constant. */
+       public final static int DW_OP_const4s = 0x0d; /* Signed 4-byte constant. */
+       public final static int DW_OP_const8u = 0x0e; /* Unsigned 8-byte constant. */
+       public final static int DW_OP_const8s = 0x0f; /* Signed 8-byte constant. */
+       public final static int DW_OP_constu = 0x10; /* Unsigned LEB128 constant. */
+       public final static int DW_OP_consts = 0x11; /* Signed LEB128 constant. */
+       public final static int DW_OP_dup = 0x12;
+       public final static int DW_OP_drop = 0x13;
+       public final static int DW_OP_over = 0x14;
+       public final static int DW_OP_pick = 0x15; /* 1-byte stack index. */
+       public final static int DW_OP_swap = 0x16;
+       public final static int DW_OP_rot = 0x17;
+       public final static int DW_OP_xderef = 0x18;
+       public final static int DW_OP_abs = 0x19;
+       public final static int DW_OP_and = 0x1a;
+       public final static int DW_OP_div = 0x1b;
+       public final static int DW_OP_minus = 0x1c;
+       public final static int DW_OP_mod = 0x1d;
+       public final static int DW_OP_mul = 0x1e;
+       public final static int DW_OP_neg = 0x1f;
+       public final static int DW_OP_not = 0x20;
+       public final static int DW_OP_or = 0x21;
+       public final static int DW_OP_plus = 0x22;
+       public final static int DW_OP_plus_uconst = 0x23; /* Unsigned LEB128 addend. */
+       public final static int DW_OP_shl = 0x24;
+       public final static int DW_OP_shr = 0x25;
+       public final static int DW_OP_shra = 0x26;
+       public final static int DW_OP_xor = 0x27;
+       public final static int DW_OP_bra = 0x28; /* Signed 2-byte constant. */
+       public final static int DW_OP_eq = 0x29;
+       public final static int DW_OP_ge = 0x2a;
+       public final static int DW_OP_gt = 0x2b;
+       public final static int DW_OP_le = 0x2c;
+       public final static int DW_OP_lt = 0x2d;
+       public final static int DW_OP_ne = 0x2e;
+       public final static int DW_OP_skip = 0x2f; /* Signed 2-byte constant. */
+       public final static int DW_OP_lit0 = 0x30; /* Literal 0. */
+       public final static int DW_OP_lit1 = 0x31; /* Literal 1. */
+       public final static int DW_OP_lit2 = 0x32; /* Literal 2. */
+       public final static int DW_OP_lit3 = 0x33; /* Literal 3. */
+       public final static int DW_OP_lit4 = 0x34; /* Literal 4. */
+       public final static int DW_OP_lit5 = 0x35; /* Literal 5. */
+       public final static int DW_OP_lit6 = 0x36; /* Literal 6. */
+       public final static int DW_OP_lit7 = 0x37; /* Literal 7. */
+       public final static int DW_OP_lit8 = 0x38; /* Literal 8. */
+       public final static int DW_OP_lit9 = 0x39; /* Literal 9. */
+       public final static int DW_OP_lit10 = 0x3a; /* Literal 10. */
+       public final static int DW_OP_lit11 = 0x3b; /* Literal 11. */
+       public final static int DW_OP_lit12 = 0x3c; /* Literal 12. */
+       public final static int DW_OP_lit13 = 0x3d; /* Literal 13. */
+       public final static int DW_OP_lit14 = 0x3e; /* Literal 14. */
+       public final static int DW_OP_lit15 = 0x3f; /* Literal 15. */
+       public final static int DW_OP_lit16 = 0x40; /* Literal 16. */
+       public final static int DW_OP_lit17 = 0x41; /* Literal 17. */
+       public final static int DW_OP_lit18 = 0x42; /* Literal 18. */
+       public final static int DW_OP_lit19 = 0x43; /* Literal 19. */
+       public final static int DW_OP_lit20 = 0x44; /* Literal 20. */
+       public final static int DW_OP_lit21 = 0x45; /* Literal 21. */
+       public final static int DW_OP_lit22 = 0x46; /* Literal 22. */
+       public final static int DW_OP_lit23 = 0x47; /* Literal 23. */
+       public final static int DW_OP_lit24 = 0x48; /* Literal 24. */
+       public final static int DW_OP_lit25 = 0x49; /* Literal 25. */
+       public final static int DW_OP_lit26 = 0x4a; /* Literal 26. */
+       public final static int DW_OP_lit27 = 0x4b; /* Literal 27. */
+       public final static int DW_OP_lit28 = 0x4c; /* Literal 28. */
+       public final static int DW_OP_lit29 = 0x4d; /* Literal 29. */
+       public final static int DW_OP_lit30 = 0x4e; /* Literal 30. */
+       public final static int DW_OP_lit31 = 0x4f; /* Literal 31. */
+       public final static int DW_OP_reg0 = 0x50; /* Register 0. */
+       public final static int DW_OP_reg1 = 0x51; /* Register 1. */
+       public final static int DW_OP_reg2 = 0x52; /* Register 2. */
+       public final static int DW_OP_reg3 = 0x53; /* Register 3. */
+       public final static int DW_OP_reg4 = 0x54; /* Register 4. */
+       public final static int DW_OP_reg5 = 0x55; /* Register 5. */
+       public final static int DW_OP_reg6 = 0x56; /* Register 6. */
+       public final static int DW_OP_reg7 = 0x57; /* Register 7. */
+       public final static int DW_OP_reg8 = 0x58; /* Register 8. */
+       public final static int DW_OP_reg9 = 0x59; /* Register 9. */
+       public final static int DW_OP_reg10 = 0x5a; /* Register 10. */
+       public final static int DW_OP_reg11 = 0x5b; /* Register 11. */
+       public final static int DW_OP_reg12 = 0x5c; /* Register 12. */
+       public final static int DW_OP_reg13 = 0x5d; /* Register 13. */
+       public final static int DW_OP_reg14 = 0x5e; /* Register 14. */
+       public final static int DW_OP_reg15 = 0x5f; /* Register 15. */
+       public final static int DW_OP_reg16 = 0x60; /* Register 16. */
+       public final static int DW_OP_reg17 = 0x61; /* Register 17. */
+       public final static int DW_OP_reg18 = 0x62; /* Register 18. */
+       public final static int DW_OP_reg19 = 0x63; /* Register 19. */
+       public final static int DW_OP_reg20 = 0x64; /* Register 20. */
+       public final static int DW_OP_reg21 = 0x65; /* Register 21. */
+       public final static int DW_OP_reg22 = 0x66; /* Register 22. */
+       public final static int DW_OP_reg23 = 0x67; /* Register 24. */
+       public final static int DW_OP_reg24 = 0x68; /* Register 24. */
+       public final static int DW_OP_reg25 = 0x69; /* Register 25. */
+       public final static int DW_OP_reg26 = 0x6a; /* Register 26. */
+       public final static int DW_OP_reg27 = 0x6b; /* Register 27. */
+       public final static int DW_OP_reg28 = 0x6c; /* Register 28. */
+       public final static int DW_OP_reg29 = 0x6d; /* Register 29. */
+       public final static int DW_OP_reg30 = 0x6e; /* Register 30. */
+       public final static int DW_OP_reg31 = 0x6f; /* Register 31. */
+       public final static int DW_OP_breg0 = 0x70; /* Base register 0. */
+       public final static int DW_OP_breg1 = 0x71; /* Base register 1. */
+       public final static int DW_OP_breg2 = 0x72; /* Base register 2. */
+       public final static int DW_OP_breg3 = 0x73; /* Base register 3. */
+       public final static int DW_OP_breg4 = 0x74; /* Base register 4. */
+       public final static int DW_OP_breg5 = 0x75; /* Base register 5. */
+       public final static int DW_OP_breg6 = 0x76; /* Base register 6. */
+       public final static int DW_OP_breg7 = 0x77; /* Base register 7. */
+       public final static int DW_OP_breg8 = 0x78; /* Base register 8. */
+       public final static int DW_OP_breg9 = 0x79; /* Base register 9. */
+       public final static int DW_OP_breg10 = 0x7a; /* Base register 10. */
+       public final static int DW_OP_breg11 = 0x7b; /* Base register 11. */
+       public final static int DW_OP_breg12 = 0x7c; /* Base register 12. */
+       public final static int DW_OP_breg13 = 0x7d; /* Base register 13. */
+       public final static int DW_OP_breg14 = 0x7e; /* Base register 14. */
+       public final static int DW_OP_breg15 = 0x7f; /* Base register 15. */
+       public final static int DW_OP_breg16 = 0x80; /* Base register 16. */
+       public final static int DW_OP_breg17 = 0x81; /* Base register 17. */
+       public final static int DW_OP_breg18 = 0x82; /* Base register 18. */
+       public final static int DW_OP_breg19 = 0x83; /* Base register 19. */
+       public final static int DW_OP_breg20 = 0x84; /* Base register 20. */
+       public final static int DW_OP_breg21 = 0x85; /* Base register 21. */
+       public final static int DW_OP_breg22 = 0x86; /* Base register 22. */
+       public final static int DW_OP_breg23 = 0x87; /* Base register 23. */
+       public final static int DW_OP_breg24 = 0x88; /* Base register 24. */
+       public final static int DW_OP_breg25 = 0x89; /* Base register 25. */
+       public final static int DW_OP_breg26 = 0x8a; /* Base register 26. */
+       public final static int DW_OP_breg27 = 0x8b; /* Base register 27. */
+       public final static int DW_OP_breg28 = 0x8c; /* Base register 28. */
+       public final static int DW_OP_breg29 = 0x8d; /* Base register 29. */
+       public final static int DW_OP_breg30 = 0x8e; /* Base register 30. */
+       public final static int DW_OP_breg31 = 0x8f; /* Base register 31. */
+       public final static int DW_OP_regx = 0x90; /* Unsigned LEB128 register. */
+       public final static int DW_OP_fbreg = 0x91; /* Signed LEB128 register. */
+       public final static int DW_OP_bregx = 0x92; /*
+                                                                                                * ULEB128 register followed by
+                                                                                                * SLEB128 off.
+                                                                                                */
+       public final static int DW_OP_piece = 0x93; /*
+                                                                                                * ULEB128 size of piece
+                                                                                                * addressed.
+                                                                                                */
+       public final static int DW_OP_deref_size = 0x94; /*
+                                                                                                        * 1-byte size of data
+                                                                                                        * retrieved.
+                                                                                                        */
+       public final static int DW_OP_xderef_size = 0x95; /*
+                                                                                                        * 1-byte size of data
+                                                                                                        * retrieved.
+                                                                                                        */
+       public final static int DW_OP_nop = 0x96;
+       public final static int DW_OP_push_object_address = 0x97; // DWARF 3
+       public final static int DW_OP_call2 = 0x98; // 2-byte offset of DIE // DWARF
+                                                                                               // 3
+       public final static int DW_OP_call4 = 0x99; // 4-byte offset of DIE // DWARF
+                                                                                               // 3
+       public final static int DW_OP_call_ref = 0x9a; // 4- or 8-byte offset of DIE
+                                                                                                       // // DWARF 3
+       public final static int DW_OP_form_tls_address = 0x9b; // DWARF 3
+       public final static int DW_OP_call_frame_cfa = 0x9c; // DWARF 3
+       public final static int DW_OP_bit_piece = 0x9d; // DWARF 3
+
+       public final static int DW_OP_lo_user = 0xe0; /*
+                                                                                                * Implementation-defined range
+                                                                                                * start.
+                                                                                                */
+       public final static int DW_OP_hi_user = 0xff; /*
+                                                                                                * Implementation-defined range
+                                                                                                * end.
+                                                                                                */
+
+       /* DWARF base type encodings. */
+       public final static int DW_ATE_void = 0x0;
+       public final static int DW_ATE_address = 0x1;
+       public final static int DW_ATE_boolean = 0x2;
+       public final static int DW_ATE_complex_float = 0x3;
+       public final static int DW_ATE_float = 0x4;
+       public final static int DW_ATE_signed = 0x5;
+       public final static int DW_ATE_signed_char = 0x6;
+       public final static int DW_ATE_unsigned = 0x7;
+       public final static int DW_ATE_unsigned_char = 0x8;
+       public final static int DW_ATE_imaginary_float = 0x09; // DWARF 3
+       public final static int DW_ATE_packed_decimal = 0x0a; // DWARF 3
+       public final static int DW_ATE_numeric_string = 0x0b; // DWARF 3
+       public final static int DW_ATE_edited = 0x0c; // DWARF 3
+       public final static int DW_ATE_signed_fixed = 0x0d; // DWARF 3
+       public final static int DW_ATE_unsigned_fixed = 0x0e; // DWARF 3
+       public final static int DW_ATE_decimal_float = 0x0f; // DWARF 3
+
+       public final static int DW_ATE_lo_user = 0x80;
+       public final static int DW_ATE_hi_user = 0xff;
+
+       /* DWARF decimal sign encodings. */
+       public final static int DW_DS_unsigned = 0x01; // DWARF 3
+       public final static int DW_DS_leading_overpunch = 0x02; // DWARF 3
+       public final static int DW_DS_trailing_overpunch = 0x03;// DWARF 3
+       public final static int DW_DS_leading_separate = 0x04; // DWARF 3
+       public final static int DW_DS_trailing_separate = 0x05; // DWARF 3
+
+       /* DWARF endianity encodings. */
+       public final static int DW_END_default = 0x00; // DWARF 3
+       public final static int DW_END_big = 0x01; // DWARF 3
+       public final static int DW_END_little = 0x02; // DWARF 3
+       public final static int DW_END_lo_user = 0x40; // DWARF 3
+       public final static int DW_END_hi_user = 0xff; // DWARF 3
+
+       /* DWARF accessibility encodings. */
+       public final static int DW_ACCESS_public = 1;
+       public final static int DW_ACCESS_protected = 2;
+       public final static int DW_ACCESS_private = 3;
+
+       /* DWARF visibility encodings. */
+       public final static int DW_VIS_local = 1;
+       public final static int DW_VIS_exported = 2;
+       public final static int DW_VIS_qualified = 3;
+
+       /* DWARF virtuality encodings. */
+       public final static int DW_VIRTUALITY_none = 0;
+       public final static int DW_VIRTUALITY_virtual = 1;
+       public final static int DW_VIRTUALITY_pure_virtual = 2;
+
+       /* DWARF language encodings. */
+       public final static int DW_LANG_C89 = 0x0001;
+       public final static int DW_LANG_C = 0x0002;
+       public final static int DW_LANG_Ada83 = 0x0003;
+       public final static int DW_LANG_C_plus_plus = 0x0004;
+       public final static int DW_LANG_Cobol74 = 0x0005;
+       public final static int DW_LANG_Cobol85 = 0x0006;
+       public final static int DW_LANG_Fortran77 = 0x0007;
+       public final static int DW_LANG_Fortran90 = 0x0008;
+       public final static int DW_LANG_Pascal83 = 0x0009;
+       public final static int DW_LANG_Modula2 = 0x000a;
+       public final static int DW_LANG_Java = 0x000b; // DWARF 3
+       public final static int DW_LANG_C99 = 0x000c; // DWARF 3
+       public final static int DW_LANG_Ada95 = 0x000d; // DWARF 3
+       public final static int DW_LANG_Fortran95 = 0x000e; // DWARF 3
+       public final static int DW_LANG_PLI = 0x000f; // DWARF 3
+       public final static int DW_LANG_PL1 = 0x000f; // misspelling found in
+                                                                                                       // org.eclipse.cdt.utils.debug.dwarf.DwarfConstants
+       public final static int DW_LANG_ObjC = 0x0010; // DWARF 3
+       public final static int DW_LANG_ObjC_plus_plus = 0x0011;// DWARF 3
+       public final static int DW_LANG_UPC = 0x0012; // DWARF 3
+       public final static int DW_LANG_D = 0x0013; // DWARF 3
+       public final static int DW_LANG_lo_user = 0x8000;
+       public final static int DW_LANG_Mips_Assembler = 0x8001;
+       public final static int DW_LANG_hi_user = 0xffff;
+
+       /* DWARF identifier case encodings. */
+       public final static int DW_ID_case_sensitive = 0;
+       public final static int DW_ID_up_case = 1;
+       public final static int DW_ID_down_case = 2;
+       public final static int DW_ID_case_insensitive = 3;
+
+       /* DWARF calling conventions encodings. */
+       public final static int DW_CC_normal = 0x1;
+       public final static int DW_CC_program = 0x2;
+       public final static int DW_CC_nocall = 0x3;
+       public final static int DW_CC_lo_user = 0x40;
+       public final static int DW_CC_hi_user = 0xff;
+
+       /* DWARF inline encodings. */
+       public final static int DW_INL_not_inlined = 0;
+       public final static int DW_INL_inlined = 1;
+       public final static int DW_INL_declared_not_inlined = 2;
+       public final static int DW_INL_declared_inlined = 3;
+
+       /* DWARF ordering encodings. */
+       public final static int DW_ORD_row_major = 0;
+       public final static int DW_ORD_col_major = 1;
+
+       /* DWARF discriminant descriptor encodings. */
+       public final static int DW_DSC_label = 0;
+       public final static int DW_DSC_range = 1;
+
+       /* DWARF standard opcode encodings. */
+       public final static int DW_LNS_copy = 1;
+       public final static int DW_LNS_advance_pc = 2;
+       public final static int DW_LNS_advance_line = 3;
+       public final static int DW_LNS_set_file = 4;
+       public final static int DW_LNS_set_column = 5;
+       public final static int DW_LNS_negate_stmt = 6;
+       public final static int DW_LNS_set_basic_block = 7;
+       public final static int DW_LNS_const_add_pc = 8;
+       public final static int DW_LNS_fixed_advance_pc = 9;
+       public final static int DW_LNS_set_prologue_end = 10; // DWARF 3
+       public final static int DW_LNS_set_epilog_begin = 11; // misspelling found
+                                                                                                                       // in
+                                                                                                                       // org.eclipse.cdt.utils.debug.dwarf.DwarfConstants
+       public final static int DW_LNS_set_epilogue_begin = 11; // DWARF 3
+       public final static int DW_LNS_set_isa = 12; // DWARF 3
+
+       public final static int LINE_IsStmt = 0x01;
+       public final static int LINE_BasicBlock = 0x02;
+       public final static int LINE_PrologueEnd = 0x04;
+       public final static int LINE_EpilogueBegin = 0x08;
+       public final static int LINE_EndSequence = 0x10;
+
+       /* DWARF extended opcide encodings. */
+       public final static int DW_LNE_end_sequence = 1;
+       public final static int DW_LNE_set_address = 2;
+       public final static int DW_LNE_define_file = 3;
+       public final static int DW_LNE_lo_user = 0x80; // DWARF 3
+       public final static int DW_LNE_hi_user = 0xff; // DWARF 3
+
+       /* DWARF macinfo type encodings. */
+       public final static int DW_MACINFO_define = 1;
+       public final static int DW_MACINFO_undef = 2;
+       public final static int DW_MACINFO_start_file = 3;
+       public final static int DW_MACINFO_end_file = 4;
+       public final static int DW_MACINFO_vendor_ext = 255;
+
+       /* DWARF macro type encodings. */
+       /* since DWARF4 */
+       public final static int DW_MACRO_end = 0;
+       public final static int DW_MACRO_define = 1;
+       public final static int DW_MACRO_undef = 2;
+       public final static int DW_MACRO_start_file = 3;
+       public final static int DW_MACRO_end_file = 4;
+       public final static int DW_MACRO_define_indirect = 5;
+       public final static int DW_MACRO_undef_indirect = 6;
+       public final static int DW_MACRO_transparent_include = 7;
+       public final static int DW_MACRO_define_indirect_alt = 0x08;
+       public final static int DW_MACRO_undef_indirect_alt = 0x09;
+       public final static int DW_MACRO_transparent_include_alt = 0x0a;
+       public final static int DW_MACRO_lo_user = 0xe0;
+       public final static int DW_MACRO_hi_user = 0xff;
+       
+       /* DWARF call frame instruction encodings. */
+       public final static int DW_CFA_advance_loc = 0x40; // low 6 bits delta
+       public final static int DW_CFA_offset = 0x80; // low 6 bits register,
+                                                                                                       // operand ULEB128 offset
+       public final static int DW_CFA_restore = 0xc0; // low 6 bits register
+       public final static int DW_CFA_extended = 0; // same as DW_CFA_nop
+
+       public final static int DW_CFA_nop = 0x00; // same as DW_CFA_extended
+       public final static int DW_CFA_set_loc = 0x01; // operand: address
+       public final static int DW_CFA_advance_loc1 = 0x02; // operand: 1-byte delta
+       public final static int DW_CFA_advance_loc2 = 0x03; // operand: 2-byte delta
+       public final static int DW_CFA_advance_loc4 = 0x04; // operand: 4-byte delta
+       public final static int DW_CFA_offset_extended = 0x05; // operands: ULEB128
+                                                                                                                       // register, ULEB128
+                                                                                                                       // offset
+       public final static int DW_CFA_restore_extended = 0x06; // operand: ULEB128
+                                                                                                                       // register
+       public final static int DW_CFA_undefined = 0x07; // operand: ULEB128
+                                                                                                               // register
+       public final static int DW_CFA_same_value = 0x08; // operand: ULEB128
+                                                                                                               // register
+       public final static int DW_CFA_register = 0x09; // operands: ULEB128
+                                                                                                       // register, ULEB128
+                                                                                                       // register
+       public final static int DW_CFA_remember_state = 0x0a;
+       public final static int DW_CFA_restore_state = 0x0b;
+       public final static int DW_CFA_def_cfa = 0x0c; // operands: ULEB128
+                                                                                                       // register, ULEB128 offset
+       public final static int DW_CFA_def_cfa_register = 0x0d; // operand: ULEB128
+                                                                                                                       // register
+       public final static int DW_CFA_def_cfa_offset = 0x0e; // operand: ULEB128
+                                                                                                                       // offset
+       public final static int DW_CFA_def_cfa_expression = 0x0f; // operand: BLOCK
+                                                                                                                               // // DWARF 3
+       public final static int DW_CFA_expression = 0x10; // operands: ULEB128
+                                                                                                               // register, BLOCK //
+                                                                                                               // DWARF 3
+       public final static int DW_CFA_offset_extended_sf = 0x11; // operands:
+                                                                                                                               // ULEB128
+                                                                                                                               // register,
+                                                                                                                               // SLEB128
+                                                                                                                               // offset //
+                                                                                                                               // DWARF 3
+       public final static int DW_CFA_def_cfa_sf = 0x12; // operands: ULEB128
+                                                                                                               // register, SLEB128
+                                                                                                               // offset // DWARF 3
+       public final static int DW_CFA_def_cfa_offset_sf = 0x13;// operand: SLEB128
+                                                                                                                       // offset // DWARF 3
+       public final static int DW_CFA_val_offset = 0x14; // operands: ULEB128,
+                                                                                                               // ULEB128// DWARF 3
+       public final static int DW_CFA_val_offset_sf = 0x15; // operands: ULEB128,
+                                                                                                                       // SLEB128// DWARF 3
+       public final static int DW_CFA_val_expression = 0x16; // operands: ULEB128,
+                                                                                                                       // BLOCK// DWARF 3
+       public final static int DW_CFA_low_user = 0x1c;
+       public final static int DW_CFA_MIPS_advance_loc8 = 0x1d;
+       public final static int DW_CFA_GNU_window_save = 0x2d;
+       public final static int DW_CFA_GNU_args_size = 0x2e;
+       public final static int DW_CFA_high_user = 0x3f;
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfDebugInfoProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfDebugInfoProvider.java
new file mode 100644 (file)
index 0000000..7fb9bfa
--- /dev/null
@@ -0,0 +1,1459 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.symbols.IForwardTypeReference;
+import org.eclipse.cdt.debug.edc.internal.symbols.Scope;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.CommonInformationEntry;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.FrameDescriptionEntry;
+import org.eclipse.cdt.debug.edc.services.IFrameRegisterProvider;
+import org.eclipse.cdt.debug.edc.symbols.ICompileUnitScope;
+import org.eclipse.cdt.debug.edc.symbols.IDebugInfoProvider;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.IModuleScope;
+import org.eclipse.cdt.debug.edc.symbols.IRangeList;
+import org.eclipse.cdt.debug.edc.symbols.IRangeList.Entry;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * This class handles the low-level aspects of reading DWARF data.
+ * There exists one provider per symbol file.
+ */
+public class DwarfDebugInfoProvider implements IDebugInfoProvider {
+       
+       /**
+        * This represents a forward type reference, which is a type
+        * that resolves itself when referenced.
+        */
+       static public class ForwardTypeReference implements IType, IForwardTypeReference {
+
+               static public final IType NULL_TYPE_ENTRY = new IType() {
+
+                       public int getByteSize() {
+                               return 0;
+                       }
+
+                       public String getName() {
+                               return DwarfMessages.DwarfDebugInfoProvider_UnhandledType;
+                       }
+
+                       public Map<Object, Object> getProperties() {
+                               return Collections.emptyMap();
+                       }
+
+                       public IScope getScope() {
+                               return null;
+                       }
+
+                       public IType getType() {
+                               return null;
+                       }
+
+                       public void setType(IType type) {
+                               throw new IllegalStateException();
+                       }
+                       
+                       public void dispose() {
+                       }
+               };
+               
+               private DwarfDebugInfoProvider provider;
+               private IType type = null;
+
+               private final long offset;
+               
+               public ForwardTypeReference(DwarfDebugInfoProvider provider, long offset) {
+                       this.provider = provider;
+                       this.offset = offset;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.symbols.dwarf.IForwardTypeReference#getReferencedType()
+                */
+               public IType getReferencedType() {
+                       if (type == null) {
+                               // to prevent recursion
+                               IType newType = NULL_TYPE_ENTRY;
+                               newType = provider.resolveTypeReference(this);
+                               if (newType == null) {
+                                       // FIXME
+                                       newType = NULL_TYPE_ENTRY;
+                               }
+                               type = newType;
+                       }
+                       return type;
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.symbols.IType#getByteSize()
+                */
+               public int getByteSize() {
+                       return getReferencedType().getByteSize();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.symbols.IType#getName()
+                */
+               public String getName() {
+                       return getReferencedType().getName();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.symbols.IType#getProperties()
+                */
+               public Map<Object, Object> getProperties() {
+                       return getReferencedType().getProperties();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.symbols.IType#getScope()
+                */
+               public IScope getScope() {
+                       return getReferencedType().getScope();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.symbols.IType#getType()
+                */
+               public IType getType() {
+                       return getReferencedType().getType();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.symbols.IType#setType(org.eclipse.cdt.debug.edc.internal.symbols.IType)
+                */
+               public void setType(IType type_) {
+                       getReferencedType().setType(type_);
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.symbols.IType#dispose()
+                */
+               public void dispose() {
+                       type = null;
+                       provider = null;
+               }
+       }
+       
+       static public class CompilationUnitHeader {
+               long length;
+               short version;
+               int abbreviationOffset;
+               byte addressSize;
+               int debugInfoOffset;
+               byte offsetSize;
+               DwarfCompileUnit scope;
+               
+               @Override
+               public String toString() {
+                       StringBuffer sb = new StringBuffer();
+                       sb.append("Offset: " + debugInfoOffset).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+                       sb.append("Length: " + length).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+                       sb.append("Version: " + version).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+                       sb.append("Abbreviation: " + abbreviationOffset).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+                       sb.append("Address size: " + addressSize).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+                       sb.append("Offset size: " + offsetSize).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$                       
+                       return sb.toString();
+               }
+       }
+       
+       static class AbbreviationEntry {
+               short tag;
+               ArrayList<Attribute> attributes;
+               boolean hasChildren;
+
+               AbbreviationEntry(long code, short tag, boolean hasChildren) {
+                       // abbreviation code not stored
+                       this.tag = tag;
+                       this.hasChildren = hasChildren;
+                       attributes = new ArrayList<Attribute>();
+               }
+       }
+
+       static class Attribute {
+               short tag;
+               byte form;
+
+               Attribute(short tag, byte form) {
+                       this.tag = tag;
+                       this.form = form;
+               }
+
+               @Override
+               public String toString() {
+                       StringBuffer sb = new StringBuffer();
+                       sb.append("tag: " + Long.toHexString(tag)); //$NON-NLS-1$
+                       sb.append(" form: " + Long.toHexString(form)); //$NON-NLS-1$
+                       return sb.toString();
+               }
+       }
+
+       static class AttributeValue {
+               private Object value;
+
+               // for indirect form, this is the actual form
+               private byte actualForm;
+
+               AttributeValue(byte form, IStreamBuffer in, byte addressSize, IStreamBuffer debugStrings) {
+                       actualForm = form;
+
+                       try {
+                               value = readAttribute(in, addressSize, debugStrings);
+                       } catch (IOException e) {
+                               EDCDebugger.getMessageLogger().logError(null, e);
+                       }
+               }
+
+               @Override
+               public String toString() {
+                       StringBuffer sb = new StringBuffer();
+                       if (value != null) {
+                               Class<? extends Object> clazz = value.getClass();
+                               if (clazz.isArray()) {
+                                       int len = Array.getLength(value);
+                                       sb.append(len).append(' ');
+                                       sb.append(clazz.getComponentType().toString());
+                                       sb.append(':');
+                                       for (int i = 0; i < len; i++) {
+                                               byte b = Array.getByte(value, i);
+                                               sb.append(' ').append(Integer.toHexString(b));
+                                       }
+                               } else {
+                                       if (value instanceof Number) {
+                                               Number n = (Number) value;
+                                               sb.append(Long.toHexString(n.longValue()));
+                                       } else if (value instanceof String) {
+                                               sb.append(value);
+                                       } else {
+                                               sb.append(value);
+                                       }
+                               }
+                       }
+                       return sb.toString();
+               }
+               //TODO: support DWARF 64-bit format
+               private Object readAttribute(IStreamBuffer in, byte addressSize, IStreamBuffer debugStrings) throws IOException {
+                       Object obj = null;
+                       switch (actualForm) {
+                       case DwarfConstants.DW_FORM_addr:
+                               obj = DwarfInfoReader.readAddress(in, addressSize);
+                       case DwarfConstants.DW_FORM_ref_addr:
+                               break;
+
+                       case DwarfConstants.DW_FORM_block: {
+                               int size = (int) DwarfInfoReader.read_unsigned_leb128(in);
+                               byte[] bytes = new byte[size];
+                               in.get(bytes);
+                               obj = bytes;
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_block1: {
+                               int size = in.get() & 0xff;
+                               byte[] bytes = new byte[size];
+                               in.get(bytes);
+                               obj = bytes;
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_block2: {
+                               int size = in.getShort();
+                               byte[] bytes = new byte[size];
+                               in.get(bytes);
+                               obj = bytes;
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_block4: {
+                               int size = in.getInt();
+                               byte[] bytes = new byte[size];
+                               in.get(bytes);
+                               obj = bytes;
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_data1:
+                               obj = new Byte(in.get());
+                               break;
+
+                       case DwarfConstants.DW_FORM_data2:
+                               obj = new Short(in.getShort());
+                               break;
+
+                       case DwarfConstants.DW_FORM_data4:
+                               obj = new Integer(in.getInt());
+                               break;
+
+                       case DwarfConstants.DW_FORM_data8:
+                               obj = new Long(in.getLong());
+                               break;
+
+                       case DwarfConstants.DW_FORM_sdata:
+                               obj = new Long(DwarfInfoReader.read_signed_leb128(in));
+                               break;
+
+                       case DwarfConstants.DW_FORM_udata:
+                               obj = new Long(DwarfInfoReader.read_unsigned_leb128(in));
+                               break;
+
+                       case DwarfConstants.DW_FORM_string: {
+                               int c;
+                               StringBuffer sb = new StringBuffer();
+                               while ((c = (in.get() & 0xff)) != -1) {
+                                       if (c == 0) {
+                                               break;
+                                       }
+                                       sb.append((char) c);
+                               }
+                               obj = sb.toString();
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_flag:
+                               obj = new Byte(in.get());
+                               break;
+
+                       case DwarfConstants.DW_FORM_strp: {
+                               int offset = in.getInt();
+                               if (debugStrings == null) {
+                                       obj = new String();
+                               } else if (offset < 0 || offset > debugStrings.capacity()) {
+                                       obj = new String();
+                               } else {
+                                       debugStrings.position(offset);
+                                       obj = DwarfInfoReader.readString(debugStrings);
+                               }
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_ref1:
+                               obj = new Integer(in.get() & 0xff);
+                               break;
+
+                       case DwarfConstants.DW_FORM_ref2:
+                               obj = new Integer(in.getShort() & 0xffff);
+                               break;
+
+                       case DwarfConstants.DW_FORM_ref4:
+                               obj = new Integer(in.getInt());
+                               break;
+
+                       case DwarfConstants.DW_FORM_ref8:
+                               obj = new Long(in.getLong());
+                               break;
+
+                       case DwarfConstants.DW_FORM_ref_udata:
+                               obj = new Long(DwarfInfoReader.read_unsigned_leb128(in));
+                               break;
+
+                       case DwarfConstants.DW_FORM_indirect: {
+                               actualForm = (byte) DwarfInfoReader.read_unsigned_leb128(in);
+                               return readAttribute(in, addressSize, debugStrings);
+                       }
+                       
+                       case DwarfConstants.DW_FORM_sec_offset :
+//                                     if (header.offsetSize == 8)
+//                                             obj = new Long(in.getLong));
+//                                     else
+                                               obj = new Long(in.getInt()  & 0xffffffffL);
+                                       break;
+                       case DwarfConstants.DW_FORM_exprloc :
+                                       long size = DwarfInfoReader.read_unsigned_leb128(in);
+                                       byte[] bytes = new byte[(int) size];
+                                       in.get(bytes);
+                                       obj = bytes;
+                                       break;
+                       case DwarfConstants.DW_FORM_flag_present :
+                                       // 0 byte value
+                                       obj = Byte.valueOf((byte)1);
+                                       break;
+                       case DwarfConstants.DW_FORM_ref_sig8 :
+                                       obj = new Long(in.getLong());
+                                       break;
+
+                       
+                       default:
+                               assert (false);
+                               break;
+                       }
+
+                       return obj;
+               }
+
+               /**
+                * @param attr
+                * @param in
+                * @param addressSize
+                * @param debugStrings
+                */
+               //TODO: support DWARF 64-bit format
+               public static void skipAttributeValue(short form, IStreamBuffer in,
+                               byte addressSize) throws IOException {
+                       switch (form) {
+                       case DwarfConstants.DW_FORM_addr:
+                       case DwarfConstants.DW_FORM_ref_addr:
+                               in.position(in.position() + addressSize);
+                               break;
+
+                       case DwarfConstants.DW_FORM_block: {
+                               int size = (int) DwarfInfoReader.read_unsigned_leb128(in);
+                               in.position(in.position() + size);
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_block1: {
+                               int size = in.get() & 0xff;
+                               in.position(in.position() + size);
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_block2: {
+                               int size = in.getShort();
+                               in.position(in.position() + size);
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_block4: {
+                               int size = in.getInt();
+                               in.position(in.position() + size);
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_data1:
+                               in.position(in.position() + 1);
+                               break;
+
+                       case DwarfConstants.DW_FORM_data2:
+                               in.position(in.position() + 2);
+                               break;
+
+                       case DwarfConstants.DW_FORM_data4:
+                               in.position(in.position() + 4);
+                               break;
+
+                       case DwarfConstants.DW_FORM_data8:
+                               in.position(in.position() + 8);
+                               break;
+
+                       case DwarfConstants.DW_FORM_sdata:
+                               DwarfInfoReader.read_signed_leb128(in);
+                               break;
+
+                       case DwarfConstants.DW_FORM_udata:
+                               DwarfInfoReader.read_unsigned_leb128(in);
+                               break;
+
+                       case DwarfConstants.DW_FORM_string: {
+                               int c;
+                               while ((c = (in.get() & 0xff)) != -1) {
+                                       if (c == 0) {
+                                               break;
+                                       }
+                               }
+                       }
+                               break;
+
+                       case DwarfConstants.DW_FORM_flag:
+                               in.position(in.position() + 1);
+                               break;
+
+                       case DwarfConstants.DW_FORM_strp:
+                               in.position(in.position() + 4);
+                               break;
+
+                       case DwarfConstants.DW_FORM_ref1:
+                               in.position(in.position() + 1);
+                               break;
+
+                       case DwarfConstants.DW_FORM_ref2:
+                               in.position(in.position() + 2);
+                               break;
+
+                       case DwarfConstants.DW_FORM_ref4:
+                               in.position(in.position() + 4);
+                               break;
+
+                       case DwarfConstants.DW_FORM_ref8:
+                               in.position(in.position() + 8);
+                               break;
+
+                       case DwarfConstants.DW_FORM_ref_udata:
+                               DwarfInfoReader.read_unsigned_leb128(in);
+                               break;
+
+                       case DwarfConstants.DW_FORM_indirect: {
+                               form = (short) DwarfInfoReader.read_unsigned_leb128(in);
+                               skipAttributeValue(form, in, addressSize);
+                               break;
+                       }
+                       
+                       case DwarfConstants.DW_FORM_sec_offset :
+//                                     if (header.offsetSize == 8)
+//                                             in.position(in.position() + 8);                         
+//                                     else
+                                       in.position(in.position() + 4);
+                                       break;
+                       case DwarfConstants.DW_FORM_exprloc :
+                                       int size = (int) DwarfInfoReader.read_unsigned_leb128(in);
+                                       in.position(in.position() + size);
+                                       break;
+                       case DwarfConstants.DW_FORM_flag_present :
+                                       // 0 byte value
+                               in.position(in.position() + 0); // for readability
+                                       break;
+                       case DwarfConstants.DW_FORM_ref_sig8 :
+                               in.position(in.position() + 8);
+                                       break;                  
+
+                       default:
+                               assert (false);
+                               break;
+                       }
+               }
+               
+               /**
+                * Parse attributes and then skip to sibling, if any
+                * 
+                * @param names array to hold up to two names
+                * @param entry debug info entry
+                * @param in buffer stream of debug info
+                * @param addressSize 
+                * @param debugStrings
+                * @return DW_AT_name value, or null if there is no or invalid DW_AT_name attribute  
+                */
+               public static void skipAttributesToSibling(AbbreviationEntry entry, IStreamBuffer in, byte addressSize) {
+               
+                       long sibling = -1;
+
+                       // go through the attributes and throw away everything except the sibling
+                       int len = entry.attributes.size();
+                       for (int i = 0; i < len; i++) {
+                               Attribute attr = entry.attributes.get(i);
+                               try {
+                                       if (attr.tag == DwarfConstants.DW_AT_sibling) {
+                                               if (attr.form == DwarfConstants.DW_FORM_ref_udata) {
+                                                       sibling = DwarfInfoReader.read_unsigned_leb128(in);
+                                               } else if (attr.form == DwarfConstants.DW_FORM_ref4) {
+                                                       sibling = in.getInt();
+                                               } else {
+                                                       // TODO: allow other forms for sibling value
+                                                       AttributeValue.skipAttributeValue(attr.form, in, addressSize);
+                                               }
+                                       } else {
+                                               AttributeValue.skipAttributeValue(attr.form, in, addressSize);
+                                       }
+                               } catch (IOException e) {
+                                       EDCDebugger.getMessageLogger().logError(null, e);
+                                       break;
+                               }
+                       }
+
+                       if (sibling != -1)
+                               in.position(sibling);
+               }
+
+
+               public byte getActualForm() {
+                       return actualForm;
+               }
+
+               /**
+                * Get the value as a 64-bit signed long, sign-extending any shorter attribute
+                * @return value as signed long
+                */
+               public long getValueAsSignedLong() {
+                       if (value instanceof Number) {
+                               return ((Number) value).longValue();
+                       }
+                       return 0;
+               }
+               
+               /**
+                * Get the value as a 64-bit long.
+                * 
+                * A Byte, Short, or Integer is zero-extended.
+                * 
+                * @return value as long
+                */
+               public long getValueAsLong() {
+                       if (value instanceof Byte) {
+                               return ((Byte) value).byteValue() & 0xff;
+                       }
+                       if (value instanceof Short) {
+                               return ((Short) value).shortValue() & 0xffff;
+                       }
+                       if (value instanceof Integer) {
+                               return ((Integer) value).intValue() & 0xffffffff;
+                       }
+                       // fallthrough
+                       if (value instanceof Number) {
+                               return ((Number) value).longValue();
+                       }
+                       return 0;
+               }
+               
+               /**
+                * Get the value as a 32-bit int.
+                * 
+                * A Byte or Short is zero-extended.
+                * 
+                * @return value as int
+                */
+               public int getValueAsInt() {
+                       if (value instanceof Byte) {
+                               return ((Byte) value).byteValue() & 0xff;
+                       }
+                       if (value instanceof Short) {
+                               return ((Short) value).shortValue() & 0xffff;
+                       }
+                       // fallthrough
+                       if (value instanceof Number) {
+                               return ((Number) value).intValue();
+                       }
+                       return 0;
+               }
+               
+               /**
+                * Get the value as a string
+                * @return String or "" if not a string
+                */
+               public String getValueAsString() {
+                       if (value != null)
+                               return value.toString();
+                       return null;
+               }
+
+               /**
+                * Get the byte array value (which is empty if this is not a byte array)
+                * @return array
+                */
+               public byte[] getValueAsBytes() {
+                       if (value instanceof byte[])
+                               return (byte[]) value;
+                       return new byte[0];
+               }
+       }
+
+       static class AttributeList {
+
+               Map<Short, AttributeValue> attributeMap;
+
+               AttributeList(AbbreviationEntry entry, IStreamBuffer in, byte addressSize, IStreamBuffer debugStrings) {
+
+                       int len = entry.attributes.size();
+                       attributeMap = new HashMap<Short, AttributeValue>(len);
+                       for (int i = 0; i < len; i++) {
+                               Attribute attr = entry.attributes.get(i);
+                               attributeMap.put(Short.valueOf(attr.tag), new AttributeValue(attr.form, in, addressSize, debugStrings));
+                       }
+
+               }
+
+               public static void skipAttributes(AbbreviationEntry entry, IStreamBuffer in, byte addressSize) {
+
+                       int len = entry.attributes.size();
+                       for (int i = 0; i < len; i++) {
+                               Attribute attr = entry.attributes.get(i);
+                               try {
+                                       AttributeValue.skipAttributeValue(attr.form, in, addressSize);
+                               } catch (IOException e) {
+                                       EDCDebugger.getMessageLogger().logError(null, e);
+                                       break;
+                               }
+                       }
+
+               }       
+
+               public long getAttributeValueAsLong(short attributeName) {
+                       AttributeValue attr = attributeMap.get(Short.valueOf(attributeName));
+                       if (attr != null) {
+                               return attr.getValueAsLong();
+                       }
+                       return 0;
+               }
+
+               public int getAttributeValueAsInt(short attributeName) {
+                       AttributeValue attr = attributeMap.get(Short.valueOf(attributeName));
+                       if (attr != null) {
+                               return attr.getValueAsInt();
+                       }
+                       return 0;
+               }
+
+
+               public long getAttributeValueAsSignedLong(short attributeName) {
+                       AttributeValue attr = attributeMap.get(Short.valueOf(attributeName));
+                       if (attr != null) {
+                               return attr.getValueAsSignedLong();
+                       }
+                       return 0;
+               }
+               
+               public String getAttributeValueAsString(short attributeName) {
+                       AttributeValue attr = attributeMap.get(Short.valueOf(attributeName));
+                       if (attr != null) {
+                               return attr.getValueAsString();
+                       }
+                       return ""; //$NON-NLS-1$
+               }
+
+               public byte[] getAttributeValueAsBytes(short attributeName) {
+                       AttributeValue attr = attributeMap.get(Short.valueOf(attributeName));
+                       if (attr != null) {
+                               return attr.getValueAsBytes();
+                       }
+                       return new byte[0];
+               }
+
+               public AttributeValue getAttribute(short attributeName) {
+                       return attributeMap.get(Short.valueOf(attributeName));
+               }
+
+               /**
+                * Tell whether the attributes do not have a code range.
+                * <p> 
+                * Note: a singular DW_AT_low_pc means an entry point
+                * <p>
+                * Also note: a compile unit can have code represented by DW_AT_stmt_list
+                * @return true if the attributes represent code
+                */
+               public boolean hasCodeRangeAttributes() {
+                       return attributeMap.containsKey(DwarfConstants.DW_AT_high_pc)
+                       ||  attributeMap.containsKey(DwarfConstants.DW_AT_ranges);
+               }
+       }
+       
+       static public class PublicNameInfo {
+               public final String nameWithNameSpace;
+               public final CompilationUnitHeader cuHeader;
+               public final short tag; // DW_TAG_xxx
+               
+               public PublicNameInfo(String nameWithNameSpace, CompilationUnitHeader cuHeader, short tag) {
+                       this.nameWithNameSpace = nameWithNameSpace;
+                       this.cuHeader = cuHeader;
+                       this.tag = tag;
+               }
+       }
+       
+       // list of compilation units per source file 
+       protected HashMap<IPath, List<ICompileUnitScope>> compileUnitsPerFile = new HashMap<IPath, List<ICompileUnitScope>>();
+       
+       // list of compile units in .debug_info order
+       protected ArrayList<DwarfCompileUnit> compileUnits = new ArrayList<DwarfCompileUnit>();
+
+       // list of compile units with code (non-zero high address), sorted by low address
+       protected ArrayList<DwarfCompileUnit> sortedCompileUnitsWithCode = new ArrayList<DwarfCompileUnit>();
+
+       // function and type declarations can be referenced by offsets relative to
+       // the compile unit or to the entire .debug_info section. therefore we keep
+       // maps by .debug_info offset, and for compile unit relative offsets, we
+       // just add the compile unit offset into the .debug_info section.
+       protected Map<Long, AttributeList> functionsByOffset = new HashMap<Long, AttributeList>();
+       protected Map<Long, IType> typesByOffset = Collections.synchronizedMap(new HashMap<Long, IType>());
+
+       // for casting to a type, keep certain types by name
+       protected Map<String, List<IType>> typesByName = new HashMap<String, List<IType>>();
+       // for casting to a type, track whether the cast name includes an aggregate designator
+       enum TypeAggregate { Class, Struct, Union, None };
+
+       // map of entities which created scopes
+       protected Map<Long, Scope> scopesByOffset = new HashMap<Long, Scope>();
+       
+       // entry points for CUs in the .debug_info section, used to dynamically parse CUs as needed 
+       protected TreeMap<Long, CompilationUnitHeader> debugOffsetsToCompileUnits = new TreeMap<Long, CompilationUnitHeader>();
+       
+       // forward references for tags we have not parsed yet.  (These will go into typesByOffset once handled)
+       //Map<Long, ForwardDwarfDefinition> forwardDwarfDefinitions = new HashMap<Long, ForwardDwarfDefinition>();
+       
+       // these are just for faster lookups
+       protected Map<String, List<IFunctionScope>> functionsByName = new HashMap<String, List<IFunctionScope>>();
+       protected Map<String, List<IVariable>> variablesByName = new HashMap<String, List<IVariable>>();
+       protected Map<String, List<PublicNameInfo>> publicFunctions = new HashMap<String, List<PublicNameInfo>>();
+       protected Map<String, List<PublicNameInfo>> publicVariables = new HashMap<String, List<PublicNameInfo>>();
+
+       // abbreviation tables (lists of abbrev entries), mapped by .debug_abbrev offset
+       protected Map<Integer, Map<Long, AbbreviationEntry>> abbreviationMaps = new HashMap<Integer, Map<Long, AbbreviationEntry>>();
+
+       // mapping of PC range to frame description entries
+       protected TreeMap<IRangeList.Entry, FrameDescriptionEntry> frameDescEntries = new TreeMap<IRangeList.Entry, FrameDescriptionEntry>();
+       // mapping of CIE offsets to parsed common info entries
+       protected Map<Long, CommonInformationEntry> commonInfoEntries = new HashMap<Long, CommonInformationEntry>();
+       
+       
+       protected Set<String> referencedFiles = new HashSet<String>();
+       protected boolean buildReferencedFilesList = true;
+       
+       private IPath symbolFilePath;
+       private long symbolFileLastModified;
+       private boolean parsedInitially = false;
+       private boolean parsedForVarsAndAddresses = false;
+       private boolean parsedForScopesAndAddresses = false;
+       private boolean parsedForTypes = false;
+       private boolean parsedForGlobalVars = false;
+       
+       private final IExecutableSymbolicsReader exeReader;
+       private final DwarfModuleScope moduleScope;
+
+       final DwarfFileHelper fileHelper;
+
+       private IFrameRegisterProvider frameRegisterProvider;
+       
+       private static String SOURCE_FILES_CACHE = "_source_files"; //$NON-NLS-1$
+
+       public DwarfDebugInfoProvider(IExecutableSymbolicsReader exeReader) {
+               this.exeReader = exeReader;
+               this.symbolFilePath = exeReader.getSymbolFile();
+               this.symbolFileLastModified = symbolFilePath.toFile().lastModified();
+               this.moduleScope = new DwarfModuleScope(this);
+               this.fileHelper = new DwarfFileHelper(symbolFilePath);
+               this.frameRegisterProvider = new DwarfFrameRegisterProvider(this);
+       }
+       
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return DwarfMessages.DwarfDebugInfoProvider_DwarfProviderFor + symbolFilePath;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IDebugInfoProvider#dispose()
+        */
+       public void dispose() {
+               // several views in DSF hold onto all our debug info, 
+               // so go through and explicitly break links
+               if (moduleScope != null) {
+                       moduleScope.dispose();
+               }
+               
+               // help GC
+               compileUnitsPerFile.clear();
+               compileUnits.clear();
+               functionsByOffset.clear();
+               typesByOffset.clear();
+               scopesByOffset.clear();
+               debugOffsetsToCompileUnits.clear();
+               functionsByName.clear();
+               variablesByName.clear();
+               publicFunctions.clear();
+               publicVariables.clear();
+               abbreviationMaps.clear();
+               referencedFiles.clear();
+               moduleScope.dispose();
+               parsedInitially = false;
+               parsedForTypes = false;
+               parsedForVarsAndAddresses = false;
+               parsedForScopesAndAddresses = false;
+               
+               fileHelper.dispose();
+               frameRegisterProvider.dispose();
+       }
+
+       void ensureParsedInitially() {
+               if (!parsedInitially) {
+                       DwarfInfoReader reader = new DwarfInfoReader(this);
+                       parsedInitially = true;
+                       reader.parseInitial();
+               }
+       }
+
+       void ensureParsedForScopes() {
+               if (!parsedForScopesAndAddresses) {
+                       DwarfInfoReader reader = new DwarfInfoReader(this);
+                       if (!parsedInitially) {
+                               parsedInitially = true;
+                               reader.parseInitial();
+                       }
+                       parsedForScopesAndAddresses = true;
+                       reader.parseForAddresses(false);
+               }
+       }
+
+       void ensureParsedForScope(IAddress linkAddress) {
+               DwarfInfoReader reader = new DwarfInfoReader(this);
+               if (!parsedInitially) {
+                       parsedInitially = true;
+                       reader.parseInitial();
+               }
+               reader.parseForAddress(linkAddress);
+       }
+
+       void ensureParsedForVariables() {
+               if (!parsedForVarsAndAddresses) {
+                       DwarfInfoReader reader = new DwarfInfoReader(this);
+                       if (!parsedInitially) {
+                               parsedInitially = true;
+                               reader.parseInitial();
+                       }
+                       parsedForVarsAndAddresses = true;
+                       reader.parseForAddresses(true);
+               }
+       }
+       
+       private void ensureParsedForGlobalVariables() {
+               if (parsedForGlobalVars)
+                       return;
+               parsedForGlobalVars = true;
+
+               if (publicVariables.size() == 0)
+                       return;
+
+               // determine compilation units containing globals
+               HashSet<CompilationUnitHeader> cuWithGlobalsArray = new HashSet<CompilationUnitHeader>(publicVariables.size());
+               for (List<PublicNameInfo> infoList : publicVariables.values()) {
+                       for (PublicNameInfo info : infoList) {
+                               cuWithGlobalsArray.add(info.cuHeader);
+                       }
+               }
+
+               // parse compilation units containing global variables
+               DwarfInfoReader reader = new DwarfInfoReader(this);
+               for (CompilationUnitHeader cuHeader : cuWithGlobalsArray)
+                       reader.parseCompilationUnitForAddresses(cuHeader.scope);
+       }
+
+       void ensureParsedForTypes() {
+               if (!parsedForTypes) {
+                       DwarfInfoReader reader = new DwarfInfoReader(this);
+                       if (!parsedInitially) {
+                               parsedInitially = true;
+                               reader.parseInitial();
+                       }
+                       parsedForTypes = true;
+                       reader.parseForTypes();
+               }
+       }
+
+       public void setParsedInitially() {
+               parsedInitially = true;
+       }
+
+       public void setParsedForAddresses() {
+               parsedForVarsAndAddresses = true;
+       }
+
+       public IPath getSymbolFile() {
+               return symbolFilePath;
+       }
+
+       public IModuleScope getModuleScope() {
+               return moduleScope;
+       }
+       
+       public IAddress getBaseLinkAddress() {
+               return exeReader.getBaseLinkAddress();
+       }
+
+       public Collection<IFunctionScope> getFunctionsByName(String name) {
+               List<IFunctionScope> result;
+
+               ensureParsedInitially();
+               
+               String baseName = name;
+               
+               /*  use same semantics as before, where qualified name lookups would fail               
+               // pubnames uses qualified names but is indexed by basename
+               if (name != null) {
+                       int baseStart = name.lastIndexOf("::");
+                       if (baseStart != -1)
+                               baseName = name.substring(baseStart + 2);
+               }
+               */
+               
+               // first, match against public function names
+               if (publicFunctions.size() > 0) {
+                       if (name != null) {
+                               DwarfInfoReader reader = new DwarfInfoReader(this);
+                               List<PublicNameInfo> nameMatches = publicFunctions.get(baseName);
+
+                               if (nameMatches != null) {
+                                       // parse the compilation units that have matches
+                                       if (nameMatches.size() == 1) { // quick usual case
+                                               reader.parseCompilationUnitForAddresses(nameMatches.get(0).cuHeader.scope);
+                                       } else {
+                                               ArrayList<DwarfCompileUnit> cuList = new ArrayList<DwarfCompileUnit>(); 
+       
+                                               for (PublicNameInfo info : nameMatches) {
+                                                       if (!cuList.contains(info.cuHeader.scope)) {
+                                                               cuList.add(info.cuHeader.scope);
+                                                       }
+                                               }
+       
+                                               for (DwarfCompileUnit cu : cuList) {
+                                                       reader.parseCompilationUnitForAddresses(cu);
+                                               }
+                                       }
+                               } else {
+                                       // not a public name, so parse all compilation units looking for functions
+                                       ensureParsedForScopes();
+                               }
+                       } else {
+                               // name is null, so parse all compilation units looking for functions
+                               ensureParsedForScopes();
+                       }
+               } else {
+                       // no public names, so parse all compilation units looking for functions
+                       ensureParsedForScopes();
+               }
+               
+               if (name != null) {
+                       result = functionsByName.get(baseName);
+                       if (result == null)
+                               return new ArrayList<IFunctionScope>(0);
+               } else {
+                       result = new ArrayList<IFunctionScope>(functionsByName.size()); // at least this big
+                       for (List<IFunctionScope> functions : functionsByName.values())
+                               result.addAll(functions);
+                       ((ArrayList<IFunctionScope>) result).trimToSize();
+               }
+               return Collections.unmodifiableCollection(result);
+       }
+
+       public Collection<IVariable> getVariablesByName(String name, boolean globalsOnly) {
+               List<IVariable> result;
+
+               ensureParsedInitially();
+
+               if (name == null) {
+                       if (publicVariables.size() > 0) {
+                               // name is null, so parse all compilation units looking for variables
+                               if (globalsOnly)
+                                       ensureParsedForGlobalVariables();
+                               else
+                                       ensureParsedForVariables();
+                       }
+                       
+                       result = new ArrayList<IVariable>(variablesByName.size()); // at least this big
+                       for (List<IVariable> variables : variablesByName.values())
+                               result.addAll(variables);
+
+                       return Collections.unmodifiableCollection(result);
+               }
+
+               String baseName = name;
+               int baseNameStart = name.lastIndexOf("::"); //$NON-NLS-1$
+               if (baseNameStart != -1)
+                       baseName = name.substring(baseNameStart + 2);
+
+               // match against public variable names, which the initial parse populated
+               if (publicVariables.size() > 0) {
+                       DwarfInfoReader reader = new DwarfInfoReader(this);
+                       List<PublicNameInfo> nameMatches = publicVariables.get(baseName);
+
+                       if (nameMatches != null) {
+                               // parse the compilation units that have matches
+                               if (nameMatches.size() == 1) { // quick usual case
+                                       reader.parseCompilationUnitForAddresses(nameMatches.get(0).cuHeader.scope);
+                               } else {
+                                       ArrayList<DwarfCompileUnit> cuList = new ArrayList<DwarfCompileUnit>(); 
+
+                                       for (PublicNameInfo info : nameMatches) {
+                                               if (!cuList.contains(info.cuHeader.scope)) {
+                                                       cuList.add(info.cuHeader.scope);
+                                               }
+                                       }
+
+                                       for (DwarfCompileUnit cu : cuList) {
+                                               reader.parseCompilationUnitForAddresses(cu);
+                                       }
+                               }
+                       } else {
+                               // not a public name, so parse all compilation units looking for variables
+                               if (!globalsOnly)
+                                       ensureParsedForVariables();
+                       }
+               }
+
+               result = variablesByName.get(name);
+
+               // check against unqualified name because RVCT 2.x did not include namespace
+               // info for globals that are inside namespaces
+               if (result == null && baseNameStart != -1)
+                       result = variablesByName.get(baseName);
+                       
+               if (result == null)
+                       return new ArrayList<IVariable>(0);
+
+               return Collections.unmodifiableCollection(result);
+       }
+
+       /**
+        * @return the publicFunctions
+        */
+       public Map<String, List<PublicNameInfo>> getPublicFunctions() {
+               ensureParsedInitially();
+               return publicFunctions;
+       }
+       /**
+        * @return the publicVariables
+        */
+       public Map<String, List<PublicNameInfo>> getPublicVariables() {
+               ensureParsedInitially();
+               return publicVariables;
+       }
+
+       public ICompileUnitScope getCompileUnitForAddress(IAddress linkAddress) {
+               ensureParsedForScope(linkAddress);
+               
+               IScope scope = moduleScope.getScopeAtAddress(linkAddress);
+               while (scope != null && !(scope instanceof ICompileUnitScope)) {
+                       scope = scope.getParent();
+               }
+
+               return (ICompileUnitScope) scope;
+       }
+
+       public List<ICompileUnitScope> getCompileUnitsForFile(IPath filePath) {
+               ensureParsedInitially();
+
+               List<ICompileUnitScope> cuList = compileUnitsPerFile.get(filePath);
+               
+               if (cuList != null)
+                       return cuList;
+               
+               // FIXME: we need a looser check here: on Windows, we added drive letters to all
+               // paths before populating compileUnitsPerFile, even if there is not really a
+               // drive (see DwarFileHelper).
+               for (Map.Entry<IPath, List<ICompileUnitScope>> entry : compileUnitsPerFile.entrySet()) {
+                       if (entry.getKey().setDevice(null).equals(filePath.setDevice(null))) {
+                               return entry.getValue();
+                       }
+               }
+               
+               return Collections.emptyList();
+       }
+
+       @SuppressWarnings("unchecked")
+       public String[] getSourceFiles(IProgressMonitor monitor) {
+               if (referencedFiles.isEmpty()) {
+                       // Check the persistent cache
+                       String cacheKey = getSymbolFile().toOSString() + SOURCE_FILES_CACHE;
+                       Set<String> cachedFiles = EDCDebugger.getDefault().getCache().getCachedData(cacheKey, Set.class, symbolFileLastModified);
+                       if (cachedFiles == null)
+                       {
+                               DwarfInfoReader reader = new DwarfInfoReader(this);
+                               reader.quickParseDebugInfo(monitor);
+                               assert referencedFiles.size() > 0;
+                               EDCDebugger.getDefault().getCache().putCachedData(cacheKey, new HashSet<String>(referencedFiles), symbolFileLastModified);
+                       }
+                       else
+                               referencedFiles = cachedFiles;
+               }
+
+               return referencedFiles.toArray(new String[referencedFiles.size()]);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IDebugInfoProvider#getTypes()
+        */
+       public Collection<IType> getTypes() {
+               ensureParsedForTypes();
+               
+               ArrayList<IType> types = new ArrayList<IType>(typesByOffset.values());
+               return types;
+       }
+       
+       /////////////////
+       
+       // Lazy evaluation methods
+       
+       
+       /**
+        * Fetch a type lazily.  Either we've already parsed the type, or we have
+        * a reference to it, or we can find its compilation unit and parse its types.  
+        * We do not fix up cross references until someone asks for
+        * it (e.g. from an IType or IVariable implementation).
+        */
+       public IType readType(long offset_) {
+               Long offset = Long.valueOf(offset_); 
+               IType type = typesByOffset.get(offset);
+               if (type == null) {
+                       // make sure we've parsed it
+                       CompilationUnitHeader header = fetchCompileUnitHeader(offset_);
+                       if (header != null) {
+                               DwarfInfoReader reader = new DwarfInfoReader(this);
+                               reader.parseCompilationUnitForTypes(header.scope);
+                               type = typesByOffset.get(offset);
+                               // may be unhandled currently
+                               if (type == null) { 
+                                       // workaround for GCC-E 3.x bug where some, but not all, type offsets are off by 4
+                                       // assume if you hit this null case that the problem may be the GCC-E bug
+                                       type = typesByOffset.get(offset - 4);
+                                       if (type == null)
+                                               EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfDebugInfoProvider_NotParsingType1 + Long.toHexString(offset_) +
+                                                                       DwarfMessages.DwarfDebugInfoProvider_NotParsingType2 + symbolFilePath, null);
+                               }
+                       } else {
+                               // may be unhandled currently
+                               EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfDebugInfoProvider_CannotResolveCompUnit1 + Long.toHexString(offset_) +
+                                                               DwarfMessages.DwarfDebugInfoProvider_CannotResolveCompUnit2 + symbolFilePath, null);
+                       }
+               }
+               return type;
+       }
+       
+
+       /**
+        * Scan compilation unit header for its subprograms and addresses.
+        */
+       public CompilationUnitHeader scanCompilationHeader(long offset_) {
+               // make sure we've parsed it
+               CompilationUnitHeader header = fetchCompileUnitHeader(offset_);
+               if (header != null) {
+                       DwarfInfoReader reader = new DwarfInfoReader(this);
+                       reader.parseCompilationUnitForAddresses(header.scope);
+               }
+               return header;
+       }
+       
+       
+       /**
+        * Fetch a referenced type lazily.
+        * @param scope 
+        */
+       IType resolveTypeReference(ForwardTypeReference ref) {
+               IType type = typesByOffset.get(ref.offset);
+               if (type == null) {
+                       type = readType(ref.offset);
+               }
+               return type;
+       }
+       /**
+        * @return
+        */
+       public IExecutableSymbolicsReader getExecutableSymbolicsReader() {
+               return exeReader;
+       }
+
+       /**
+        * Remember where a compilation unit header lives in the debug info.
+        * @param debugInfoOffset
+        * @param currentCUHeader
+        */
+       public void registerCompileUnitHeader(int debugInfoOffset,
+                       CompilationUnitHeader currentCUHeader) {
+               debugOffsetsToCompileUnits.put((long) debugInfoOffset, currentCUHeader);
+       }
+       
+       /**
+        * Get a compilation unit header that contains the given offset.
+        * @param debugInfoOffset an offset which is on or after a compilation unit's debug offset
+        * @return {@link CompilationUnitHeader} containing the offset
+        */
+       public CompilationUnitHeader fetchCompileUnitHeader(long debugInfoOffset) {
+               CompilationUnitHeader match = debugOffsetsToCompileUnits.get(debugInfoOffset);
+               if (match != null)
+                       return match;
+               
+               // it's inside one
+               SortedMap<Long,CompilationUnitHeader> headMap = debugOffsetsToCompileUnits.headMap(debugInfoOffset);
+               // urgh, sorted map... no easy way to get to the end
+               for (CompilationUnitHeader header : headMap.values()) {
+                       match = header;
+               }
+               return match;
+       }
+
+       /**
+        * Get the frame description entry for the given PC
+        * @param framePC
+        * @return FDE or <code>null</code>
+        */
+       public FrameDescriptionEntry findFrameDescriptionEntry(IAddress framePC) {
+               DwarfInfoReader reader = new DwarfInfoReader(this);
+               if (frameDescEntries.isEmpty()) {
+                       reader.parseForFrameIndices();
+               }
+               
+               long pc = framePC.getValue().longValue();
+               SortedMap<Entry, FrameDescriptionEntry> tailMap = frameDescEntries.tailMap(new IRangeList.Entry(pc, pc));
+               if (tailMap.isEmpty())
+                       return null;
+               
+               FrameDescriptionEntry entry = tailMap.values().iterator().next();
+               if (entry.getCIE() == null) {
+                       CommonInformationEntry cie = null;
+                       if (!commonInfoEntries.containsKey(entry.ciePtr)) {
+                               try {
+                                       cie = reader.parseCommonInfoEntry(entry.ciePtr, entry.addressSize, framePC);
+                               } catch (IOException e) {
+                                       EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfDebugInfoProvider_FailedToReadCIE + entry.ciePtr, e);
+                               }
+                               commonInfoEntries.put(entry.ciePtr, cie);
+                       } else {
+                               cie = commonInfoEntries.get(entry.ciePtr);
+                       }
+                       entry.setCIE(cie);
+               }
+               
+               return entry;
+       }
+
+       /**
+        * @return
+        */
+       public IFrameRegisterProvider getFrameRegisterProvider() {
+               return frameRegisterProvider;
+       }
+
+       /*
+        * (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IDebugInfoProvider#getTypesByName(java.lang.String)
+        */
+       public Collection<IType> getTypesByName(String name) {
+               // is name has "struct", "class" or "union", search without that
+               name = name.trim();
+               
+               String baseName = name;
+               TypeAggregate aggregate = TypeAggregate.None;
+               
+               if (baseName.startsWith("class ")) { //$NON-NLS-1$
+                       aggregate = TypeAggregate.Class;
+                       baseName = baseName.replace("class ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+               } else if (baseName.startsWith("struct ")) { //$NON-NLS-1$
+                       aggregate = TypeAggregate.Struct;
+                       baseName = baseName.replace("struct ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+               } else if (baseName.startsWith("union ")) { //$NON-NLS-1$
+                       aggregate = TypeAggregate.Union;
+                       baseName = baseName.replace("union ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+               }
+               
+               Collection<IType> types = typesByName.get(baseName);
+               
+               String templateName  = null;
+               String templateName2 = null;
+
+               if (types == null) {
+                       // if we didn't match and this is a template name,
+                       // remove extra spaces and composite type names 
+                       if (baseName.indexOf('<') != -1) {
+                               templateName = baseName;
+
+                               while (templateName.contains("  ")) //$NON-NLS-1$
+                                       templateName = templateName.replaceAll("  ", " "); //$NON-NLS-1$ //$NON-NLS-2$
+                               templateName = templateName.replaceAll(", ", ","); //$NON-NLS-1$ //$NON-NLS-2$
+                               templateName = templateName.replaceAll("class ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                               templateName = templateName.replaceAll("struct ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                               templateName = templateName.replaceAll("union ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+                               types = typesByName.get(templateName);
+
+                               // template name without "<...>", rather than with "<...>", might match 
+                               if (types == null) {
+                                       templateName2 = templateName.substring(0, templateName.indexOf('<'));
+
+                                       types = typesByName.get(templateName2);
+
+                                       // screen out types whose template list does not match
+                                       if (types != null) {
+                                               ArrayList<IType> matchingTypes = null;
+                                               for (Iterator<IType> it = types.iterator(); it.hasNext(); ) {
+                                                       IType nextType = it.next();
+                                                       String match = nextType.getName();
+                                                       // for templates, remove composite type names (e.g., "class")
+                                                       match = match.replaceAll("class ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                                                       match = match.replaceAll("struct ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                                                       match = match.replaceAll("union ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+                                                       if (match.equals(templateName)) {
+                                                               if (matchingTypes == null)
+                                                                       matchingTypes = new ArrayList<IType>(types.size());
+                                                               matchingTypes.add(nextType);
+                                                       }
+                                               }
+                                               types = matchingTypes; // may be null
+                                       }
+                               }
+                       }
+
+                       if (types == null) {
+                               // Maybe we optimistically searched for relevant types;
+                               // if that fails, do the full parse of types now
+                               if (!parsedForTypes) {
+                                       ensureParsedForTypes();
+                                       types = getTypesByName(baseName);
+                                       if (types != null)
+                                               return types; // non-template return
+
+                                       if (baseName.indexOf('<') != -1) {
+                                               types = typesByName.get(templateName);
+                                               if (types == null)
+                                                       types = typesByName.get(templateName2);
+                                               else
+                                                       templateName2 = null; // did not match name without "<...>"
+                                       }
+                               }
+                               
+                               if (types == null)
+                                       return new ArrayList<IType>(0);
+                       }
+               }
+
+               // screen out types whose template list does not match
+               if (templateName2 != null) {
+                       ArrayList<IType> matchingTypes = new ArrayList<IType>(types.size());
+                       for (Iterator<IType> it = types.iterator(); it.hasNext(); ) { // types can't be null
+                               IType nextType = it.next();
+                               String match = nextType.getName();
+                               // for templates, remove composite type names (e.g., "class")
+                               match = match.replaceAll("class ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                               match = match.replaceAll("struct ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                               match = match.replaceAll("union ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+                               if (match.equals(templateName))
+                                       matchingTypes.add(nextType);
+                       }
+                       types = matchingTypes;
+               }
+               
+               // make sure that the aggregate type matches as well as the name
+               if (aggregate == TypeAggregate.None)
+                       return Collections.unmodifiableCollection(types);
+               
+               Iterator<IType> itr = types.iterator();
+               while (itr.hasNext()) {
+                       IType nextType = itr.next();
+                       if ((aggregate == TypeAggregate.Class  && !nextType.getName().contains("class ")) || //$NON-NLS-1$
+                               (aggregate == TypeAggregate.Struct && !nextType.getName().contains("struct ")) || //$NON-NLS-1$
+                           (aggregate == TypeAggregate.Union  && !nextType.getName().contains("union "))) //$NON-NLS-1$
+                               types.remove(nextType);
+               }
+
+               if (types.isEmpty())
+                       return new ArrayList<IType>(0);
+               
+               return Collections.unmodifiableCollection(types);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfDebugInfoProviderFactory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfDebugInfoProviderFactory.java
new file mode 100644 (file)
index 0000000..6e42b72
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.files.ExecutableSymbolicsReaderFactory;
+import org.eclipse.cdt.debug.edc.symbols.IDebugInfoProvider;
+import org.eclipse.cdt.debug.edc.symbols.IDebugInfoProviderFactory;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * 
+ */
+public class DwarfDebugInfoProviderFactory implements
+               IDebugInfoProviderFactory {
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IDebugInfoProviderFactory#createDebugInfoProvider(org.eclipse.core.runtime.IPath)
+        */
+       public IDebugInfoProvider createDebugInfoProvider(IPath binaryPath, IExecutableSymbolicsReader exeReader) {
+               // DWARF info lives either in the executable itself or in an associated symbol file.
+               if (exeReader != null) {
+                       if (exeReader.findExecutableSection(DwarfInfoReader.DWARF_DEBUG_INFO) != null) {
+                               return new DwarfDebugInfoProvider(exeReader);
+                       }
+               }
+               
+               // else, look alongside for a *.sym or *.dbg file
+               IPath symFile = ExecutableSymbolicsReaderFactory.findSymbolicsFile(binaryPath);
+               if (symFile != null) {
+                       IExecutableSymbolicsReader symExeReader = ExecutableSymbolicsReaderFactory.createFor(symFile);
+                       if (symExeReader != null) {
+                               return new DwarfDebugInfoProvider(symExeReader);
+                       }
+               }
+               
+               // no one has DWARF
+               return null;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFileHelper.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFileHelper.java
new file mode 100644 (file)
index 0000000..87ee718
--- /dev/null
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.internal.HostOS;
+import org.eclipse.cdt.debug.edc.internal.PathUtils;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * An instance of this class per DwarfDebugInfoProvider assists in
+ * canonicalizing filepaths (from DW_AT_comp_dir and DW_AT_stmt_list)
+ */
+public class DwarfFileHelper {
+
+       private boolean DEBUG = false;
+       
+       @SuppressWarnings("unused") // no longer used, but kept for compatibility and possible futureuse
+       private final IPath symbolFile;
+       
+       private Map<String, IPath> compDirAndNameMap;
+       
+       private int hits;
+       private long nextDump;
+       
+       public DwarfFileHelper(IPath symbolFile) {
+               this.symbolFile = symbolFile;
+               this.compDirAndNameMap = new HashMap<String, IPath>();
+       }
+       
+       protected String getKey(String compDir, String name) {
+               return compDir + "/" + name;
+       }
+       
+       /**
+        * This is to combine the given compDir and file name from Dwarf to form a
+        * file path. Some processing is done to canonicalize the path, including <br>
+        * -- extra path delimiter are removed. <br>
+        * -- "a/b/" and "../c/d" are combined to "/a/c/d". <br>
+        * -- change path delimiter to native, namely on Windows "/" => "\\" and the
+        * opposite on unix/linux
+        * 
+        * @param compDir
+        *            compDir from dwarf data.
+        * @param name
+        *            file name from dwarf data with full or partial or no path.
+        * @return most complete file path that we can get from Dwarf data, which
+        *         may still be a partial path. Note letter case of the names
+        *         remains unchanged. Empty string is returned if the given name is
+        *         an invalid file name, e.g. <internal>.
+        * 
+        */
+       public IPath normalizeFilePath(String compDir, String name) {
+               if (name == null || name.length() == 0)
+                       return null;
+
+               // don't count the entry "<internal>" from GCCE compiler
+               if (name.charAt(0) == '<')
+                       return null;
+
+               // Create a key for doing a lookup in our IPath cache 
+               String key = getKey(compDir, name);
+
+               // Look in the cache
+               IPath path = compDirAndNameMap.get(key);
+               if (path == null) {
+                       path = normalizePath(compDir, name);
+                       compDirAndNameMap.put(key, path);
+               } else {
+                       hits++;
+               }
+               if (DEBUG && System.currentTimeMillis() > nextDump) {
+                       System.out.println("DwarfFileHelper entries: " + compDirAndNameMap.size() + "; hits: " + hits);
+                       nextDump = System.currentTimeMillis() + 1000;
+               }
+               return path;
+       }
+
+       /**
+        * Takes a DW_AT_comp_dir and a filename from DWARF,
+        * canonicalizes it and creates an IPath.
+        * 
+        * @param compDir the compilation directory, as found in DWARF data
+        * @param name the file specification, as found in DWARF data
+        * @return IPath, never <code>null</code>
+        */
+       private IPath normalizePath(String compDir, String name) {
+
+               String fullName = name;
+
+               IPath path = PathUtils.createPath(name);
+
+               // Combine dir & name if needed.
+               if (!path.isAbsolute() && compDir.length() > 0) {
+                       fullName = compDir;
+                       if (!compDir.endsWith(File.separator))
+                               fullName += File.separatorChar;
+                       fullName += name;
+
+                       path = PathUtils.createPath(fullName);
+               }
+
+               return path;
+       }
+
+       /**
+        * Convert cygwin path and change path delimiter to native.
+        * No longer used but left for backwards compatbility.
+        * 
+        * @param path
+        * @return
+        */
+       public IPath fixUpPath(String path) {
+               /*
+                * translate cygwin drive path like /cygdrive/c/system/main.c
+                * //G/System/main.cpp
+                */
+               boolean isCygwin = false;
+               int deleteTill = 0;
+               
+               // These paths may appear in Cygwin-compiled code, so check on any host
+               if (path.length() > 12 && path.startsWith("/cygdrive/") && ('/' == path.charAt(11))) { //$NON-NLS-1$
+                       isCygwin = true;
+                       deleteTill = 10;
+               }
+
+               // These paths may appear in Cygwin-compiled code, so check on any host
+               if (path.length() > 4 && path.startsWith("//") && ('/' == path.charAt(3))) { //$NON-NLS-1$
+                       isCygwin = true;
+                       deleteTill = 2;
+               }
+
+               // New-style Cygwin is different and has neither prefix.  
+               // But this check only makes sense on a Windows host, since
+               // it may be a valid Unix-host path.
+               //
+               //      /C/sources/foo.c --> c:\sources\foo.c
+               if (HostOS.IS_WIN32 && path.length() > 3 
+                               && path.charAt(0) == '/'
+                               && Character.isLetter(path.charAt(1))
+                               && path.charAt(2) == '/') {
+                       isCygwin = true;
+                       deleteTill = 1;
+               }
+               
+               if (isCygwin) {
+                       StringBuilder buf = new StringBuilder(path);
+                       buf.delete(0, deleteTill);
+                       buf.insert(1, ':');
+                       path = buf.toString();
+               }
+
+               // convert to path on runtime platform
+               //
+               return PathUtils.createPath(path);
+       }
+
+       /**
+        * 
+        */
+       public void dispose() {
+               compDirAndNameMap.clear();
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFrameRegisterProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFrameRegisterProvider.java
new file mode 100644 (file)
index 0000000..1d79354
--- /dev/null
@@ -0,0 +1,950 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import java.util.TreeMap;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.MemoryStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC;
+import org.eclipse.cdt.debug.edc.internal.symbols.MemoryVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.RegisterOffsetVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.RegisterVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.ValueVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.AttributeValue;
+import org.eclipse.cdt.debug.edc.services.IEDCModuleDMContext;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.services.IFrameRegisterProvider;
+import org.eclipse.cdt.debug.edc.services.IFrameRegisters;
+import org.eclipse.cdt.debug.edc.services.Registers;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.symbols.IRangeList;
+import org.eclipse.cdt.debug.edc.symbols.IRangeList.Entry;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Apply the rules for the CIE and FDE to a given frame.
+ */
+public class DwarfFrameRegisterProvider implements IFrameRegisterProvider {
+       
+       public static class InstructionState {
+               public EDCServicesTracker tracker;
+               /**  Calculated register locations for the current frame */
+               public Map<Integer, AbstractRule> regRules;
+               /**  Context for the current frame */
+               public IFrameDMContext context;
+               /**  Accessor for registers from child frame */
+               public IFrameRegisters childRegisters;
+               /**  Initial locations from CIE */
+               public Map<Integer, AbstractRule> initialRules;
+               /**  Implicit stack for DW_CFA_remember_state and DW_CFA_restore_state*/
+               public Stack<Map<Integer, AbstractRule>> stateStack;
+               
+               CFARegisterRule cfaRegRule = new CFARegisterRule(0, 0);
+               
+               private final int addressSize;
+               public boolean cfaOffsetsAreReversed;
+               
+               public InstructionState(EDCServicesTracker tracker,
+                               IFrameDMContext context,
+                               IFrameRegisters childRegisters,
+                               FrameDescriptionEntry fde) {
+                       this.tracker = tracker;
+                       this.addressSize = fde.addressSize;
+                       this.cfaOffsetsAreReversed = fde.getCIE().cfaOffsetsAreReversed;
+                       this.regRules = new TreeMap<Integer, AbstractRule>();
+                       this.stateStack = new Stack<Map<Integer,AbstractRule>>();
+                       this.initialRules = new TreeMap<Integer, AbstractRule>();
+       
+                       this.context = context;
+                       this.childRegisters = childRegisters;
+                       //this.cfaValue = BigInteger.ZERO;
+               }
+
+               // pseudo register for current CFA
+               public static final int CFA = -1;
+               
+               /**
+                * Read the current CFA.
+                * @return
+                */
+               public BigInteger readCFA() throws CoreException {
+                       BigInteger regval = childRegisters.getRegister(cfaRegRule.regnum, addressSize);
+                       return regval.add(BigInteger.valueOf(cfaOffsetsAreReversed ? -cfaRegRule.offset : cfaRegRule.offset));
+               }
+
+               /**
+                * Get the register which is the CFA base.
+                * @return register number
+                */
+               public int getCFARegister() {
+                       return cfaRegRule.regnum;
+               }
+               
+               
+       };
+       
+       public static abstract class AbstractRule {
+               public abstract IVariableLocation evaluate(InstructionState state) throws CoreException;
+       }
+       
+       static class ErrorRule extends AbstractRule {
+               private String message;
+
+               public ErrorRule(String message) {
+                       this.message = message;
+               }
+               @Override
+               public String toString() {
+                       return "error: " + message;
+               }
+               
+               @Override
+               public IVariableLocation evaluate(InstructionState state) throws CoreException {
+                       throw EDCDebugger.newCoreException(message);
+               }
+       }
+       
+       static class UndefinedRule extends AbstractRule {
+               private final int regnum;
+
+               public UndefinedRule(int regnum) {
+                       this.regnum = regnum;
+               }
+               @Override
+               public String toString() {
+                       return "R"+regnum+": undefined";
+               }
+               @Override
+               public IVariableLocation evaluate(InstructionState state) throws CoreException {
+                       return null;
+               }
+       }
+       
+       static class SameValueRule extends AbstractRule {
+               private final int regnum;
+
+               public SameValueRule(int regnum) {
+                       this.regnum = regnum;
+               }
+               @Override
+               public String toString() {
+                       return "R"+regnum+": same value";
+               }
+               @Override
+               public IVariableLocation evaluate(InstructionState state) throws CoreException {
+                       return new ValueVariableLocation(state.childRegisters.getRegister(regnum, state.addressSize));
+               }
+       }
+       
+       static class OffsetRule extends AbstractRule {
+               private final long offset;
+
+               public OffsetRule(long offset) {
+                       this.offset = offset;
+               }
+               @Override
+               public String toString() {
+                       return "offset("+offset+")";
+               }
+               @Override
+               public IVariableLocation evaluate(InstructionState state) throws CoreException {
+                       BigInteger cfa = state.readCFA();
+                       return new MemoryVariableLocation(state.tracker, state.context, 
+                                       cfa.add(BigInteger.valueOf(offset)), true);
+               }
+       }
+       static class ValueOffsetRule extends AbstractRule {
+               private final long offset;
+
+               public ValueOffsetRule(long offset) {
+                       this.offset = offset;
+               }
+               @Override
+               public String toString() {
+                       return "val_offset("+offset+")";
+               }
+               @Override
+               public IVariableLocation evaluate(InstructionState state) throws CoreException {
+                       BigInteger cfa = state.readCFA();
+                       return new ValueVariableLocation(cfa.add(BigInteger.valueOf(offset)));
+               }
+       }
+       static class RegisterRule extends AbstractRule {
+               private final int regnum;
+
+               public RegisterRule(int regnum) {
+                       this.regnum = regnum;
+               }
+               @Override
+               public String toString() {
+                       return "register("+regnum+")";
+               }
+               @Override
+               public IVariableLocation evaluate(InstructionState state) throws CoreException {
+                       return new RegisterVariableLocation(state.tracker, state.context, null, regnum);
+               }
+       }
+       
+       static class CFARegisterRule extends AbstractRule {
+               private int regnum;
+               private long offset;
+
+               public CFARegisterRule(int regnum, long offset) {
+                       this.regnum = regnum;
+                       this.offset = offset;
+               }
+               @Override
+               public String toString() {
+                       return "["+regnum+"]"+(offset < 0 ? "-" : "+")+Math.abs(offset);
+               }
+               @Override
+               public IVariableLocation evaluate(InstructionState state) throws CoreException {
+                       return new RegisterOffsetVariableLocation(state.tracker, state.context, null, regnum, offset);
+               }
+       }
+       private static ErrorRule UNIMPLEMENTED = new ErrorRule(
+               "unimplemented support for reading this location");
+       
+
+       /** The base class for instructions
+        */
+       public static abstract class AbstractInstruction {
+               
+               public AbstractInstruction() {
+               }
+               
+               /**
+                * Apply this instruction to the state.
+                * @param state 
+                * @throws CoreException
+                */
+               abstract public void applyInstruction(InstructionState state) throws CoreException;
+       }
+       
+       /** The base class for rules that apply to registers 
+        */
+       public static abstract class AbstractRegisterInstruction extends AbstractInstruction {
+               protected final int thereg;
+               
+               public AbstractRegisterInstruction(int thereg) {
+                       super();
+                       this.thereg = thereg;
+               }
+               
+               @Override
+               public String toString() {
+                       return "R"+thereg;
+               }
+       }
+       
+       public static class NopInstruction extends AbstractInstruction {
+
+               public NopInstruction() {
+                       super();
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.AbstractRegisterRule#toString()
+                */
+               @Override
+               public String toString() {
+                       return "nop";
+               }
+               
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.AbstractRegisterRule#applyRule(org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext, java.util.Map, java.util.Map)
+                */
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       
+               }
+               
+       }
+       /** CFA=RN+o */
+       public static class DefCFAInstruction extends AbstractInstruction {
+               long regnum;
+               long offset;
+               public DefCFAInstruction(long regnum, long offset) {
+                       this.regnum = regnum;
+               }
+               @Override
+               public String toString() {
+                       return "CFA := R"+regnum + " + " + offset;
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.cfaRegRule.regnum = (int) regnum;
+                       state.cfaRegRule.offset = offset; 
+               }
+       }
+       
+       /** CFA=RN (+o) */
+       public static class DefCFARegisterInstruction extends AbstractInstruction {
+               long regnum;
+               public DefCFARegisterInstruction(long regnum) {
+                       this.regnum = regnum;
+               }
+               @Override
+               public String toString() {
+                       return "CFA register := R"+regnum;
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.cfaRegRule.regnum = (int) regnum;
+               }
+       }
+       
+
+       /** CFA=(RN) +o */
+       public static class DefCFAOffsetInstruction extends AbstractInstruction {
+               long offset;
+               public DefCFAOffsetInstruction(long offset) {
+                       this.offset = offset;
+               }
+               @Override
+               public String toString() {
+                       return "CFA offset := "+offset;
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.cfaRegRule.offset = offset;
+               }
+       }
+       
+
+       public static class DefCFAExpressionInstruction extends AbstractInstruction {
+               IStreamBuffer expression;
+               public DefCFAExpressionInstruction(IStreamBuffer expression) {
+                       this.expression = expression;
+               }
+               @Override
+               public String toString() {
+                       return "CFA := expression";
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       throw EDCDebugger.newCoreException("CFA expression not implemented");
+               }
+       }
+       
+       public static class SameValueInstruction extends AbstractRegisterInstruction {
+               public SameValueInstruction(int thereg) {
+                       super(thereg);
+               }
+               @Override
+               public String toString() {
+                       return super.toString() + "same value";
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.regRules.put(thereg, new SameValueRule(thereg));
+               }
+       }
+       
+       public static class UndefinedInstruction extends AbstractRegisterInstruction {
+               public UndefinedInstruction(int thereg) {
+                       super(thereg);
+               }
+               @Override
+               public String toString() {
+                       return super.toString() + "undefined";
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.regRules.put(thereg, new UndefinedRule(thereg));
+               }
+       }
+
+       public static class OffsetInstruction extends AbstractRegisterInstruction {
+               long offset;
+
+               public OffsetInstruction(int thereg, long offset) {
+                       super(thereg);
+                       this.offset = offset;
+               }
+               @Override
+               public String toString() {
+                       return super.toString() + "@ CFA + " + offset;
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.regRules.put(thereg, new OffsetRule(offset));
+               }
+       }
+       
+       public static class ValueOffsetInstruction extends AbstractRegisterInstruction {
+               long offset;
+               public ValueOffsetInstruction(int thereg, long offset) {
+                       super(thereg);
+                       this.offset = offset;
+               }
+               @Override
+               public String toString() {
+                       return super.toString() + "CFA + " + offset;
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.regRules.put(thereg, new ValueOffsetRule(offset));
+               }
+       }
+       
+       public static class RegisterInstruction extends AbstractRegisterInstruction {
+               int regnum;
+               public RegisterInstruction(int thereg, int regnum) {
+                       super(thereg);
+                       this.regnum = regnum;
+               }
+               @Override
+               public String toString() {
+                       return super.toString() + "copy R"+regnum;
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       if (state.regRules.containsKey(regnum))
+                               state.regRules.put(thereg, state.regRules.get(regnum));
+                       else
+                               state.regRules.put(thereg, new UndefinedRule(regnum));
+               }
+       }
+       
+       public static class ExpressionInstruction extends AbstractRegisterInstruction {
+               IStreamBuffer expression;
+               public ExpressionInstruction(int thereg, IStreamBuffer expression) {
+                       super(thereg);
+                       this.expression = expression;
+               }
+               @Override
+               public String toString() {
+                       return super.toString() + "@ expression";
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.regRules.put(thereg, UNIMPLEMENTED);
+               }
+       }
+       public static class ValueExpressionInstruction extends AbstractRegisterInstruction {
+               IStreamBuffer expression;
+               public ValueExpressionInstruction(int thereg, IStreamBuffer expression) {
+                       super(thereg);
+                       this.expression = expression;
+               }
+               @Override
+               public String toString() {
+                       return super.toString() + " expression";
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.regRules.put(thereg, UNIMPLEMENTED);
+               }
+       }
+       public static class RestoreInstruction extends AbstractRegisterInstruction {
+               public RestoreInstruction(int thereg) {
+                       super(thereg);
+               }
+               @Override
+               public String toString() {
+                       return super.toString() + " restore";
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       if (state.initialRules.containsKey(thereg))
+                               state.regRules.put(thereg, state.initialRules.get(thereg));
+                       else
+                               state.regRules.remove(thereg);  
+               }
+       }
+       
+       public static class RememberStateInstruction extends AbstractInstruction {
+               public RememberStateInstruction() {
+                       super();
+               }
+               @Override
+               public String toString() {
+                       return "remember state";
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.stateStack.push(new TreeMap<Integer, AbstractRule>(state.regRules));
+               }
+       }
+       public static class RestoreStateInstruction extends AbstractInstruction {
+               public RestoreStateInstruction() {
+                       super();
+               }
+               @Override
+               public String toString() {
+                       return "restore state";
+               }
+               @Override
+               public void applyInstruction(InstructionState state) throws CoreException {
+                       state.regRules.clear();
+                       state.regRules.putAll(state.stateStack.pop());
+               }
+       }
+
+
+       /**
+        * A "CIE" from the .debug_frame section.
+        */
+       public static class CommonInformationEntry {
+       
+               final long codeAlignmentFactor;
+               final long dataAlignmentFactor;
+               final int version;
+               final int returnAddressRegister;
+               final int addressSize;
+               final IStreamBuffer instructions;
+               private List<AbstractInstruction> initialLocations;
+               private CoreException initialLocationsError;
+               private boolean cfaOffsetSfIsFactored;
+               private boolean cfaOffsetsAreReversed;
+               
+               public CommonInformationEntry(long codeAlignmentFactor,
+                               long dataAlignmentFactor, int returnAddressRegister,
+                               int version,
+                               IStreamBuffer instructions,
+                               int addressSize, 
+                               String producer, String augmentation) {
+                       
+                       this.codeAlignmentFactor = codeAlignmentFactor;
+                       this.dataAlignmentFactor = dataAlignmentFactor;
+                       this.returnAddressRegister = returnAddressRegister;
+                       this.version = version;
+                       this.instructions = instructions;
+                       this.addressSize = addressSize;
+                       
+                       checkAugmentations(producer, augmentation);
+               }
+               
+               /**
+                * Handle augmentations we find.
+                */
+               private void checkAugmentations(String producer, String augmentation) {
+                       // RVCT has bugs with the frame info in DWARF 1/2 and some DWARF 3
+                       
+                       if (augmentation.startsWith("armcc") && augmentation.contains("+")) {
+                               // this means bugs are fixed
+                               
+                       } else {
+                               if (producer != null && producer.contains("RVCT")) { //$NON-NLS-1$
+                                       if (version == 1) {
+                                               cfaOffsetSfIsFactored = true;
+                                               cfaOffsetsAreReversed = true;
+                                       }
+                                       
+                                       if (version == 3) {
+                                               cfaOffsetsAreReversed = true;
+                                       }
+                               }
+                       }
+               }
+
+               /**
+                * Get the rules defining initial locations for all the registers 
+                * @return list of instructions
+                */
+               public List<AbstractInstruction> getInitialLocations(DwarfDebugInfoProvider provider) throws CoreException {
+                       if (initialLocations == null) {
+                               try {
+                                       initialLocations = parseInitialLocations(provider);
+                               } catch (CoreException e) {
+                                       initialLocationsError = e;
+                               }
+                       }
+                       if (initialLocationsError != null)
+                               throw initialLocationsError;
+                       return initialLocations;
+               }
+               
+               /**
+                * Parse the instructions for calculating the initial locations for all the registers 
+                * @return map of register to rule
+                */
+               public List<AbstractInstruction> parseInitialLocations(DwarfDebugInfoProvider provider) throws CoreException {
+                       List<AbstractInstruction> instrs = new ArrayList<AbstractInstruction>();
+
+                       IStreamBuffer buffer = instructions.wrapSubsection(instructions.capacity());
+                       
+                       buffer.position(0);
+                       
+                       try {
+                               while (buffer.hasRemaining()) {
+                                       int opcode = buffer.get() & 0xff;
+                                       AbstractInstruction inst = parseInstruction(opcode, buffer, provider, addressSize, dataAlignmentFactor);
+                                       if (inst != null)
+                                               instrs.add(inst);
+                               }
+                       } catch (Exception e) {
+                               throw EDCDebugger.newCoreException("Malformed data at " + buffer, e);
+                       }
+
+                       
+                       return instrs;
+               }
+
+               public AbstractInstruction parseInstruction(int opcode, IStreamBuffer buffer, 
+                               DwarfDebugInfoProvider provider, int addressSize, long dataAlignmentFactor) throws IOException {
+                       int reg;
+                       long offset;
+                       IStreamBuffer expr;
+                       
+                       //
+                       // CFA DEFINITION INSTRUCTIONS
+                       //
+                       if (opcode >= DwarfConstants.DW_CFA_offset && opcode < DwarfConstants.DW_CFA_offset + 0x40) {
+                               reg = opcode - DwarfConstants.DW_CFA_offset;
+                               offset = DwarfInfoReader.read_unsigned_leb128(buffer) * dataAlignmentFactor;
+                               return new OffsetInstruction(reg, offset);
+                       } else if (opcode >= DwarfConstants.DW_CFA_restore && opcode < DwarfConstants.DW_CFA_restore + 0x40) {
+                               reg = opcode - DwarfConstants.DW_CFA_restore;
+                               return new RestoreInstruction(reg);
+                       } else {
+                               switch (opcode) {
+                               case DwarfConstants.DW_CFA_nop:
+                                       // ignore
+                                       return new NopInstruction();
+                               case DwarfConstants.DW_CFA_def_cfa:
+                                       reg = readRegister(buffer);
+                                       offset = DwarfInfoReader.read_unsigned_leb128(buffer);
+                                       if (cfaOffsetSfIsFactored) {
+                                               offset *= dataAlignmentFactor;
+                                       }
+                                       return new DefCFAInstruction(reg, offset);
+                               case DwarfConstants.DW_CFA_def_cfa_sf:
+                                       reg = readRegister(buffer);
+                                       offset = DwarfInfoReader.read_signed_leb128(buffer) * dataAlignmentFactor;
+                                       return new DefCFAInstruction(reg, offset);
+                               case DwarfConstants.DW_CFA_def_cfa_register: {
+                                       reg = readRegister(buffer);
+                                       return new DefCFARegisterInstruction(reg);
+                               }
+                               case DwarfConstants.DW_CFA_def_cfa_offset: {
+                                       offset = DwarfInfoReader.read_unsigned_leb128(buffer); // non-factored, usually
+                                       if (cfaOffsetSfIsFactored) {
+                                               offset *= dataAlignmentFactor;
+                                       }
+                                       return new DefCFAOffsetInstruction(offset);
+                               }
+                               case DwarfConstants.DW_CFA_def_cfa_offset_sf: {
+                                       offset = DwarfInfoReader.read_signed_leb128(buffer) * dataAlignmentFactor;
+                                       return new DefCFAOffsetInstruction(offset);
+                               }
+                               case DwarfConstants.DW_CFA_def_cfa_expression: {
+                                       byte form = buffer.get();
+                                       expr = readExpression(form, addressSize, provider, buffer);
+                                       return new DefCFAExpressionInstruction(expr);
+                               }
+                               }
+                       }
+                               
+                       //
+                       // REGISTER RULE INSTRUCTIONS
+                       //
+                       if (opcode >= DwarfConstants.DW_CFA_offset && opcode < DwarfConstants.DW_CFA_offset + 0x40) {
+                               reg = opcode - DwarfConstants.DW_CFA_offset;
+                               offset = DwarfInfoReader.read_unsigned_leb128(buffer) * dataAlignmentFactor;
+                               return new OffsetInstruction(reg, offset);
+                       } else if (opcode >= DwarfConstants.DW_CFA_restore && opcode < DwarfConstants.DW_CFA_restore + 0x40) {
+                               reg = opcode - DwarfConstants.DW_CFA_restore;
+                               return new RestoreInstruction(reg);
+                       } else {
+                               switch (opcode) {
+                               case DwarfConstants.DW_CFA_nop:
+                                       break;
+                                       
+                               case DwarfConstants.DW_CFA_undefined:
+                                       reg = readRegister(buffer);
+                                       return new UndefinedInstruction(reg);
+                               case DwarfConstants.DW_CFA_same_value:
+                                       reg = readRegister(buffer);
+                                       return new SameValueInstruction(reg);
+                               case DwarfConstants.DW_CFA_offset_extended:
+                                       reg = readRegister(buffer);
+                                       offset = DwarfInfoReader.read_unsigned_leb128(buffer) * dataAlignmentFactor;
+                                       return new OffsetInstruction(reg, offset);
+                               case DwarfConstants.DW_CFA_offset_extended_sf:
+                                       reg = readRegister(buffer);
+                                       offset = DwarfInfoReader.read_signed_leb128(buffer) * dataAlignmentFactor;
+                                       return new OffsetInstruction(reg, offset);
+                               case DwarfConstants.DW_CFA_val_offset:
+                                       reg = readRegister(buffer);
+                                       offset = DwarfInfoReader.read_unsigned_leb128(buffer) * dataAlignmentFactor;
+                                       return new ValueOffsetInstruction(reg, offset);
+                               case DwarfConstants.DW_CFA_val_offset_sf:
+                                       reg = readRegister(buffer);
+                                       offset = DwarfInfoReader.read_signed_leb128(buffer) * dataAlignmentFactor;
+                                       return new ValueOffsetInstruction(reg, offset);
+                               case DwarfConstants.DW_CFA_register: {
+                                       reg = readRegister(buffer);
+                                       int otherReg = readRegister(buffer);
+                                       return new RegisterInstruction(reg, otherReg);
+                               }
+                               case DwarfConstants.DW_CFA_expression: {
+                                       reg = readRegister(buffer);
+                                       byte form = buffer.get();
+                                       expr = readExpression(form, addressSize, provider, buffer);
+                                       return new ExpressionInstruction(reg, expr);
+                               }
+                               case DwarfConstants.DW_CFA_val_expression: {
+                                       reg = readRegister(buffer);
+                                       byte form = buffer.get();
+                                       expr = readExpression(form, addressSize, provider, buffer);
+                                       return new ValueExpressionInstruction(reg, expr);
+                               }
+                               case DwarfConstants.DW_CFA_restore_extended:
+                                       reg = readRegister(buffer);
+                                       return new RestoreInstruction(reg);
+                               case DwarfConstants.DW_CFA_remember_state:
+                                       return new RememberStateInstruction();
+                               case DwarfConstants.DW_CFA_restore_state:
+                                       return new RestoreStateInstruction();
+                               }
+                       }
+                       return null;
+               }
+
+               /**
+                * @param buffer
+                * @return
+                * @throws IOException
+                */
+               private int readRegister(IStreamBuffer buffer) throws IOException {
+                       return (int) DwarfInfoReader.read_unsigned_leb128(buffer);
+               }
+
+               private IStreamBuffer readExpression(byte form, int addressSize, 
+                               DwarfDebugInfoProvider provider, IStreamBuffer buffer) {
+                       AttributeValue value = new AttributeValue(form, buffer, (byte) addressSize, null);
+                       return new MemoryStreamBuffer(value.getValueAsBytes(), 
+                                       provider.getExecutableSymbolicsReader().getByteOrder());
+               }
+               
+       }
+
+
+       /**
+        * A "FDE" entry from the .debug_frame section.
+        */
+       public static class FrameDescriptionEntry {
+       
+               final Long fdePtr;
+               final Long ciePtr;
+               final int addressSize;
+               private final IStreamBuffer instructions;
+               
+               private final long low, high;
+               
+               private CommonInformationEntry cie;
+               private CoreException parseException;
+               private TreeMap<Entry, List<AbstractInstruction>> instructionMap;
+               
+               public CommonInformationEntry getCIE() {
+                       return cie;
+               }
+       
+               public void setCIE(CommonInformationEntry cie) {
+                       this.cie = cie;
+               }
+       
+               public FrameDescriptionEntry(long fdePtr, long ciePtr, long low, long high, 
+                               IStreamBuffer instructions, int addressSize) {
+                       this.ciePtr = ciePtr;
+                       this.fdePtr = fdePtr;
+                       this.instructions = instructions;
+                       this.addressSize = addressSize;
+                       this.low = low;
+                       this.high = high;
+               }
+       
+               @Override
+               public String toString() {
+                       return "FDE at " + instructions + " with CIE " + (cie != null ? cie : ciePtr);
+               }
+       
+               /**
+                * Get the register for this frame which denotes the return address
+                * @return register number
+                */
+               public int getReturnAddressRegister() {
+                       return cie != null ? cie.returnAddressRegister : 0;
+               }
+
+               /**
+                * Get the instruction map for the FDE
+                * @param provider
+                * @return
+                */
+               public TreeMap<IRangeList.Entry, List<AbstractInstruction>> getInstructions(
+                               DwarfDebugInfoProvider provider) throws CoreException {
+                       if (instructionMap == null) {
+                               try {
+                                       instructionMap = parseRules(provider);
+                               } catch (CoreException e) {
+                                       parseException = e;
+                               }
+                       }
+                       if (parseException != null)
+                               throw parseException;
+                       return instructionMap;
+               }
+               
+               private TreeMap<Entry, List<AbstractInstruction>> parseRules(
+                               DwarfDebugInfoProvider provider) throws CoreException {
+                       TreeMap<IRangeList.Entry, List<AbstractInstruction>> rules = new TreeMap<IRangeList.Entry, List<AbstractInstruction>>();
+
+                       IStreamBuffer buffer = instructions.wrapSubsection(instructions.capacity());
+                       
+                       buffer.position(0);
+                       
+                       // adjust range and store row as we see set_loc/advance_loc instructions
+                       long current = low;
+                       List<AbstractInstruction> row = new ArrayList<AbstractInstruction>();
+                       
+                       try {
+                               while (buffer.hasRemaining()) {
+                                       int opcode = buffer.get() & 0xff;
+                                       
+                                       //
+                                       // ROW CREATION INSTRUCTIONS
+                                       //
+                                       long offset = -1;
+                                       if (opcode >= DwarfConstants.DW_CFA_advance_loc && opcode < DwarfConstants.DW_CFA_advance_loc + 0x40) {
+                                               offset = (opcode - DwarfConstants.DW_CFA_advance_loc) * cie.codeAlignmentFactor;
+                                       } else {
+                                               switch (opcode) {
+                                               case DwarfConstants.DW_CFA_set_loc:
+                                                       offset = DwarfInfoReader.readAddress(buffer, addressSize) - current;
+                                                       break;
+                                               case DwarfConstants.DW_CFA_advance_loc1:
+                                                       offset = (buffer.get() & 0xff) * cie.codeAlignmentFactor;
+                                                       break;
+                                               case DwarfConstants.DW_CFA_advance_loc2:
+                                                       offset = (buffer.getShort() & 0xffff) * cie.codeAlignmentFactor;
+                                                       break;
+                                               case DwarfConstants.DW_CFA_advance_loc4:
+                                                       offset = (buffer.getInt() & 0xffffffff) * cie.codeAlignmentFactor;
+                                                       break;
+                                               }
+                                       }
+
+                                       if (offset > 0) {
+                                               rules.put(new IRangeList.Entry(current, current + offset), row);
+                                               current += offset;
+                                               row = new ArrayList<DwarfFrameRegisterProvider.AbstractInstruction>();
+                                               continue;
+                                       }
+                                       
+                                       //
+                                       // REGISTER RULE INSTRUCTIONS
+                                       // 
+                                       
+                                       AbstractInstruction instr = cie.parseInstruction(opcode, buffer, provider, addressSize, cie.dataAlignmentFactor);
+                                       if (instr != null) {
+                                               row.add(instr);
+                                       } else {
+                                               assert(false);
+                                               throw EDCDebugger.newCoreException("Unimplemented opcode " + opcode + " at " + buffer);
+                                       }
+                               }
+                       } catch (CoreException e) {
+                               throw e;
+                       } catch (Exception e) {
+                               throw EDCDebugger.newCoreException("error parsing FDE rules at " + buffer, e);
+                       }
+                       
+                       if (!row.isEmpty()) {
+                               // finish instruction stream
+                               rules.put(new IRangeList.Entry(current, high), row);
+                       }
+                       return rules;
+               }
+       }
+
+       private DwarfDebugInfoProvider provider;
+
+       public DwarfFrameRegisterProvider(
+                       DwarfDebugInfoProvider provider) {
+               this.provider = provider;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IFrameRegisterProvider#dispose()
+        */
+       public void dispose() {
+               provider = null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.services.IFrameRegisterProvider#getFrameRegisters(org.eclipse.cdt.dsf.service.DsfSession, org.eclipse.cdt.dsf.service.DsfServicesTracker, org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext)
+        */
+       public IFrameRegisters getFrameRegisters(DsfSession session,
+                       EDCServicesTracker tracker,
+                       IFrameDMContext context) throws CoreException {
+               Registers registers = tracker.getService(Registers.class);
+               IStack stack = tracker.getService(IStack.class);
+               ExecutionDMC exeDMC = DMContexts.getAncestorOfType(context, ExecutionDMC.class);
+               
+               if (registers == null || exeDMC == null || !(context instanceof StackFrameDMC))
+                       throw EDCDebugger.newCoreException("cannot read frame");
+               
+               StackFrameDMC stackFrame = (StackFrameDMC) context;
+
+               if (stackFrame.getLevel() == 0) {
+                       // shouldn't actually get here, but whatevah 
+                       return new org.eclipse.cdt.debug.edc.services.Stack.CurrentFrameRegisters(exeDMC, registers);
+               }
+               
+               // get the child frame's registers
+               StackFrameDMC childFrame = getChildFrame(session, stack, exeDMC, stackFrame);
+               if (childFrame == null)
+                       return null;
+               
+               IFrameRegisters childRegisters = childFrame.getFrameRegisters();
+               
+               IAddress linkaddress = childFrame.getInstructionPtrAddress();
+               IEDCModuleDMContext module = childFrame.getModule();
+               if (module != null) {
+                       linkaddress = module.toLinkAddress(linkaddress);
+               }
+
+               FrameDescriptionEntry currentFrameEntry = provider.findFrameDescriptionEntry(linkaddress);
+               if (currentFrameEntry == null) 
+                       return null;
+               
+               return new DwarfFrameRegisters(tracker, childFrame, currentFrameEntry, childRegisters, provider);
+       }
+
+       /**
+        * Find the frame called by stackFrame
+        */
+       private StackFrameDMC getChildFrame(DsfSession session, IStack stack,
+                       ExecutionDMC exeDMC, StackFrameDMC stackFrame) throws CoreException {
+               StackFrameDMC childFrame = stackFrame.getCalledFrame();
+               return childFrame;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFrameRegisters.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFrameRegisters.java
new file mode 100644 (file)
index 0000000..9b9f195
--- /dev/null
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.symbols.ValueVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.AbstractInstruction;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.AbstractRule;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.FrameDescriptionEntry;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.InstructionState;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.services.IFrameRegisters;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.symbols.IRangeList.Entry;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * This class wraps the cached values from reading unwind information from the CIE and FDE
+ * records along each frame of the call stack to a given stack frame.
+ * This must be recreated on each context suspend.
+ */
+public class DwarfFrameRegisters implements IFrameRegisters {
+
+       private final EDCServicesTracker tracker;
+       private final StackFrameDMC context;
+       private final IFrameRegisters childRegisters;
+
+       // holds BigInteger or CoreException
+       private Map<Integer, Object> cachedRegisters = new TreeMap<Integer, Object>();
+       private final FrameDescriptionEntry fde;
+       private final DwarfDebugInfoProvider provider;
+       private Map<Integer, AbstractRule> frameRegisterRules;
+       private InstructionState state;
+       
+       /**
+        * @param provider 
+        * 
+        */
+       public DwarfFrameRegisters(EDCServicesTracker tracker,
+                       StackFrameDMC context, 
+                       FrameDescriptionEntry fde,
+                       IFrameRegisters childRegisters, DwarfDebugInfoProvider provider) {
+               if (childRegisters == null)
+                       throw new NullPointerException();
+               this.provider = provider;
+               this.tracker = tracker;
+               this.context = context;
+               this.fde = fde;
+               this.childRegisters = childRegisters;
+       }
+
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IFrameRegisters#getRegister(int)
+        */
+       public BigInteger getRegister(int regnum, int bytes) throws CoreException {
+               BigInteger value = null;
+               CoreException exception = null;
+               Object object = cachedRegisters.get(regnum);
+               if (object == null) {
+                       try {
+                               IVariableLocation loc = getRegisterLocation(regnum);
+                               if (loc == null)
+                                       throw EDCDebugger.newCoreException(MessageFormat.format(DwarfMessages.DwarfFrameRegisters_CannotReadRegister,
+                                                       regnum, context.getInstructionPtrAddress().toHexAddressString()));
+                               value = loc.readValue(bytes);
+                               cachedRegisters.put(regnum, value);
+                       } catch (CoreException e) {
+                               exception = e;
+                               cachedRegisters.put(regnum, exception);
+                       }
+               } else {
+                       if (object instanceof CoreException)
+                               exception = (CoreException) object;
+                       else
+                               value = (BigInteger) object;
+               }
+               
+               if (exception != null)
+                       throw exception;
+               
+               return value;
+       }
+
+
+       /**
+        * Calculate the location of a register for the current frame and PC.
+        * @param regnum
+        * @return location or <code>null</code> if undefined
+        * @throws CoreException in case of a problem calculating the location
+        */
+       private IVariableLocation getRegisterLocation(int regnum) throws CoreException {
+               
+               if (frameRegisterRules == null) {
+                       state = new InstructionState(tracker, context, childRegisters, fde);
+                       frameRegisterRules = calculateFrameRegisterRules(state);
+               }
+               
+               AbstractRule rule = frameRegisterRules.get(regnum);
+               if (rule == null) {
+                       // Note: according to DWARF-3 spec, any register not mentioned here is undefined.
+                       // But DWARF-2 producers didn't know what to do (or is it ABI-defined?), 
+                       // so for these, assume the current register for now
+                       if (fde.getCIE().version < 3)
+                               if (regnum == state.getCFARegister())
+                                       return new ValueVariableLocation(state.readCFA());
+                               else
+                                       return new ValueVariableLocation(childRegisters.getRegister(regnum, fde.addressSize));
+                       else
+                               return null;
+               }
+               
+               return rule.evaluate(state);
+       }
+
+
+       /**
+        * Create locations for every register in this frame.
+        * @param state 
+        * @return mapping of register to location
+        * @throws CoreException
+        */
+       private Map<Integer, AbstractRule> calculateFrameRegisterRules(InstructionState state) throws CoreException {
+               if (fde.getCIE() == null)
+                       throw EDCDebugger.newCoreException(MessageFormat.format(DwarfMessages.DwarfFrameRegisters_NoCommonInfoEntry, fde));
+               
+               List<AbstractInstruction> initialLocationInstructions =
+                       fde.getCIE().getInitialLocations(provider);
+
+               for (AbstractInstruction instr : initialLocationInstructions) {
+                       instr.applyInstruction(state);
+               }
+
+               // Run through rules until we hit one past our range
+               TreeMap<Entry, List<AbstractInstruction>> fdeInstrs = fde.getInstructions(provider); 
+               
+               long currentPC = context.getModule().toLinkAddress(context.getInstructionPtrAddress()).getValue().longValue();
+               
+               for (Map.Entry<Entry, List<AbstractInstruction>> instrEntry : fdeInstrs.entrySet()) {
+                       Entry entry = instrEntry.getKey();
+                       if (entry.low > currentPC)              // execute all instructions <= PC
+                               break;
+                       
+                       try {
+                               for (AbstractInstruction instr : instrEntry.getValue()) {
+                                       instr.applyInstruction(state);
+                               }
+                       } catch (Exception e) {
+                               throw EDCDebugger.newCoreException(DwarfMessages.DwarfFrameRegisters_ErrorCalculatingLocation, e);
+                       }
+               }
+               
+               return state.regRules;
+       }
+
+
+       public void writeRegister(int regnum, int bytes, BigInteger value) throws CoreException {
+               CoreException exception = null;
+               try {
+                       IVariableLocation loc = getRegisterLocation(regnum);
+                       if (loc == null)
+                               throw EDCDebugger.newCoreException(MessageFormat.format(DwarfMessages.DwarfFrameRegisters_CannotWriteRegister,
+                                               regnum, context.getInstructionPtrAddress().toHexAddressString()));
+                       loc.writeValue(bytes, value);
+                       cachedRegisters.put(regnum, value);
+               } catch (CoreException e) {
+                       exception = e;
+                       cachedRegisters.put(regnum, exception);
+               }
+               
+               if (exception != null)
+                       throw exception;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFunctionScope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfFunctionScope.java
new file mode 100644 (file)
index 0000000..9317a68
--- /dev/null
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.symbols.FunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.core.runtime.IPath;
+
+public class DwarfFunctionScope extends FunctionScope implements IFunctionScope {
+       protected int declFileNum;
+       
+       public DwarfFunctionScope(String name, IScope parent, IAddress lowAddress, IAddress highAddress,
+                       ILocationProvider frameBaseLocationProvider) {
+               super(name, parent, lowAddress, highAddress, frameBaseLocationProvider);
+       }
+       
+       /**
+        * Set the declaration file number entry from the line number table
+        * @param declFileNum
+        */
+       public void setDeclFileNum(int declFileNum) {
+               this.declFileNum = declFileNum;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.FunctionScope#getDeclFile()
+        */
+       @Override
+       public IPath getDeclFile() {
+               IPath file = super.getDeclFile();
+               if (file == null && declFileNum != 0) {
+                       // ask the parent
+                       IScope cu = getParent();
+                       while (cu != null) {
+                               if (cu instanceof DwarfCompileUnit) {
+                                       return ((DwarfCompileUnit) cu).getFileEntry(declFileNum);
+                               }
+                               cu = cu.getParent();
+                       }
+               }
+               return file;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfInfoReader.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfInfoReader.java
new file mode 100644 (file)
index 0000000..6b48dce
--- /dev/null
@@ -0,0 +1,3451 @@
+/**
+ * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of the License "Eclipse Public License v1.0"
+ * which accompanies this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ *
+ * Initial Contributors:
+ * Nokia Corporation - initial contribution.
+ *
+ * Contributors:
+ *
+ * Description: 
+ *
+ */
+
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import java.util.TreeMap;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.internal.MemoryStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.PathUtils;
+import org.eclipse.cdt.debug.edc.internal.symbols.ArrayBoundType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.CPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ClassType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ConstType;
+import org.eclipse.cdt.debug.edc.internal.symbols.Enumeration;
+import org.eclipse.cdt.debug.edc.internal.symbols.Enumerator;
+import org.eclipse.cdt.debug.edc.internal.symbols.FieldType;
+import org.eclipse.cdt.debug.edc.internal.symbols.FunctionScope;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICompositeType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISection;
+import org.eclipse.cdt.debug.edc.internal.symbols.InheritanceType;
+import org.eclipse.cdt.debug.edc.internal.symbols.LexicalBlockScope;
+import org.eclipse.cdt.debug.edc.internal.symbols.LineEntry;
+import org.eclipse.cdt.debug.edc.internal.symbols.PointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ReferenceType;
+import org.eclipse.cdt.debug.edc.internal.symbols.Scope;
+import org.eclipse.cdt.debug.edc.internal.symbols.StructType;
+import org.eclipse.cdt.debug.edc.internal.symbols.SubroutineType;
+import org.eclipse.cdt.debug.edc.internal.symbols.TemplateParamType;
+import org.eclipse.cdt.debug.edc.internal.symbols.TypedefType;
+import org.eclipse.cdt.debug.edc.internal.symbols.UnionType;
+import org.eclipse.cdt.debug.edc.internal.symbols.VolatileType;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.AbbreviationEntry;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.Attribute;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.AttributeList;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.AttributeValue;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.CompilationUnitHeader;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.ForwardTypeReference;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.PublicNameInfo;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.CommonInformationEntry;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.FrameDescriptionEntry;
+import org.eclipse.cdt.debug.edc.internal.symbols.files.BaseExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.internal.symbols.files.UnmanglerEABI;
+import org.eclipse.cdt.debug.edc.internal.symbols.files.UnmanglingException;
+import org.eclipse.cdt.debug.edc.symbols.ICompileUnitScope;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSection;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
+import org.eclipse.cdt.debug.edc.symbols.IRangeList;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IUnmangler;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+import org.eclipse.cdt.utils.Addr32;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * Handle restartable parsing of Dwarf information from a single module.  
+ * This class may be instantiated multiple times to parse specific subsets 
+ * of the Dwarf data.  The {@link DwarfDebugInfoProvider}
+ * holds the global state of everything parsed so far.
+ */
+public class DwarfInfoReader {
+       
+       private class BaseAndScopedNames {
+               public String baseName;                 // e.g., "bar"
+               public String nameWithScope;    // e.g., "foo::bar" 
+       }
+       
+       private BaseAndScopedNames baseAndScopedNames = new BaseAndScopedNames();
+
+       // These are only for developer of the reader.
+       // 
+       private static boolean DEBUG = false;
+       private static String dumpFileName = "C:\\temp\\_EDC_DwarfReaderDump.txt"; //$NON-NLS-1$
+       
+       // TODO 64-bit Dwarf currently unsupported
+
+       /* Section names. */
+       public final static String DWARF_DEBUG_INFO      = ".debug_info"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_RANGES    = ".debug_ranges"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_ABBREV    = ".debug_abbrev"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_ARANGES   = ".debug_aranges"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_LINE      = ".debug_line"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_FRAME     = ".debug_frame"; //$NON-NLS-1$
+       public final static String DWARF_EH_FRAME        = ".eh_frame"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_LOC       = ".debug_loc"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_PUBNAMES  = ".debug_pubnames"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_STR       = ".debug_str"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_FUNCNAMES = ".debug_funcnames"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_TYPENAMES = ".debug_typenames"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_VARNAMES  = ".debug_varnames"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_WEAKNAMES = ".debug_weaknames"; //$NON-NLS-1$
+       public final static String DWARF_DEBUG_MACINFO   = ".debug_macinfo"; //$NON-NLS-1$
+
+       private Map<Long, Collection<LocationEntry>> locationEntriesByOffset = Collections.synchronizedMap(new HashMap<Long, Collection<LocationEntry>>());
+
+       // the target for all the reading
+       private DwarfDebugInfoProvider provider;
+       
+       private IExecutableSymbolicsReader exeReader;
+       private DwarfModuleScope moduleScope;
+       private IPath symbolFilePath;
+       
+       private IExecutableSection debugInfoSection;
+       private IExecutableSection publicNamesSection;
+       private CompilationUnitHeader currentCUHeader;
+       
+       private Map<IType, IType> typeToParentMap = Collections.synchronizedMap(new HashMap<IType, IType>());
+       private IType currentParentType;
+       private Scope currentParentScope;
+       private DwarfCompileUnit currentCompileUnitScope;
+
+       private DwarfFileHelper fileHelper;
+
+       private RangeList codeRanges;
+       
+       private ICPPBasicType voidType = null;
+       
+       private IUnmangler unmangler;
+       
+       // comparator for sorting and searching based on compilation unit low address
+       private static Comparator<DwarfCompileUnit> sComparatorByLowAddress = new Comparator<DwarfCompileUnit>() {
+               public int compare(DwarfCompileUnit o1, DwarfCompileUnit o2) {
+                       return (o1.getLowAddress().compareTo(o2.getLowAddress()));
+               }};
+
+       /**
+        * Create a reader for the provider.  This constructor and any methods 
+        * on this reader class will incrementally update the provider.
+        * @param provider
+        */
+       public DwarfInfoReader(DwarfDebugInfoProvider provider) {
+               this.provider = provider;
+               exeReader = provider.getExecutableSymbolicsReader();
+               if (exeReader instanceof BaseExecutableSymbolicsReader)
+                       unmangler = ((BaseExecutableSymbolicsReader) exeReader).getUnmangler();
+               if (unmangler == null)
+                       unmangler = new UnmanglerEABI();
+
+               symbolFilePath = provider.getSymbolFile();
+               fileHelper = provider.fileHelper;
+               moduleScope = (DwarfModuleScope) provider.getModuleScope();
+               debugInfoSection = exeReader.findExecutableSection(DWARF_DEBUG_INFO);
+               publicNamesSection = exeReader.findExecutableSection(DWARF_DEBUG_PUBNAMES);
+
+               codeRanges = getCodeRanges();
+       }
+
+       private String unmangle(String name) {
+               if (!unmangler.isMangled(name))
+                       return name;
+
+               try {
+                       name = unmangler.unmangle(name);
+               } catch (UnmanglingException ue) {
+               }
+
+               return name;
+       }
+
+
+       private String unmangleType(String name) {
+               if (!unmangler.isMangled(name))
+                       return name;
+
+               try {
+                       name = unmangler.unmangleType(name);
+               } catch (UnmanglingException ue) {
+               }
+
+               return name;
+       }
+
+       /**
+        * @return
+        */
+       private RangeList getCodeRanges() {
+               RangeList codeRanges = new RangeList();
+               for (ISection section : exeReader.getSections()) {
+                       if (section.getProperties().get(ISection.PROPERTY_NAME).equals(ISection.NAME_TEXT)) {
+                               long start = section.getLinkAddress().getValue().longValue();
+                               long size = section.getSize();
+                               codeRanges.addRange(start, start + size);
+                       }
+               }
+               return codeRanges;
+       }
+
+       protected IStreamBuffer getDwarfSection(String sectionName) {
+               // the exe reader and section already handle caching this
+               IStreamBuffer buffer = null;
+               IExecutableSection section = exeReader.findExecutableSection(sectionName);
+               if (section != null) {
+                       buffer = section.getBuffer();
+               }
+               return buffer;
+       }
+
+       /** 
+        * Parse top-level debugging information about compilation units and globally
+        * visible objects, but do not expand or gather data about other objects in
+        * compilation units.  
+        */
+       public void parseInitial() {
+                       Job parseInitialJob = new Job(DwarfMessages.DwarfInfoReader_ReadingSymbolInfo + symbolFilePath) {
+               
+                               @Override
+                               protected IStatus run(IProgressMonitor monitor) {
+                                       if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceInitialParseFor + symbolFilePath)); }
+                                       synchronized (provider) {
+                                               parseCUDebugInfo(monitor);
+                                               parsePublicNames();
+                                       }
+                                       if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceFinishedInitialParse)); }
+                                       return Status.OK_STATUS;
+                               }
+                       };
+                       
+                       try {
+                               parseInitialJob.schedule();
+                               parseInitialJob.join();
+                       } catch (InterruptedException e) {
+                               EDCDebugger.getMessageLogger().logError(null, e);
+                       }
+       }
+
+       /**
+        * Parse all compilation units for addresses
+        * 
+        * @param includeCUWithoutCode
+        *            whether to parse compile units without code. For variable
+        *            info, we need to look into those CUs, whereas for scope
+        *            info, we don't.
+        */
+       public void parseForAddresses(boolean includeCUWithoutCode) {
+               if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceAddressesParseFor + symbolFilePath)); }
+               synchronized (provider) {
+                       for (DwarfCompileUnit compileUnit : provider.compileUnits) {
+                               if (DEBUG) {
+                                       // For internal check. 
+                                       if (compileUnit.getHighAddress().isZero())
+                                               assert(compileUnit.getChildren().size() == 0);
+                                       else
+                                               assert(compileUnit.getChildren().size() >= 0);
+                               }
+       
+                               if (includeCUWithoutCode ||     // parse every CU
+                                       ! compileUnit.getHighAddress().isZero()) // parse only those with code. 
+                               {
+                                       parseCompilationUnitForAddresses(compileUnit);
+                               }
+                       }
+               }
+               if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceFinishedAddressesParse)); }
+               
+               moduleScope.fixupRanges(Addr32.ZERO);
+
+               if (DEBUG) {
+                       dumpSymbols();
+               }
+
+       }
+
+       /**
+        * Parse compilation unit corresponding to address
+        * 
+        * @param linkAddress
+        *            address in a compile unit that contains code
+        */
+       public void parseForAddress(IAddress linkAddress) {
+               if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceAddressParseFor + symbolFilePath)); }
+
+               // find compilation unit containing address, and parse it
+               synchronized (provider) {
+                       DwarfCompileUnit cu = new DwarfCompileUnit(provider, null, null, linkAddress, linkAddress, null, false, null);
+                       int index = Collections.binarySearch (provider.sortedCompileUnitsWithCode, cu, sComparatorByLowAddress);
+       
+                       if (index >= 0) {
+                               cu = provider.sortedCompileUnitsWithCode.get(index);
+                               parseCompilationUnitForAddresses(cu);
+                       } else if (index < -1 && -index - 2 < provider.sortedCompileUnitsWithCode.size()) {
+                               cu = provider.sortedCompileUnitsWithCode.get(-index - 2);
+                               if (cu.getLowAddress().compareTo(linkAddress) <= 0 && cu.getHighAddress().compareTo(linkAddress) >= 0)
+                                       parseCompilationUnitForAddresses(cu);
+                       } else {
+                               return;
+                       }
+       
+                       if (moduleScope.getLowAddress().compareTo(cu.getLowAddress()) > 0)
+                               moduleScope.setLowAddress(cu.getLowAddress());
+                       if (moduleScope.getHighAddress().compareTo(cu.getHighAddress()) < 0)
+                               moduleScope.setHighAddress(cu.getHighAddress());
+               }
+
+               if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceFinishedAddressParse)); }
+       }
+       
+       /**
+        * Parse names in the .debug_pubnames section
+        */
+       private void parsePublicNames() {
+
+               if (publicNamesSection == null || debugInfoSection == null) { // no public names and/or debug info 
+                       return;
+               }
+
+               IStreamBuffer bufferPublicNames = publicNamesSection.getBuffer();
+               if (bufferPublicNames == null)
+                       return;
+
+               IStreamBuffer bufferDebuginfo = debugInfoSection.getBuffer();
+               if (bufferDebuginfo == null)
+                       return;
+
+               long fileIndex = 0;
+               long fileEndIndex = bufferPublicNames.capacity();
+
+               // parse all the sets in the .debug_pubnames section
+               while (fileIndex < fileEndIndex) {
+                       fileIndex = parsePublicNamesSet(bufferPublicNames, fileIndex, bufferDebuginfo);
+               }
+       }
+       
+       /**
+        * Parse one set of global objects and functions
+        */
+       private long parsePublicNamesSet(IStreamBuffer bufferPublicNames, long fileIndex, IStreamBuffer bufferDebugInfo) {
+               bufferPublicNames.position(fileIndex);
+
+               // get the set's data length
+               int setLength = bufferPublicNames.getInt();
+
+               // get the entire set
+
+               IStreamBuffer dataPublicNames = bufferPublicNames.wrapSubsection(setLength);
+
+               // get header info for set of public names
+               // skip over Dwarf version
+               dataPublicNames.position(2);
+               int debugInfoOffset = dataPublicNames.getInt();
+               int debugInfoLength = dataPublicNames.getInt();
+
+               try {
+                       // read the entire compile unit
+                       bufferDebugInfo.position(debugInfoOffset);
+
+                       IStreamBuffer dataInfoBytes = bufferDebugInfo.wrapSubsection(debugInfoLength);
+                       
+                       CompilationUnitHeader header = provider.debugOffsetsToCompileUnits.get(Long.valueOf(debugInfoOffset));
+                       
+                       // get stored abbrev table, or read and parse an abbrev table
+                       Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(header.abbreviationOffset);
+
+                       // read names and corresponding types
+                       // ignore the 4 bytes of 0 at the end of the set
+                       while (dataPublicNames.remaining() > 4) {
+                               // read the object offset and name
+                               int objectOffset = dataPublicNames.getInt();
+                               String name = readString(dataPublicNames);
+                               
+                               // read the type of object
+                               dataInfoBytes.position(objectOffset);
+                               long code = read_unsigned_leb128(dataInfoBytes);
+                               AbbreviationEntry entry = abbrevs.get(new Long(code));
+                               
+                               // ignore empty names, names without debug info, and
+                               // compiler-generated special symbols
+                               if (entry != null && name.length() > 0 && !name.startsWith("<")) {
+                                       // if the name is mangled, unmangle it
+                                       name = unmangle(name);
+
+                                       String baseName = name;
+                                       int baseStart = name.lastIndexOf("::"); //$NON-NLS-1$
+                                       if (baseStart != -1)            
+                                               baseName = name.substring(baseStart + 2);
+                                       if (entry.tag == DwarfConstants.DW_TAG_variable) {
+                                               List<PublicNameInfo> variables = provider.publicVariables.get(baseName);
+                                               if (variables == null) {
+                                                       variables = new ArrayList<PublicNameInfo>();
+                                               }
+                                               variables.add(new PublicNameInfo(name, header, entry.tag));
+                                               provider.publicVariables.put(baseName, variables);
+                                       } else if (entry.tag == DwarfConstants.DW_TAG_subprogram) {
+                                               List<PublicNameInfo> functions = provider.publicFunctions.get(baseName);
+                                               if (functions == null) {
+                                                       functions = new ArrayList<PublicNameInfo>();
+                                                       functions.add(new PublicNameInfo(name, header, entry.tag));
+                                               } else {
+                                                       // we don't store debug info offsets, so polymorphic functions for a compilation
+                                                       // unit have identical PublicNameInfo fields; throw all but one away
+                                                       ArrayList<PublicNameInfo> arrayList = (ArrayList<PublicNameInfo>)functions;
+                                                       boolean found = false;
+                                                       for (int i = arrayList.size() - 1; 
+                                                                       !found && (i >= 0) && (arrayList.get(i).cuHeader == header); i--)
+                                                               found = arrayList.get(i).nameWithNameSpace.equals(name);
+                                                       if (!found)
+                                                               functions.add(new PublicNameInfo(name, header, entry.tag));
+                                               }
+                                               provider.publicFunctions.put(baseName, functions);
+                                               
+                                       }
+                               }
+                       }
+               } catch (Throwable t) {
+                       EDCDebugger.getMessageLogger().logError(null, t);
+               }
+
+               return fileIndex + setLength + 4;
+       }
+
+       /**
+        * Parse all compilation units for types
+        */
+       public void parseForTypes() {
+               synchronized (provider) {
+                       for (DwarfCompileUnit compileUnit : provider.compileUnits) {
+                               parseCompilationUnitForTypes(compileUnit);
+                       }
+               }
+       }
+       /**
+        * Parse compilation unit headers and top-level info in the .debug_info section
+        * @param monitor 
+        */
+       private void parseCUDebugInfo(IProgressMonitor monitor) {
+
+               if (debugInfoSection == null) { // no Dwarf data.
+                       return;
+               }
+               
+               // if we haven't built the referenced files list from a quick parse yet,
+               // flag it here so we can build the file list as we parse.
+               if (provider.referencedFiles.isEmpty()) {
+                       provider.buildReferencedFilesList = true;
+               }
+
+               IStreamBuffer buffer = debugInfoSection.getBuffer();
+               IStreamBuffer debugStrings = getDebugStrings();
+               boolean havePubNames = publicNamesSection != null && publicNamesSection.getBuffer() != null;
+
+               int totalWork = (int) (buffer.capacity() / 1024);
+               monitor.beginTask(DwarfMessages.DwarfInfoReader_ReadDebugInfo, totalWork);
+               try {
+                       if (buffer != null) {
+                               long fileIndex = 0;
+                               long fileEndIndex = buffer.capacity();
+                               
+                               while (fileIndex < fileEndIndex) {
+                                       long oldIndex = fileIndex;
+                                       fileIndex = parseCompilationUnitForNames(buffer, fileIndex, debugStrings, fileEndIndex, havePubNames);
+                                       monitor.worked((int) ((fileIndex - oldIndex) / 1024));
+                               }
+                       }
+               } finally {
+                       monitor.done();
+               }
+               provider.compileUnits.trimToSize();
+               // sort by low address the list of compilation units with code
+               provider.sortedCompileUnitsWithCode.trimToSize();
+               Collections.sort(provider.sortedCompileUnitsWithCode, sComparatorByLowAddress);
+               provider.buildReferencedFilesList = false;
+       }
+
+       /**
+        * Parse the compile unit quickly looking for variables that are globally visible 
+     *
+        * @return offset of next compilation unit
+        */
+       private long parseCompilationUnitForNames(IStreamBuffer buffer, long fileIndex, IStreamBuffer debugStrings, long fileEndIndex, boolean havePubNames) {
+               buffer.position(fileIndex);
+               int lengthSize = 0;
+               currentCUHeader = new CompilationUnitHeader();
+               try {
+                       InitialLengthValue sectionLength = readInitialLengthField(buffer);
+                       currentCUHeader.length = sectionLength.length;
+                       currentCUHeader.offsetSize = sectionLength.offsetSize;
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+               currentCUHeader.version            = buffer.getShort();
+               if (currentCUHeader.offsetSize == 8) {
+                       currentCUHeader.abbreviationOffset = (int) buffer.getLong();
+                       lengthSize = 12;
+               } else {
+                       currentCUHeader.abbreviationOffset = buffer.getInt();
+                       lengthSize = 4;
+               }
+               currentCUHeader.addressSize        = buffer.get();
+               currentCUHeader.debugInfoOffset    = (int) fileIndex;
+
+               /*
+                * With certain GCC-E 3.x compilers, some subset of compile unit headers can have unit
+                * lengths 4 bytes too long. Before reading compile unit data, make sure there is a
+                * valid compile unit header right after this unit's data. Adjust the length if needed.
+                * To validate, check that the DWARF version and the address size are
+                * the same as the previous compile unit's.
+                */
+               if (fileIndex + currentCUHeader.length + (2 * lengthSize) < fileEndIndex) {
+                       // try good case
+                       short nextVersion;
+                       byte nextAddrSize;
+                       buffer.position(fileIndex + currentCUHeader.length + (2 * lengthSize)); // to next version
+                       nextVersion = buffer.getShort();
+                       buffer.position(fileIndex + currentCUHeader.length + (2 * lengthSize) + 2 + currentCUHeader.offsetSize); // to next address size
+                       nextAddrSize = buffer.get();
+                       // TODO: is this adjustment still necessary?
+                       if (currentCUHeader.version != nextVersion || currentCUHeader.addressSize != nextAddrSize) {
+                               // try adjusting back by 4 bytes
+                               buffer.position(fileIndex + currentCUHeader.length + 4); // to next version
+                               nextVersion = buffer.getShort();
+                               buffer.position(fileIndex + currentCUHeader.length + 10); // to next address size
+                               nextAddrSize = buffer.get();
+                               
+                               if (currentCUHeader.version == nextVersion && currentCUHeader.addressSize == nextAddrSize) {
+                                       // all this work to adjust the length...
+                                       currentCUHeader.length -= 4;
+                               }
+                       }
+               }
+
+               // now read the whole compile unit into memory. note that we're
+               // reading the whole section including the size that we already
+               // read because other code will use the offset of the buffer as
+               // the offset of the section to store things by offset (types,
+               // function declarations, etc).
+               buffer.position(fileIndex);
+               
+               IStreamBuffer in = buffer.wrapSubsection(currentCUHeader.length + lengthSize);
+
+               // skip over the header info we already read
+               if (currentCUHeader.offsetSize == 8) {
+                       in.position(lengthSize + 2 + 8 + 1); // sizeof (length + version + offset + address size)
+               } else {
+                       in.position(lengthSize + 2 + 4 + 1); // sizeof (length + version + offset + address size)
+               }
+               
+               try {
+                       // get stored abbrev table, or read and parse an abbrev table
+                       Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(currentCUHeader.abbreviationOffset);
+                       
+                       // read the compile unit's attribute list
+                       long code = read_unsigned_leb128(in);
+                       AbbreviationEntry entry = abbrevs.get(Long.valueOf(code));
+                       
+                       AttributeList attributeList = new AttributeList(entry, in, currentCUHeader.addressSize, debugStrings);
+                       processCompileUnit(currentCUHeader, entry.hasChildren, attributeList);
+                       
+                       if (!havePubNames) {
+                               // record file scope variables
+                               byte addressSize = currentCUHeader.addressSize;
+                               while (in.remaining() > 0) {
+                                       code = read_unsigned_leb128(in);
+               
+                                       if (code != 0) {
+                                               entry = abbrevs.get(Long.valueOf(code));
+               
+                                               switch (entry.tag) {
+                                               // record names of interest, but not other Dwarf attributes
+                                               case DwarfConstants.DW_TAG_variable:
+                                               {
+                                                       // get variable names at the compile unit scope level
+                                                       parseAttributesForNames(true, baseAndScopedNames, entry, in, addressSize, debugStrings);
+                                                       if (baseAndScopedNames.baseName != null)
+                                                               storePublicNames(provider.publicVariables, baseAndScopedNames, currentCUHeader, (short) DwarfConstants.DW_TAG_variable);
+                                                       break;
+                                               }
+                                               case DwarfConstants.DW_TAG_imported_declaration: // for possible namespace alias
+                                               case DwarfConstants.DW_TAG_namespace:
+                                               case DwarfConstants.DW_TAG_subprogram:
+                                               case DwarfConstants.DW_TAG_enumerator:
+                                               case DwarfConstants.DW_TAG_class_type:
+                                               case DwarfConstants.DW_TAG_structure_type:
+                                               case DwarfConstants.DW_TAG_array_type:
+                                               case DwarfConstants.DW_TAG_base_type:
+                                               case DwarfConstants.DW_TAG_enumeration_type:
+                                               case DwarfConstants.DW_TAG_pointer_type:
+                                               case DwarfConstants.DW_TAG_ptr_to_member_type:
+                                               case DwarfConstants.DW_TAG_subroutine_type:
+                                               case DwarfConstants.DW_TAG_typedef:
+                                               case DwarfConstants.DW_TAG_union_type:
+                                               case DwarfConstants.DW_TAG_access_declaration:
+                                               case DwarfConstants.DW_TAG_catch_block:
+                                               case DwarfConstants.DW_TAG_common_block:
+                                               case DwarfConstants.DW_TAG_common_inclusion:
+                                               case DwarfConstants.DW_TAG_condition:
+                                               case DwarfConstants.DW_TAG_const_type:
+                                               case DwarfConstants.DW_TAG_constant:
+                                               case DwarfConstants.DW_TAG_entry_point:
+                                               case DwarfConstants.DW_TAG_file_type:
+                                               case DwarfConstants.DW_TAG_formal_parameter:
+                                               case DwarfConstants.DW_TAG_friend:
+                                               case DwarfConstants.DW_TAG_imported_module:
+                                               case DwarfConstants.DW_TAG_inheritance:
+                                               case DwarfConstants.DW_TAG_inlined_subroutine:
+                                               case DwarfConstants.DW_TAG_interface_type:
+                                               case DwarfConstants.DW_TAG_label:
+                                               case DwarfConstants.DW_TAG_lexical_block:
+                                               case DwarfConstants.DW_TAG_member:
+                                               case DwarfConstants.DW_TAG_module:
+                                               case DwarfConstants.DW_TAG_namelist:
+                                               case DwarfConstants.DW_TAG_namelist_item:
+                                               case DwarfConstants.DW_TAG_packed_type:
+                                               case DwarfConstants.DW_TAG_reference_type:
+                                               case DwarfConstants.DW_TAG_restrict_type:
+                                               case DwarfConstants.DW_TAG_set_type:
+                                               case DwarfConstants.DW_TAG_shared_type:
+                                               case DwarfConstants.DW_TAG_string_type:
+                                               case DwarfConstants.DW_TAG_subrange_type:
+                                               case DwarfConstants.DW_TAG_template_type_param:
+                                               case DwarfConstants.DW_TAG_template_value_param:
+                                               case DwarfConstants.DW_TAG_thrown_type:
+                                               case DwarfConstants.DW_TAG_try_block:
+                                               case DwarfConstants.DW_TAG_unspecified_parameters:
+                                               case DwarfConstants.DW_TAG_variant:
+                                               case DwarfConstants.DW_TAG_variant_part:
+                                               case DwarfConstants.DW_TAG_volatile_type:
+                                               case DwarfConstants.DW_TAG_with_stmt:
+                                               {
+                                                       AttributeValue.skipAttributesToSibling(entry, in, addressSize);
+                                                       break;
+                                               }
+               //                              case DwarfConstants.DW_TAG_compile_unit:
+               //                              case DwarfConstants.DW_TAG_partial_unit:
+               //                              case DwarfConstants.DW_TAG_unspecified_type:
+                                               default:
+                                                       // skip entire entries
+                                                       AttributeList.skipAttributes(entry, in, addressSize);                                           
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               } catch (Throwable t) {
+                       EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed1 
+                                       + debugInfoSection.getName() + DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed2 + symbolFilePath, t);
+               }
+               
+               // skip past the compile unit. note that the
+               // currentCUHeader.length does not include
+               // the size of the unit length itself
+               fileIndex += currentCUHeader.length + lengthSize;               
+               
+               return fileIndex;
+       }
+       
+       /**
+        * Parse attributes, returning names
+        * 
+        * @param onlyExternal only return names if they have external visibility
+        * @param names array to hold up to two names
+        * @param entry debug info entry
+        * @param in buffer stream of debug info
+        * @param addressSize 
+        * @param debugStrings
+        * @return DW_AT_name value in names[0], unmangled DW_AT_MIPS_linkage_name value in
+        * names[1], or nulls  
+        */
+       private void parseAttributesForNames(boolean onlyExternal, BaseAndScopedNames baseAndScopedNames, AbbreviationEntry entry, IStreamBuffer in,
+                       byte addressSize, IStreamBuffer debugStrings) {
+       
+               String name = null;
+               baseAndScopedNames.baseName = null;
+               baseAndScopedNames.nameWithScope = null;
+               boolean isExternal = false;
+
+               // go through the attributes and throw away everything except the names
+               int len = entry.attributes.size();
+               for (int i = 0; i < len; i++) {
+                       Attribute attr = entry.attributes.get(i);
+                       try {
+                               if (   attr.tag == DwarfConstants.DW_AT_name
+                                       || attr.tag == DwarfConstants.DW_AT_MIPS_linkage_name) {
+                                       // names should be DW_FORM_string or DW_FORM_strp 
+                                   if (attr.form == DwarfConstants.DW_FORM_string) {
+                                               int c;
+                                               StringBuffer sb = new StringBuffer();
+                                               while ((c = (in.get() & 0xff)) != -1) {
+                                                       if (c == 0) {
+                                                               break;
+                                                       }
+                                                       sb.append((char) c);
+                                               }
+                                               name = sb.toString();
+                                       } else if (attr.form == DwarfConstants.DW_FORM_strp) {
+                                               int debugStringOffset = in.getInt();
+                                               if (   debugStrings != null
+                                                       && debugStringOffset >= 0
+                                                       && debugStringOffset < debugStrings.capacity()) {
+                                                       debugStrings.position(debugStringOffset);
+                                                       name = DwarfInfoReader.readString(debugStrings);
+                                               }
+                                       }
+                                   
+                                   if (name != null) {
+                                       if (attr.tag == DwarfConstants.DW_AT_name) {
+                                               baseAndScopedNames.baseName = name;
+                                               baseAndScopedNames.nameWithScope = name;
+                                       } else {
+                                               if (exeReader instanceof BaseExecutableSymbolicsReader) {
+                                                       try {
+                                                               baseAndScopedNames.nameWithScope = unmangler.unmangle(unmangler.undecorate(name));
+                                                       } catch(UnmanglingException ue) {
+                                                       }
+                                               }
+                                       }
+                                       name = null;
+                                   }
+                               } else if (attr.tag == DwarfConstants.DW_AT_external) {
+                                       if (attr.form == DwarfConstants.DW_FORM_flag) {
+                                               isExternal = in.get() != 0;
+                                       } else {
+                                               AttributeValue.skipAttributeValue(attr.form, in, addressSize);
+                                       }
+                               } else {
+                                       AttributeValue.skipAttributeValue(attr.form, in, addressSize);
+                               }
+                       } catch (Throwable t) {
+                               EDCDebugger.getMessageLogger().logError(null, t);
+                               break;
+                       }
+               }
+
+               // if only looking for externals, throw away internals
+               if (onlyExternal && !isExternal) {
+                       baseAndScopedNames.baseName = null;
+                       baseAndScopedNames.nameWithScope = null;
+               } else {
+                       // if only have the scoped name, derive the base name
+                       if (baseAndScopedNames.nameWithScope != null && baseAndScopedNames.baseName == null) {
+                               int baseStart = baseAndScopedNames.nameWithScope.lastIndexOf("::"); //$NON-NLS-1$
+                               if (baseStart != -1)
+                                       baseAndScopedNames.baseName = baseAndScopedNames.nameWithScope.substring(baseStart + 2);
+                               else
+                                       baseAndScopedNames.baseName = baseAndScopedNames.nameWithScope;
+                       }
+               }
+       }
+
+       /**
+        * Store compilation unit level names from Dwarf .debug_info
+        * 
+        * @param namesStore
+        * @param names
+        * @param offset
+        */
+       private void storePublicNames(Map<String, List<PublicNameInfo>> namesStore, BaseAndScopedNames baseAndScopedNames,
+                       CompilationUnitHeader cuHeader, short tag) {
+
+               List<PublicNameInfo> currentNames = namesStore.get(baseAndScopedNames.baseName);
+               if (currentNames == null) {
+                       currentNames = new ArrayList<PublicNameInfo>();
+                       namesStore.put(baseAndScopedNames.baseName, currentNames);
+               }
+               currentNames.add(new PublicNameInfo(baseAndScopedNames.nameWithScope, cuHeader, tag));
+       }
+       
+       private synchronized void parseCompilationUnitForAddressesPrivate(DwarfCompileUnit compileUnit, IProgressMonitor monitor)
+       {
+               synchronized (compileUnit) {
+                       if (compileUnit.isParsedForAddresses())
+                               return;
+                       
+                       compileUnit.setParsedForAddresses(true);
+
+                       CompilationUnitHeader header = compileUnit.header;
+
+                       if (header == null)
+                               return;
+
+                       if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().trace(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceAddressParse1 + Integer.toHexString(header.debugInfoOffset) + DwarfMessages.DwarfInfoReader_TraceAddressParse2 + header.scope.getFilePath())); }
+                       
+                       IStreamBuffer buffer = debugInfoSection.getBuffer();
+                       
+                       if (buffer == null)
+                               return;
+                       
+                       int fileIndex = header.debugInfoOffset;
+                       
+                       // read the compile unit debug info into memory
+                       buffer.position(fileIndex);
+                       
+                       int lengthSize = 0, headerLength = 0;
+                       if (header.offsetSize == 8) {
+                               lengthSize = 12;
+                               headerLength = lengthSize + 2 + 8 + 1; // unit length(8) + version + abbrev table offset + address size
+                       } else {
+                               lengthSize = 4;
+                               headerLength = lengthSize + 2 + 4 + 1; // unit length(8) + version + abbrev table offset + address size
+                       }
+
+                       IStreamBuffer data = buffer.wrapSubsection(header.length + lengthSize);
+
+                       // skip over the header, since we've already read it
+                       data.position(headerLength);
+                       
+                       currentCompileUnitScope = compileUnit;
+                       currentParentScope = compileUnit;
+                       registerScope(header.debugInfoOffset, compileUnit);
+                       currentCUHeader = header;
+
+                       try {
+                               // get stored abbrev table, or read and parse an abbrev table
+                               Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(header.abbreviationOffset);
+
+                               parseForAddresses(data, abbrevs, header, new Stack<Scope>(), monitor);
+                       } catch (Throwable t) {
+                               EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed1 
+                                               + debugInfoSection.getName() + DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed2 + symbolFilePath, t);
+                       }
+               }
+       }
+       
+       /**
+        * Given compilation unit, parse to get variables and all children that have address ranges.
+        * 
+        * @param compileUnit
+        */
+       public void parseCompilationUnitForAddresses(final DwarfCompileUnit compileUnit) {
+               synchronized (provider) {
+                       synchronized (compileUnit) {
+                               if (compileUnit.isParsedForAddresses())
+                                       return;
+                       }
+                       parseCompilationUnitForAddressesPrivate(compileUnit, new NullProgressMonitor());
+               }
+       }
+
+       synchronized public void parseCompilationUnitForTypes(DwarfCompileUnit compileUnit) {
+               synchronized (provider) {
+                       synchronized(compileUnit) {
+                               if (compileUnit.isParsedForTypes())
+                                       return;
+                               
+                               compileUnit.setParsedForTypes(true);
+                               
+                               CompilationUnitHeader header = compileUnit.header;
+       
+                               if (header == null)
+                                       return;
+       
+                               if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().trace(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceTypeParse1 + Integer.toHexString(header.debugInfoOffset) + DwarfMessages.DwarfInfoReader_TraceTypeParse2 + header.scope.getFilePath())); }
+                               
+                               IStreamBuffer buffer = debugInfoSection.getBuffer();
+                               
+                               if (buffer == null)
+                                       return;
+                               
+                               int fileIndex = header.debugInfoOffset;
+                               
+                               // read the compile unit debug info into memory
+                               buffer.position(fileIndex);
+       
+                               int lengthSize = 0, headerLength = 0;
+                               if (header.offsetSize == 8) {
+                                       lengthSize = 12;
+                                       headerLength = lengthSize + 2 + 8 + 1; // unit length(8) + version + abbrev table offset + address size
+                               } else {
+                                       lengthSize = 4;
+                                       headerLength = lengthSize + 2 + 4 + 1; // unit length(8) + version + abbrev table offset + address size
+                               }
+                               
+                               IStreamBuffer data = buffer.wrapSubsection(header.length + lengthSize);
+       
+                               // skip over the header, since we've already read it
+                               data.position(headerLength);
+                               
+                               currentCompileUnitScope = compileUnit;
+                               currentParentScope = compileUnit;
+                               registerScope(header.debugInfoOffset, compileUnit);
+                               currentCUHeader = header;
+       
+                               try {
+                                       // get stored abbrev table, or read and parse an abbrev table
+                                       Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(header.abbreviationOffset);
+       
+                                       parseForTypes(data, abbrevs, header, new Stack<Scope>());
+                               } catch (Throwable t) {
+                                       EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_ParseTraceInfoSectionFailed1 
+                                                       + debugInfoSection.getName() + DwarfMessages.DwarfInfoReader_ParseTraceInfoSectionFailed2 + symbolFilePath, t);
+                               }
+                       }
+               }
+       }
+
+       public void quickParseDebugInfo(IProgressMonitor monitor) {
+               if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceQuickParse + symbolFilePath)); }
+               synchronized (provider) {
+                       doQuickParseDebugInfo(monitor);
+               }
+               if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceFinishedQuickParse)); }
+       }
+       
+       /**
+        * Does a quick parse of the .debug_info section just to get a list of
+        * referenced files from the compile units.
+        */
+       private void doQuickParseDebugInfo(IProgressMonitor monitor) {
+               
+               if (debugInfoSection == null) { // no Dwarf data.
+                       return;
+               }
+               
+               // get the compile units out of the .debug_info section
+               IStreamBuffer buffer = debugInfoSection.getBuffer();
+               if (buffer == null) 
+                       return;
+               
+               try {
+                       int lengthSize = 0;
+                       long fileIndex = 0;
+                       long fileEndIndex = buffer.capacity();
+                       
+                       monitor.beginTask(DwarfMessages.DwarfInfoReader_ReadDebugInfo, (int) (fileEndIndex / 1024));
+
+                       buffer.position(0);
+                       while (fileIndex < fileEndIndex) {
+                               buffer.position(fileIndex);
+                               long unit_length = 0;
+                               byte offsetSize = 0;
+                               int debug_abbrev_offset = 0;
+
+                               try {
+                                       InitialLengthValue sectionLength = readInitialLengthField(buffer);
+                                       unit_length = sectionLength.length;
+                                       offsetSize = sectionLength.offsetSize;
+                               } catch (IOException e) {
+                                       e.printStackTrace();
+                               }
+                               
+                               short version           = buffer.getShort();
+                               if (offsetSize == 8) {
+                                       debug_abbrev_offset = (int) buffer.getLong();
+                                       lengthSize = 12;
+                               } else {
+                                       debug_abbrev_offset = buffer.getInt();
+                                       lengthSize = 4;
+                               }
+                               byte address_size       = buffer.get();
+
+                               /*
+                                * With certain GCC-E 3.x compilers, some subset of compile unit headers can have unit
+                                * lengths 4 bytes too long. So before reading this unit's data, make sure there is a
+                                * valid compile unit header right after this unit's data. Adjust the length if needed.
+                                * To validate, check that the DWARF version and the address size are
+                                * the same as the previous compile unit's.
+                                */
+                               if (fileIndex + unit_length + (2 * lengthSize) < fileEndIndex) {
+                                       // try good case
+                                       short nextVersion;
+                                       byte nextAddrSize;
+                                       buffer.position(fileIndex + unit_length + (2 * lengthSize)); // to next version
+                                       nextVersion = buffer.getShort();
+                                       buffer.position(fileIndex + unit_length + (2 * lengthSize) + 2 + debug_abbrev_offset); // to next address size
+                                       nextAddrSize = buffer.get();
+                                       // TODO: is this adjustment still necessary?                                    
+                                       if (version != nextVersion || address_size != nextAddrSize) {
+                                               // try adjusting back by 4 bytes
+                                               buffer.position(fileIndex + unit_length + 4); // to next version
+                                               nextVersion = buffer.getShort();
+                                               buffer.position(fileIndex + unit_length + 10); // to next address size
+                                               nextAddrSize = buffer.get();
+                                               
+                                               if (version == nextVersion && address_size == nextAddrSize) {
+                                                       unit_length -= 4;
+                                               } // otherwise, just let things bomb
+                                       }
+                               }
+                               
+                               buffer.position(fileIndex + lengthSize);
+                               IStreamBuffer data = buffer.wrapSubsection(unit_length);
+                               // skip header info already read
+                               if (offsetSize == 8) {
+                                       data.position(2 + 8 + 1); // sizeof (version + offset + address size)                                   
+                               } else {                                        
+                                       data.position(2 + 4 + 1); // sizeof (version + offset + address size) 
+                               }                               
+
+                               // get the abbreviation entry for the compile unit
+                               // find the offset to the
+                               Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(debug_abbrev_offset);
+
+                               long code = read_unsigned_leb128(data);
+                               AbbreviationEntry entry = abbrevs.get(Long.valueOf(code));
+                               AttributeList attributeList = new AttributeList(entry, data, address_size, getDebugStrings());
+
+                               // get comp_dir and name and figure out the path
+                               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+                               String compDir = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_comp_dir);
+
+                               IPath filePath = fileHelper.normalizeFilePath(compDir, name);
+                               provider.referencedFiles.add(filePath.toOSString());
+
+                               // do a quick parse of the line table to get any other
+                               // referenced files
+                               AttributeValue a = attributeList.getAttribute(DwarfConstants.DW_AT_stmt_list);
+                               if (a != null) {
+                                       int stmtList = a.getValueAsInt();
+                                       quickParseLineInfo(stmtList, compDir);
+                               }
+
+                               // skip past the compile unit. note that the unit_length does
+                               // not include the size of the unit length itself
+                               long oldIndex = fileIndex;
+                               fileIndex += unit_length + lengthSize;
+                               monitor.worked((int) ((fileIndex - oldIndex) / 1024));
+                       }
+
+               } catch (Throwable t) {
+                       EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_ParseSectionSourceFilesFailed1 
+                                       + debugInfoSection.getName() + DwarfMessages.DwarfInfoReader_ParseSectionSourceFilesFailed2 + symbolFilePath, t);
+               } finally {
+                       monitor.done();
+               }
+       }
+
+       /**
+        *  
+        */
+       class InitialLengthValue {
+               /**
+                * section length
+                */
+               long length;
+
+               /**
+                * section offset size in bytes. 
+                */
+               byte offsetSize; //
+       }
+
+       /**
+        * Read section length field from the beginning of dwarf section. 
+        * 
+        * <p>See Chapter 7.4 32-Bit and 64-Bit DWARF Formats</p>
+        * @param data - stream buffer positioned at the start of section length record
+        * @return section length info. Cannot be null.
+        * @throws IOException
+        */
+       InitialLengthValue readInitialLengthField(IStreamBuffer data) throws IOException {
+               InitialLengthValue info = new InitialLengthValue();  
+               info.length = data.getInt() & 0xffffffffL;
+
+               if (info.length == 0xffffffffL) {
+                       info.length = data.getLong();
+                       info.offsetSize = 8;
+               } else if (info.length == 0) { // IRIX
+                       info.length = data.getLong();
+                       info.offsetSize = 8;
+               } else
+                       info.offsetSize = 4;
+               return info;
+       }
+       
+       
+       /**
+        * Get the .debug_strings section.
+        * @return ByteBuffer or <code>null</code>
+        */
+       private IStreamBuffer getDebugStrings() {
+               return getDwarfSection(DWARF_DEBUG_STR);
+       }
+
+       /**
+        * Does a quick parse of the .debug_line section just to get a list of
+        * referenced files from the line table.
+        */
+       private void quickParseLineInfo(int lineTableOffset, String compileUnitDirectory) {
+               IPath compileUnitDirectoryPath = PathUtils.createPath(compileUnitDirectory);
+               try {
+                       // do a quick parse of the line table just to get referenced files
+                       IStreamBuffer data = getDwarfSection(DWARF_DEBUG_LINE);
+                       if (data != null) {
+                               data.position(lineTableOffset);
+
+                               /*
+                                * Skip past the bytes of the header that we don't care about:
+                                * unit_length (4 bytes), version (2 bytes), header_length (4 bytes),
+                                * minimum_instruction_length (1 byte), default_is_stmt (1 byte),
+                                * line_base (1 byte), line_range (1 byte)
+                                */
+                               data.position(data.position() + 14);
+
+                               // we need to get this value so we can skip over
+                               // standard_opcode_lengths
+                               int opcode_base = data.get() & 0xff;
+                               data.position(data.position() + opcode_base - 1);
+
+                               // include_directories
+                               ArrayList<String> dirList = new ArrayList<String>();
+
+                               // add the compilation directory of the CU as the first
+                               // directory
+                               dirList.add(compileUnitDirectory);
+
+                               while (true) {
+                                       String str = readString(data);
+                                       if (str.length() == 0)
+                                               break;
+
+                                       // if the directory is relative, append it to the CU dir
+                                       IPath dir = PathUtils.createPath(str);
+                                       if (!dir.isAbsolute() && dir.getDevice() == null) {
+                                               dir = compileUnitDirectoryPath.append(str);
+                                       }
+                                       dirList.add(dir.toString());
+                               }
+
+                               while (true) {
+                                       String fileName = readString(data);
+                                       if (fileName.length() == 0) // no more file entry
+                                               break;
+
+                                       // dir index
+                                       long leb128 = DwarfInfoReader.read_unsigned_leb128(data);
+
+                                       IPath fullPath = fileHelper.normalizeFilePath(dirList.get((int) leb128), fileName);
+                                       if (fullPath != null) {
+                                               provider.referencedFiles.add(fullPath.toOSString());
+                                       }
+
+                                       // skip the modification time and file size
+                                       leb128 = read_unsigned_leb128(data);
+                                       leb128 = read_unsigned_leb128(data);
+                               }
+                       }
+               } catch (Throwable t) {
+                       EDCDebugger.getMessageLogger().logError(null, t);
+               }
+       }
+
+
+       /**
+        * Parse the line table for a given compile unit
+        * @param attributes
+        * @param fileList list for file entries
+        * @return new array of ILineEntry
+        */
+       @SuppressWarnings("unused")
+       public Collection<ILineEntry> parseLineTable(IScope scope, AttributeList attributes, List<IPath> fileList) {
+               synchronized (provider) {
+                       List<ILineEntry> lineEntries = new ArrayList<ILineEntry>();
+                       try {
+                               IStreamBuffer data = getDwarfSection(DWARF_DEBUG_LINE);
+                               AttributeValue a = attributes.getAttribute(DwarfConstants.DW_AT_stmt_list);
+                               if (data != null && a != null) {
+                                       int stmtList = a.getValueAsInt();
+                                       data.position(stmtList);
+       
+                                       /*
+                                        * Read line table header:
+                                        * 
+                                        * total_length: 4 bytes (excluding itself)
+                                        * version: 2
+                                        * prologue length: 4
+                                        * minimum_instruction_len: 1
+                                        * default_is_stmt: 0 or 1
+                                        * line_base: 1
+                                        * line_range: 1
+                                        * opcode_base: 1
+                                        * standard_opcode_lengths: (value of opcode_base)
+                                        */
+       
+                                       // Remember the CU line tables we've parsed.
+                                       int length = data.getInt() + 4;
+       
+                                       // Skip the following till "opcode_base"
+                                       int version = data.getShort();
+                                       int prologue_length = data.getInt();
+                                       int minimum_instruction_length = data.get() & 0xff;
+                                       boolean default_is_stmt = data.get() > 0;
+                                       int line_base = data.get();  // signed
+                                       int line_range = data.get() & 0xff;
+       
+                                       int opcode_base = data.get() & 0xff;
+                                       byte[] opcodes = new byte[opcode_base - 1];
+                                       data.get(opcodes);
+       
+                                       // Read in directories.
+                                       //
+                                       ArrayList<String> dirList = new ArrayList<String>();
+       
+                                       // Put the compilation directory of the CU as the first dir
+                                       String compDir = attributes.getAttributeValueAsString(DwarfConstants.DW_AT_comp_dir);
+                                       dirList.add(compDir);
+       
+                                       IPath compDirPath = PathUtils.createPath(compDir);
+                                       
+                                       String str, fileName;
+       
+                                       while (true) {
+                                               str = readString(data);
+                                               if (str.length() == 0)
+                                                       break;
+                                               // If the directory is relative, append it to the CU dir
+                                               IPath dir = PathUtils.createPath(str);
+                                               if (!dir.isAbsolute() && dir.getDevice() == null) {
+                                                       dir = compDirPath.append(str);
+                                               }
+                                               dirList.add(dir.toString());
+                                       }
+       
+                                       // Read file names
+                                       //
+                                       long leb128;
+                                       while (true) {
+                                               fileName = readString(data);
+                                               if (fileName.length() == 0) // no more file entry
+                                                       break;
+       
+                                               // dir index
+                                               leb128 = read_unsigned_leb128(data);
+       
+                                               IPath fullPath = fileHelper.normalizeFilePath(dirList.get((int) leb128), fileName);
+                                               // add a null as a placeholder when the filename is enclosed in '<' & '>' (e.g., "<stdin>")
+                                               fileList.add(fullPath);
+       
+                                               // Skip the following
+                                               //
+                                               // modification time
+                                               leb128 = read_unsigned_leb128(data);
+       
+                                               // file size in bytes
+                                               leb128 = read_unsigned_leb128(data);
+                                       }
+       
+                                       long info_address = 0;
+                                       long info_file = 1;
+                                       int info_line = 1;
+                                       int info_column = 0;
+                                       boolean is_stmt = default_is_stmt;
+                                       int info_flags = 0;
+                                       long info_ISA = 0;
+       
+                                       long lineInfoEnd = stmtList + length;
+                                       while (data.position() < lineInfoEnd) {
+                                               byte opcodeB = data.get();
+                                               int opcode = 0xFF & opcodeB;
+       
+                                               if (opcode >= opcode_base) {
+                                                       info_line += (((opcode - opcode_base) % line_range) + line_base);
+                                                       info_address += (opcode - opcode_base) / line_range * minimum_instruction_length;
+                                                       if (is_stmt && fileList.size() > 0) {
+                                                               IPath path = fileList.get((int) info_file - 1);
+                                                               // added a null as a placeholder when the filename was enclosed in '<' & '>' (e.g., "<stdin>")
+                                                               if (path != null)
+                                                                       lineEntries.add(new LineEntry(path, info_line, info_column,     new Addr32(info_address), null));
+                                                       }
+                                                       info_flags &= ~(DwarfConstants.LINE_BasicBlock | DwarfConstants.LINE_PrologueEnd | DwarfConstants.LINE_EpilogueBegin);
+                                               } else if (opcode == 0) {
+                                                       long op_size = read_unsigned_leb128(data);
+                                                       long op_pos = data.position();
+                                                       int code = data.get() & 0xff;
+                                                       switch (code) {
+                                                       case DwarfConstants.DW_LNE_define_file: {
+                                                               fileName = readString(data);
+                                                               long dir = read_unsigned_leb128(data);
+                                                               long modTime = read_unsigned_leb128(data);
+                                                               long fileSize = read_unsigned_leb128(data);
+                                                               IPath fullPath = fileHelper.normalizeFilePath(dirList.get((int) dir), fileName);
+                                                               if (fullPath != null) {
+                                                                       fileList.add(fullPath);
+                                                               }
+                                                               break;
+                                                       }
+                                                       case DwarfConstants.DW_LNE_end_sequence:
+                                                               info_flags |= DwarfConstants.LINE_EndSequence;
+       
+                                                               if (lineEntries.size() > 0) {
+                                                                       // this just marks the end of a line number
+                                                                       // program sequence. use
+                                                                       // its address to set the high address of the
+                                                                       // last line entry
+                                                                       lineEntries.get(lineEntries.size() - 1).setHighAddress(new Addr32(info_address));
+                                                               }
+       
+                                                               // it also resets the state machine
+                                                               info_address = 0;
+                                                               info_file = 1;
+                                                               info_line = 1;
+                                                               info_column = 0;
+                                                               is_stmt = default_is_stmt;
+                                                               info_flags = 0;
+                                                               info_ISA = 0;
+                                                               break;
+       
+                                                       case DwarfConstants.DW_LNE_set_address:
+                                                               info_address = data.getInt();
+                                                               break;
+                                                       default:
+                                                               data.position((int) (data.position() + op_size - 1));
+                                                               break;
+                                                       }
+                                                       assert (data.position() == op_pos + op_size);
+                                               } else {
+                                                       switch (opcode) {
+                                                       case DwarfConstants.DW_LNS_copy:
+                                                               if (is_stmt && fileList.size() > 0) {
+                                                                       lineEntries.add(new LineEntry(fileList.get((int) info_file - 1), info_line,
+                                                                                       info_column, new Addr32(info_address), null));
+                                                               }
+                                                               info_flags &= ~(DwarfConstants.LINE_BasicBlock | DwarfConstants.LINE_PrologueEnd | DwarfConstants.LINE_EpilogueBegin);
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_advance_pc:
+                                                               info_address += read_unsigned_leb128(data) * minimum_instruction_length;
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_advance_line:
+                                                               info_line += read_signed_leb128(data);
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_set_file:
+                                                               info_file = read_unsigned_leb128(data);
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_set_column:
+                                                               info_column = (int) read_unsigned_leb128(data);
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_negate_stmt:
+                                                               is_stmt = !is_stmt;
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_set_basic_block:
+                                                               info_flags |= DwarfConstants.LINE_BasicBlock;
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_const_add_pc:
+                                                               info_address += (255 - opcode_base) / line_range * minimum_instruction_length;
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_fixed_advance_pc:
+                                                               info_address += data.getShort();
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_set_prologue_end:
+                                                               info_flags |= DwarfConstants.LINE_PrologueEnd;
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_set_epilogue_begin:
+                                                               info_flags |= DwarfConstants.LINE_EpilogueBegin;
+                                                               break;
+                                                       case DwarfConstants.DW_LNS_set_isa:
+                                                               info_ISA = read_unsigned_leb128(data);
+                                                               break;
+                                                       default:
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       } catch (Throwable t) {
+                               EDCDebugger.getMessageLogger().logError(null, t);
+                       }
+       
+                       // sort by start address
+                       Collections.sort(lineEntries);
+       
+                       // fill in the end addresses as needed
+                       ILineEntry previousEntry = null;
+                       for (ILineEntry line : lineEntries) {
+                               if (previousEntry != null && previousEntry.getHighAddress() == null) {
+                                       previousEntry.setHighAddress(line.getLowAddress());
+                               }
+       
+                               previousEntry = line;
+                       }
+       
+                       // the last line entry
+                       if (previousEntry != null) {
+                               IAddress prevHigh = previousEntry.getHighAddress();
+                               if (prevHigh == null)
+                                       previousEntry.setHighAddress(scope.getHighAddress());
+// FIXME: the following is causing JUnit tests to fail
+//                     else if (prevHigh != null && prevHigh.compareTo(scope.getHighAddress()) > 0)
+//                             previousEntry.setHighAddress(scope.getHighAddress());
+                       }
+                       
+                       return lineEntries;
+               }
+       }
+
+       private void parseForAddresses(IStreamBuffer in, Map<Long, AbbreviationEntry> abbrevs, CompilationUnitHeader header,
+                       Stack<Scope> nestingStack, IProgressMonitor monitor)
+                       throws IOException {
+
+               if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().trace(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceScopeAddressParse1 + header.scope.getName() + DwarfMessages.DwarfInfoReader_TraceScopeAddressParse2 + Long.toHexString(header.debugInfoOffset))); }
+
+               try {
+                       long startWork = in.remaining();
+                       long lastWork = startWork;
+                       int workChunk = (int)(startWork / Integer.MAX_VALUE) + 1;
+                       int work = (int)(startWork / workChunk);
+                       monitor.beginTask(DwarfMessages.DwarfInfoReader_TraceScopeAddressParse1 + header.scope.getName() + DwarfMessages.DwarfInfoReader_TraceScopeAddressParse2 + Long.toHexString(header.debugInfoOffset), work);
+
+                       while (in.remaining() > 0) {
+                               
+                               work = (int)((lastWork - in.remaining()) / workChunk);
+                               monitor.worked(work);
+                               lastWork = in.remaining();
+
+                               long offset = in.position() + currentCUHeader.debugInfoOffset;
+                               long code = read_unsigned_leb128(in);
+
+                               if (code != 0) {
+                                       AbbreviationEntry entry = abbrevs.get(new Long(code));
+                                       if (entry == null) {
+                                               assert false;
+                                               continue;
+                                       }
+
+                                       if (entry.hasChildren) {
+                                               nestingStack.push(currentParentScope);
+                                       }
+                                       
+                                       if (isDebugInfoEntryWithAddressRange(entry.tag)) {
+                                               AttributeList attributeList = new AttributeList(entry, in, header.addressSize, getDebugStrings());
+                                               processDebugInfoEntry(offset, entry, attributeList, header);
+
+                                               // if we didn't create a scope for a routine or lexical block, then ignore its innards
+                                               switch (entry.tag) {
+                                               case DwarfConstants.DW_TAG_subprogram:
+                                               case DwarfConstants.DW_TAG_inlined_subroutine:
+                                               case DwarfConstants.DW_TAG_lexical_block:
+                                                       if (entry.hasChildren && (provider.scopesByOffset.get(offset) == null)) {
+                                                               // because some versions of GCC-E 3.x produce invalid sibling offsets,
+                                                               // always read entry attributes, rather than skipping using siblings
+                                                               // keep track of nesting just like in parseForTypes()
+                                                               int nesting = 1;
+                                                               while ((nesting > 0) && (in.remaining() > 0)) {
+                                                                       offset = in.position() + currentCUHeader.debugInfoOffset;
+                                                                       code = read_unsigned_leb128(in);
+
+                                                                       if (code != 0) {
+                                                                               entry = abbrevs.get(new Long(code));
+                                                                               if (entry == null) {
+                                                                                       assert false;
+                                                                                       continue;
+                                                                               }
+                                                                               if (entry.hasChildren)
+                                                                                       nesting++;
+                                                                               // skip the attributes we're not reading...
+                                                                               AttributeList.skipAttributes(entry, in, header.addressSize);
+                                                                       } else {
+                                                                               nesting--;
+                                                                       }
+                                                               }
+
+                                                               // nesting loop ends after reading 0 code of skipped entry
+                                                               if (nestingStack.isEmpty()) {
+                                                                       // FIXME
+                                                                       currentParentScope = null;
+                                                               } else {
+                                                                       currentParentScope = nestingStack.pop();
+                                                               }
+                                                       }
+                                                       break;
+                                               }
+                                       } else {
+                                               // skip the attributes we're not reading...
+                                               AttributeList.skipAttributes(entry, in, header.addressSize);
+                                       }
+
+                               } else {
+                                       if (code == 0) {
+                                               if (nestingStack.isEmpty()) {
+                                                       // FIXME
+                                                       currentParentScope = null;
+                                               } else {
+                                                       currentParentScope = nestingStack.pop();
+                                               }
+                                       }
+                               }
+                       }
+               } catch (IOException e) {
+                       throw e;
+               } finally {
+                       monitor.done();
+               }
+       }
+
+
+       private void parseForTypes(IStreamBuffer in, Map<Long, AbbreviationEntry> abbrevs, CompilationUnitHeader header,
+                       Stack<Scope> nestingStack)
+                       throws IOException {
+
+               if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().trace(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceParseTypes1 + header.scope.getName() + DwarfMessages.DwarfInfoReader_TraceParseTypes2 + Long.toHexString(header.debugInfoOffset))); }
+               
+               Stack<IType> typeStack = new Stack<IType>();
+               typeToParentMap.clear();
+               
+               currentParentScope = currentCompileUnitScope;
+               
+               while (in.remaining() > 0) {
+                       long offset = in.position() + currentCUHeader.debugInfoOffset;
+                       long code = read_unsigned_leb128(in);
+
+                       if (code != 0) {
+                               AbbreviationEntry entry = abbrevs.get(new Long(code));
+                               if (entry == null) {
+                                       assert false;
+                                       continue;
+                               }
+                               if (entry.hasChildren) {
+                                       nestingStack.push(currentParentScope);
+                                       typeStack.push(currentParentType);
+                               }
+                               
+                               if (isForwardTypeTag(entry.tag) || isForwardTypeChildTag(entry.tag)) {
+                                       
+                                       processDebugInfoEntry(offset, entry, 
+                                                       new AttributeList(entry, in, header.addressSize, getDebugStrings()), 
+                                                       header);
+                                       
+                               } else {
+                                       switch (entry.tag) {
+                                       case DwarfConstants.DW_TAG_subprogram:
+                                       case DwarfConstants.DW_TAG_inlined_subroutine:
+                                       case DwarfConstants.DW_TAG_lexical_block: {
+                                               Scope scope = provider.scopesByOffset.get(offset);  // may be null
+                                               if (scope != null)
+                                                       currentParentScope = scope;
+                                               break;
+                                       }
+                                       }
+
+                                       // skip the attributes we're not reading...
+                                       AttributeList.skipAttributes(entry, in, header.addressSize);
+                               }
+                       } else {
+                               // code == 0
+                               if (nestingStack.isEmpty()) {
+                                       // FIXME
+                                       currentParentType = null;
+                                       currentParentScope = null;
+                               } else {
+                                       currentParentScope = nestingStack.pop();
+                                       currentParentType = typeStack.pop();
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Tell if a tag will be parsed on-demand to generate an IType, and will
+        * be accessible via provider.getType() or provider.readType().
+        * <p>
+        * Note: DW_TAG_member is usually considered a child of struct/class/etc., but
+        * a static class variable contains a reference to it, so we must be able to
+        * locate it.
+        * @param tag
+        * @return true if type is parsed and should have a ForwardDwarfDefinition
+        */
+       private boolean isForwardTypeTag(short tag) {
+               switch (tag) {
+               case DwarfConstants.DW_TAG_array_type:
+               case DwarfConstants.DW_TAG_class_type:
+               case DwarfConstants.DW_TAG_enumeration_type:
+               case DwarfConstants.DW_TAG_member:
+               case DwarfConstants.DW_TAG_pointer_type:
+               case DwarfConstants.DW_TAG_reference_type:
+               case DwarfConstants.DW_TAG_structure_type:
+               case DwarfConstants.DW_TAG_subroutine_type:
+               case DwarfConstants.DW_TAG_typedef:
+               case DwarfConstants.DW_TAG_union_type:
+               //case DwarfConstants.DW_TAG_unspecified_parameters:
+               case DwarfConstants.DW_TAG_inheritance:
+               case DwarfConstants.DW_TAG_ptr_to_member_type:
+               //case DwarfConstants.DW_TAG_with_stmt:
+               case DwarfConstants.DW_TAG_base_type:
+               //case DwarfConstants.DW_TAG_catch_block:
+               case DwarfConstants.DW_TAG_const_type:
+               //case DwarfConstants.DW_TAG_enumerator:
+               //case DwarfConstants.DW_TAG_file_type:
+               //case DwarfConstants.DW_TAG_friend:
+               case DwarfConstants.DW_TAG_template_type_param:
+               //case DwarfConstants.DW_TAG_template_value_param:
+               //case DwarfConstants.DW_TAG_thrown_type:
+               //case DwarfConstants.DW_TAG_try_block:
+               case DwarfConstants.DW_TAG_volatile_type:
+               case DwarfConstants.DW_TAG_subrange_type:
+                       return true;
+               }
+               return false;
+       }
+       
+
+       /**
+        * Tell if a tag is a parsed child of an IType.  This should not be explicitly
+        * referenced in provider.typesByOffset or .forwardDwarfDefinitions but as
+        * children of other ForwardDwarfDefinitions parsed on demand.
+        *<p>
+        * Note: DW_TAG_member is usually considered a child of struct/class/etc., but
+        * a static class variable contains a reference to it, so we must be able to
+        * locate it.  Thus, it is not listed here.
+        * @param tag
+        * @return true if component is parsed and a child of a forward definition
+        */
+       private boolean isForwardTypeChildTag(short tag) {
+               switch (tag) {
+               //case DwarfConstants.DW_TAG_unspecified_parameters:
+               case DwarfConstants.DW_TAG_inheritance:
+               case DwarfConstants.DW_TAG_enumerator:
+               case DwarfConstants.DW_TAG_member:
+               case DwarfConstants.DW_TAG_subrange_type:
+               //case DwarfConstants.DW_TAG_friend:
+               //case DwarfConstants.DW_TAG_template_type_param:
+               //case DwarfConstants.DW_TAG_template_value_param:
+               //case DwarfConstants.DW_TAG_thrown_type:
+                       return true;
+               }
+               return false;
+       }
+       /**
+        * Fully parse any debug info entry.
+        * @param offset
+        * @param entry
+        * @param attributeList
+        * @param header
+        * @param compositeNesting
+        */
+       private void processDebugInfoEntry(long offset, AbbreviationEntry entry, AttributeList attributeList,
+                       CompilationUnitHeader header) {
+               //System.out.println("Handling " + entry.tag + " at " + Long.toHexString(offset));
+               short tag = entry.tag;
+
+               // We are only interested in certain tags.
+               switch (tag) {
+               case DwarfConstants.DW_TAG_array_type:
+                       processArrayType(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_class_type:
+                       processClassType(offset, attributeList, header, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_enumeration_type:
+                       processEnumType(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_formal_parameter:
+                       processVariable(offset, attributeList, true);
+                       break;
+               case DwarfConstants.DW_TAG_lexical_block:
+                       processLexicalBlock(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_member:
+                       processField(offset, attributeList, header, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_pointer_type:
+                       processPointerType(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_reference_type:
+                       processReferenceType(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_structure_type:
+                       processStructType(offset, attributeList, header, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_subroutine_type:
+                       processSubroutineType(offset, attributeList, header, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_typedef:
+                       processTypeDef(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_union_type:
+                       processUnionType(offset, attributeList, header, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_unspecified_parameters:
+                       break;
+               case DwarfConstants.DW_TAG_inheritance:
+                       processInheritance(offset, attributeList, header, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_ptr_to_member_type:
+                       processPtrToMemberType(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_with_stmt:
+                       break;
+               case DwarfConstants.DW_TAG_base_type:
+                       processBasicType(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_catch_block:
+                       break;
+               case DwarfConstants.DW_TAG_const_type:
+                       processConstType(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_enumerator:
+                       processEnumerator(offset, attributeList);
+                       break;
+               case DwarfConstants.DW_TAG_file_type:
+                       break;
+               case DwarfConstants.DW_TAG_friend:
+                       break;
+               case DwarfConstants.DW_TAG_subprogram:
+                       processSubprogram(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_inlined_subroutine:
+                       processInlinedSubroutine(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_template_type_param:
+                       processTemplateTypeParam(offset, attributeList, header, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_template_value_param:
+                       break;
+               case DwarfConstants.DW_TAG_thrown_type:
+                       break;
+               case DwarfConstants.DW_TAG_try_block:
+                       break;
+               case DwarfConstants.DW_TAG_variable:
+                       processVariable(offset, attributeList, false);
+                       break;
+               case DwarfConstants.DW_TAG_volatile_type:
+                       processVolatileType(offset, attributeList, entry.hasChildren);
+                       break;
+               case DwarfConstants.DW_TAG_subrange_type:
+                       processArrayBoundType(offset, attributeList, entry.hasChildren);
+                       break;
+               }
+       }       
+       
+       /**
+        * Tell whether a tag has or may have content with an address range
+        * 
+        * Note: tag DW_TAG_compile_unit was parsed in the initial parse
+        * 
+        * @param tag
+        * @return
+        */
+       private boolean isDebugInfoEntryWithAddressRange(short tag) {
+               switch (tag) {
+               // tags allowed to have both DW_AT_low_pc and DW_AT_high_pc or DW_at_ranges
+               case DwarfConstants.DW_TAG_catch_block:
+               case DwarfConstants.DW_TAG_inlined_subroutine:
+               case DwarfConstants.DW_TAG_lexical_block:
+               case DwarfConstants.DW_TAG_module:
+               case DwarfConstants.DW_TAG_partial_unit:
+               case DwarfConstants.DW_TAG_subprogram:
+               case DwarfConstants.DW_TAG_try_block:
+               case DwarfConstants.DW_TAG_with_stmt:
+                       return true;
+               // TODO: take DW_TAG_variable out of here?
+               case DwarfConstants.DW_TAG_variable:
+               case DwarfConstants.DW_TAG_formal_parameter:
+                       return true;
+               }
+               return false;
+       }
+       //TODO: support DWARF 64-bit format     
+       static long readAddress(IStreamBuffer in, int addressSize) throws IOException {
+               long value = 0;
+
+               switch (addressSize) {
+               case 2:
+                       value = in.getShort();
+                       break;
+               case 4:
+                       value = in.getInt();
+                       break;
+               case 8:
+                       value = in.getLong();
+                       break;
+               default:
+                       // ????
+               }
+               return value;
+       }
+
+
+       /* unsigned */
+       static long read_unsigned_leb128(IStreamBuffer in) throws IOException {
+               /* unsigned */
+               long result = 0;
+               int shift = 0;
+               byte b;
+
+               while (true) {
+                       if (!in.hasRemaining())
+                               break; // throw new IOException("no more data");
+                       b = in.get();
+                       result |= ((long) (b & 0x7f) << shift);
+                       if ((b & 0x80) == 0) {
+                               break;
+                       }
+                       shift += 7;
+               }
+               return result;
+       }
+
+       /* signed */
+       public static long read_signed_leb128(IStreamBuffer in) throws IOException {
+               /* unsigned */
+               long result = 0;
+               int shift = 0;
+               int size = 32;
+               byte b;
+
+               while (true) {
+                       if (!in.hasRemaining())
+                               throw new IOException(CCorePlugin.getResourceString("Util.exception.noData")); //$NON-NLS-1$
+                       b = in.get();
+                       result |= ((long) (b & 0x7f) << shift);
+                       shift += 7;
+                       if ((b & 0x80) == 0) {
+                               break;
+                       }
+               }
+               if ((shift < size) && (b & 0x40) != 0) {
+                       result |= -(1 << shift);
+               }
+               return result;
+       }
+
+
+       /**
+        * Read a null-ended string from the given "data" stream. data : IN, byte
+        * buffer
+        */
+       public static String readString(IStreamBuffer data) {
+               String str;
+
+               StringBuilder sb = new StringBuilder();
+               while (data.hasRemaining()) {
+                       byte c = data.get();
+                       if (c == 0) {
+                               break;
+                       }
+                       sb.append((char) c);
+               }
+
+               str = sb.toString();
+               return str;
+       }
+
+       private Collection<LocationEntry> getLocationRecord(long offset) {
+               // first check the cache
+               Collection<LocationEntry> entries = locationEntriesByOffset.get(offset);
+               if (entries == null) {
+                       // not found so try to get the entries from the offset
+                       
+                       // note: some compilers generate MULTIPLE ENTRIES for the same location,
+                       // and the last one tends to be more correct... use a map here when reading
+                       TreeMap<IRangeList.Entry, LocationEntry> entryMap = new TreeMap<IRangeList.Entry, LocationEntry>();
+
+                       try {
+                               IStreamBuffer data = getDwarfSection(DWARF_DEBUG_LOC);
+                               if (data != null) {
+                                       data.position(offset);
+                                       
+                                       boolean first = true;
+                                       long base = 0;
+                                       
+                                       while (data.hasRemaining()) {
+
+                                               long lowPC = readAddress(data, currentCUHeader.addressSize);
+                                               long highPC = readAddress(data, currentCUHeader.addressSize);
+
+                                               if (lowPC == 0 && highPC == 0) {
+                                                       // end of list entry
+                                                       break;
+                                               } else if (first) {
+                                                       first = false;
+                                                       long maxaddress = currentCUHeader.addressSize == 4 ? Integer.MAX_VALUE : Long.MAX_VALUE;
+                                                       if (lowPC == maxaddress) {
+                                                               // base address selection entry
+                                                               base = highPC;
+                                                               continue;
+                                                       } else if (currentCompileUnitScope.getRangeList() == null) {
+                                                               // if the compilation unit has a contiguous range, no implicit base is needed
+                                                               base = currentCompileUnitScope.getLowAddress().getValue().longValue();
+                                                       }
+                                               }
+                                               
+                                               // location list entry
+                                               int numOpCodes = data.getShort();
+                                               byte[] bytes = new byte[numOpCodes];
+                                               data.get(bytes);
+                                               LocationEntry entry = new LocationEntry(lowPC + base, highPC + base, bytes);
+                                               entryMap.put(new IRangeList.Entry(lowPC + base, highPC + base), entry);
+                                       }
+
+                                       entries = entryMap.values();
+                                       locationEntriesByOffset.put(offset, entries);
+                               }
+                       } catch (Throwable t) {
+                               EDCDebugger.getMessageLogger().logError(null, t);
+                       }
+               }
+
+               return entries;
+       }
+
+
+       private Map<Long, AbbreviationEntry> parseDebugAbbreviation(int abbreviationOffset) throws IOException {
+               Integer key = Integer.valueOf(abbreviationOffset);
+               Map<Long, AbbreviationEntry> abbrevs = provider.abbreviationMaps.get(key);
+               if (abbrevs == null) {
+                       abbrevs = new HashMap<Long, AbbreviationEntry>();
+                       provider.abbreviationMaps.put(key, abbrevs);
+                       IStreamBuffer data = getDwarfSection(DWARF_DEBUG_ABBREV);
+                       if (data != null) {
+                               data.position(abbreviationOffset);
+                               while (data.remaining() > 0) {
+                                       long code = read_unsigned_leb128(data);
+                                       if (code == 0) {
+                                               break;
+                                       }
+                                       short tag = (short) read_unsigned_leb128(data);
+                                       boolean hasChildren = data.get() == DwarfConstants.DW_CHILDREN_yes;
+                                       AbbreviationEntry entry = new AbbreviationEntry(code, tag, hasChildren);
+
+                                       // attributes
+                                       short name = 0;
+                                       byte form = 0;
+                                       do {
+                                               name = (short) read_unsigned_leb128(data);
+                                               form = (byte) read_unsigned_leb128(data);
+                                               if (name != 0) {
+                                                       entry.attributes.add(new Attribute(name, form));
+                                               }
+                                       } while (name != 0 && form != 0);
+                                       entry.attributes.trimToSize();
+
+                                       abbrevs.put(Long.valueOf(code), entry);
+                               }
+                       }
+               }
+               return abbrevs;
+       }
+
+
+       private void registerType(long offset, IType type, boolean hasChildren) {
+               provider.typesByOffset.put(offset, type);
+               
+               typeToParentMap.put(type, currentParentType);
+               if (hasChildren)
+                       currentParentType = type;
+               if (DEBUG) {
+                       if (type != null) {
+                               System.out.print(DwarfMessages.DwarfInfoReader_ReadType + type.getName());
+                               while (type.getType() != null) {
+                                       type = type.getType();
+                                       System.out.print(" " + type.getName()); //$NON-NLS-1$
+                               }
+                               System.out.println();
+                       }
+               }
+       }
+
+       private void registerScope(long offset, Scope scope) {
+               provider.scopesByOffset.put(offset, scope);
+       }
+
+       /**
+        * Read a range list referenced from a code scope.
+        * @param offset
+        * @param base the specified DW_AT_low_pc value (or 0)
+        * @return a new RangeList
+        */
+       public RangeList readRangeList(int offset, AttributeValue baseValue) {
+               synchronized (provider) {
+                       IStreamBuffer data = getDwarfSection(DWARF_DEBUG_RANGES);
+                       if (data == null) {
+                               return null;
+                       }
+                       
+                       try {
+                               data.position(offset);
+                       
+                               /*
+                                * Read range list entry:
+                                * 
+                                * start: DW_FORM_addr
+                                * end: DW_FORM_addr
+                                * 
+                                * When start == all ones, it is a base address selection entry,
+                                * and end is the base address.  The base address does not need to
+                                * be specified, and is the compialtion unit's base address by default.
+                                * 
+                                * When start == end == 0, this is the end of the list.
+                                */
+       
+                               RangeList list = new RangeList();
+       
+                               long base = 0;
+                               long start = data.getInt();
+                               long end = data.getInt();
+                               
+                               if (start == -1) {
+                                       base = end;
+                                       
+                                       start = data.getInt();
+                                       end = data.getInt();
+                               } else if (baseValue != null) {
+                                       base = baseValue.getValueAsLong();
+                               } else if (currentCompileUnitScope != null && currentCompileUnitScope.getRangeList() == null) {
+                                       base = currentCompileUnitScope.getLowAddress().getValue().longValue();
+                               }
+                               do {
+                                       if (start == 0 && end == 0) {
+                                               break;
+                                       } else if (start != end) {
+                                               // ignore bogus entries: GCC-E sometimes generates these buggily (for artifical non-inlined functions)
+                                               if (base + start >= codeRanges.getLowAddress()) {
+                                                       list.addRange(base + start, base + end);
+                                               }
+                                       }
+                                       start = data.getInt();
+                                       end = data.getInt();
+                                       
+                               } while (true);
+                               
+                               return list;
+                               
+                       } catch (Throwable t) {
+                               EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_RangeReadFailed, t);
+                               return null;
+                       }
+               }
+       }
+
+       
+       
+       /**
+        * Set up the address range for a scope by using its DW_AT_low_pc/DW_AT_high_pc
+        * or DW_AT_ranges attributes, or DW_AT_stmt_list in a pinch
+        * @param attributeList
+        * @param scope
+        */
+       private void setupAddresses(AttributeList attributeList, Scope scope) {
+               
+               // get the high and low pc from the attributes list
+               AttributeValue value
+                 = attributeList.getAttribute(DwarfConstants.DW_AT_high_pc);
+               if (value != null) {
+                       IAddress low = new Addr32(attributeList.getAttributeValueAsLong(DwarfConstants.DW_AT_low_pc));
+                       scope.setLowAddress(low);
+                       IAddress high = new Addr32(attributeList.getAttributeValueAsLong(DwarfConstants.DW_AT_high_pc));
+                       IScope parent = scope.getParent();
+                       if (low.compareTo(high) <= 0) {
+                               if (parent instanceof DwarfFunctionScope) {
+                                       IAddress parentHigh = parent.getHighAddress();
+                                       if (parentHigh != null && high.compareTo(parentHigh) > 0) {
+                                               ((Scope)parent).setHighAddress(high);
+                                       }
+                               }
+                       } else {
+                               // relying on the following to confirm that this is an RVCT inline DWARF generation bug
+                               if (scope instanceof DwarfFunctionScope && parent instanceof DwarfFunctionScope) {
+                                       high = fix_Dwarf_InlineHighAddress_Problem(scope);
+                                       if (high == null)
+                                               // at least prevent ecl.bz Bug 329324 from happening
+                                               high = parent.getHighAddress();
+
+                               // wow, RVCT, you're neat... I think you mean, point to the high PC of the parent
+                               } else if (parent != null && parent.getHighAddress() != null) {
+                                       high = parent.getHighAddress();
+                                       // may still be bogus, check again next
+                               } 
+                               
+                               if (low.compareTo(high) > 0) {
+                                       scope.setLowAddress(high);
+                                       high = low;
+                               }
+                       }
+                       scope.setHighAddress(high);
+                       return;
+               }
+               
+               // look for a range
+               value = attributeList.getAttribute(DwarfConstants.DW_AT_ranges);
+               if (value != null) {
+                       AttributeValue baseValue = attributeList.getAttribute(DwarfConstants.DW_AT_low_pc);
+                       RangeList ranges = readRangeList(value.getValueAsInt(), baseValue);
+                       if (ranges != null) {
+                               scope.setRangeList(ranges);
+                               
+                               // if the range list high and low pc extend outside the parent's
+                               // high/low range, adjust the parent (found in GCC-E)
+                               if (ranges.getLowAddress() < scope.getParent().getLowAddress().getValue().longValue()) {
+                                       if (scope.getParent() instanceof Scope)
+                                               ((Scope)scope.getParent()).setLowAddress(new Addr32(ranges.getLowAddress()));
+                               }
+                               if (ranges.getHighAddress() > scope.getParent().getHighAddress().getValue().longValue()) {
+                                       if (scope.getParent() instanceof Scope)
+                                               ((Scope)scope.getParent()).setHighAddress(new Addr32(ranges.getHighAddress()));
+                               }
+                               return;
+                       }
+               }
+               
+               // in a CU, GCC-E may have only generated this, so we need to dig into the line table
+               if (scope instanceof ICompileUnitScope) {
+                       value = attributeList.getAttribute(DwarfConstants.DW_AT_stmt_list);
+                       if (value != null) {
+                               RangeList ranges = new RangeList();
+                               for (ILineEntry entry : ((ICompileUnitScope) scope).getLineEntries()) {
+                                       // ignore (for now) entries that seem far out of range
+                                       if (entry.getLowAddress().getValue().longValue() >= codeRanges.getLowAddress()) {
+                                               ranges.addRange(entry.getLowAddress().getValue().longValue(),
+                                                               entry.getHighAddress().getValue().longValue());
+                                       }
+                               }
+                               scope.setRangeList(ranges);
+                               return;
+                       }
+               }
+               
+               // no code, apparently
+               scope.setLowAddress(new Addr32(0));
+               scope.setHighAddress(new Addr32(0));
+       }
+
+       /**
+        * for cases where the compiler generates an incorrect high-address,
+        * the line entry provider can give information about the current and
+        * subsequent lines within an inline.
+        * <br>
+        * caveats: this is not meant to handle nested broken inlines.  the
+        * algorithm assumes
+        * - an outer inline nesting another inline will use set of ranges, not a high-low
+        * - an inline function will likely be in another file
+        * - if not, it will likely be prior to the function that inlines it
+        * - and if not, it will likely be more than 32 lines after the function that inlines it
+        * @param scope
+        * @return high address if determined, or null if prerequisites for finding it aren't met.
+        */
+       private IAddress fix_Dwarf_InlineHighAddress_Problem(Scope scope) {
+               IAddress low = scope.getLowAddress();
+               IAddress highest = scope.getParent().getHighAddress();
+               Iterator<ILineEntry> lineEntries
+                 = currentCompileUnitScope.getLineEntries().iterator();
+
+               ILineEntry entry;
+               do {
+                       entry = lineEntries.next();
+                       if (entry == null)
+                               return null;
+               } while (low.compareTo(entry.getHighAddress()) > 0);
+
+               IAddress high = null;
+               IPath actualPath = entry.getFilePath(), otherPath = null;
+               int actualLine = entry.getLineNumber();
+               int thisLine = actualLine, lastLine = 0;                // XXX false positive on uninitialized variable below causes needless initialization of lastLine = 0
+               boolean jumpedBack = false, jumpedAway = false;
+               OUTER:do {
+                       IAddress nextHigh = entry.getHighAddress(); 
+                       if (highest != null && nextHigh != null && highest.compareTo(nextHigh) < 0) {
+                               nextHigh = entry.getLowAddress();
+                               if (high == null || nextHigh.compareTo(high) < 0)
+                                       high = nextHigh;
+                               break;
+                       }
+                       high = nextHigh;
+                       if (!jumpedAway && otherPath == null)
+                               lastLine = thisLine;
+
+                       if (high == null)
+                               break OUTER;
+                       
+                       do {
+                               entry = lineEntries.next();
+                               if (entry == null)
+                                       break OUTER;
+                       } while (high.equals(entry.getHighAddress()));
+
+                       if (otherPath != null) {
+                               if (entry.getFilePath().equals(actualPath))     // done with nesting
+                                       break;
+                       } else if (!entry.getFilePath().equals(actualPath))     {// easiest test for done with inline
+                               otherPath = entry.getFilePath();
+                       } else {
+                               thisLine = entry.getLineNumber();
+                               if (!jumpedBack && !jumpedAway) {
+                                       if (thisLine < actualLine) {
+                                               jumpedBack = true;
+                                       } else if (thisLine > lastLine + 24) {  // XXX false positive here causes needless init of lastLine = 0 above
+                                               jumpedAway = true;
+                                       }
+                               } else if (jumpedBack) {
+                                       if (thisLine > actualLine) // jumped back ahead; done
+                                               break;
+                               } else if (jumpedAway) {
+                                       if (thisLine < actualLine
+                                                       || thisLine < lastLine
+                                                       || thisLine > lastLine + 24)
+                                               break;
+                               }                                       
+                       }
+               } while (entry != null);
+
+               return high;
+       }
+
+       /**
+        * Process a compile unit
+        * 
+        * @param attributeList
+        * @param childrenPosition
+        */
+       private void processCompileUnit(CompilationUnitHeader header, boolean hasChildren, AttributeList attributeList) {
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               String compDir = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_comp_dir);
+               //System.out.println("processing compile unit: " + Integer.toHexString(header.debugInfoOffset) + ": " + name);
+
+               IPath filePath = fileHelper.normalizeFilePath(compDir, name);
+               
+               currentCompileUnitScope = new DwarfCompileUnit(provider, moduleScope, filePath, null, null, header, hasChildren, attributeList);
+               header.scope = currentCompileUnitScope;
+               currentParentScope = currentCompileUnitScope;
+               
+               setupAddresses(attributeList, currentCompileUnitScope);
+
+               // some compilers (RVCT) may generate multiple compile units for the
+               // same file.
+               List<ICompileUnitScope> matchingCompileUnits = provider.compileUnitsPerFile.get(filePath);
+               
+               if (matchingCompileUnits == null) {
+                       // first one. create it now.
+                       matchingCompileUnits = new ArrayList<ICompileUnitScope>();
+               }
+               
+               matchingCompileUnits.add(currentCompileUnitScope);
+               provider.compileUnitsPerFile.put(filePath, matchingCompileUnits);
+               provider.compileUnits.add(currentCompileUnitScope);
+
+               if (!currentCompileUnitScope.getHighAddress().isZero()) // has code
+                       provider.sortedCompileUnitsWithCode.add(currentCompileUnitScope);
+
+               moduleScope.addChild(currentCompileUnitScope);
+               
+               provider.registerCompileUnitHeader(currentCUHeader.debugInfoOffset, currentCUHeader);
+               
+               if (provider.buildReferencedFilesList) {
+                       provider.referencedFiles.add(filePath.toOSString());
+
+                       // do a quick parse of the line table to get any other referenced files.
+                       // note that even the full parse doesn't parse the line table information.
+                       // that is calculated (and then cached) on demand
+                       AttributeValue a = attributeList.getAttribute(DwarfConstants.DW_AT_stmt_list);
+                       if (a != null) {
+                               int stmtList = a.getValueAsInt();
+                               quickParseLineInfo(stmtList, compDir);
+                       }
+               }
+               
+               // remove unused attributes
+               attributeList.attributeMap.remove(DwarfConstants.DW_AT_name);
+               //attributeList.attributeMap.remove(DwarfConstants.DW_AT_comp_dir); // needed later
+               attributeList.attributeMap.remove(DwarfConstants.DW_AT_low_pc);
+               attributeList.attributeMap.remove(DwarfConstants.DW_AT_high_pc);
+               attributeList.attributeMap.remove(DwarfConstants.DW_AT_ranges);
+       }
+
+       private void processLexicalBlock(long offset, AttributeList attributeList, boolean hasChildren) {
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+
+               if (!attributeList.hasCodeRangeAttributes()) {
+                       // ignore any that don't have a valid range
+                       return;
+               }
+               
+               LexicalBlockScope lb = new LexicalBlockScope(name, currentParentScope, null, null);
+               setupAddresses(attributeList, lb);
+
+               currentParentScope.addChild(lb);
+               registerScope(offset, lb);
+               if (hasChildren)
+                       currentParentScope = lb;
+       }
+
+       static class DereferencedAttributes {
+               public CompilationUnitHeader header;
+               public AttributeList attributeList;
+               
+               public DereferencedAttributes(CompilationUnitHeader header,
+                               AttributeList attributeList) {
+                       this.header = header;
+                       this.attributeList = attributeList;
+               }
+               
+       }
+
+       /**
+        * DW_AT_abstract_origin and DW_AT_specification can refer to types in other
+        * compilation units. This will dynamically parse that CU if needed in order
+        * to get the attributes for the type.
+        * 
+        * @param debugInfoOffset
+        * @return AttributeList or <code>null</code> (should not happen)
+        */
+       private DereferencedAttributes getDereferencedAttributes(AttributeList attributeList, short tag) {
+               CompilationUnitHeader providingCU = currentCUHeader;
+               AttributeValue derefLocation = attributeList.getAttribute(tag);
+               if (derefLocation == null)
+                       return null;
+               
+               // get the offset into the .debug_info section
+               long debugInfoOffset =  derefLocation.getValueAsLong();
+               if (derefLocation.getActualForm() == DwarfConstants.DW_FORM_ref_addr) {
+                       // this is already relative to the .debug_info section
+               } else {
+                       // relative to the CU 
+                       debugInfoOffset += providingCU.debugInfoOffset;
+               }
+               
+               AttributeList attributes = provider.functionsByOffset.get(debugInfoOffset);
+               if (attributes == null) {
+                       // dereferenced function does not exist yet
+                       providingCU = provider.fetchCompileUnitHeader(debugInfoOffset);
+                       attributes = provider.functionsByOffset.get(debugInfoOffset);
+                       if (attributes == null) {
+                               // dereferenced entry is not parsed yet, perhaps because it's
+                               // later in the current compile unit (despite Dwarf 3 spec saying
+                               // that's not allowed)
+                               IStreamBuffer buffer = getDwarfSection(DWARF_DEBUG_INFO);
+       
+                               if (buffer != null) {
+                                       buffer.position(debugInfoOffset);
+       
+                                       try {
+                                               // get stored abbrev table, or read and parse an abbrev table
+                                               Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(providingCU.abbreviationOffset);
+       
+                                               long code = read_unsigned_leb128(buffer);
+       
+                                               if (code != 0) {
+                                                       AbbreviationEntry entry = abbrevs.get(new Long(code));
+                                                       if (entry != null) {
+                                                               attributes = new AttributeList(entry, buffer, providingCU.addressSize, getDebugStrings());
+                                                       }
+                                               }
+                                       } catch (Throwable t) {
+                                               EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed1 
+                                                               + debugInfoSection.getName() + DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed2 + symbolFilePath, t);
+                                       }
+                               }
+                       }
+               } else {
+                       providingCU = provider.fetchCompileUnitHeader(debugInfoOffset);
+                       if (providingCU == null) {
+                               assert(false);
+                               return null;
+                       }
+               }
+
+               if (attributes == null)
+                       return null;
+               
+               return new DereferencedAttributes(providingCU, attributes);
+       }
+
+       private void processSubprogram(long offset, AttributeList attributeList, boolean hasChildren) {
+               // if it's a declaration just add to the offsets map for later lookup
+               if (attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_declaration) > 0) {
+                       provider.functionsByOffset.put(offset, attributeList);
+                       return;
+               }
+
+               // functions with no high/low pc aren't real functions. just treat them
+               // as declarations as they will be pointed to by abstract_origin from
+               // another subprogram tag
+               if (!attributeList.hasCodeRangeAttributes()) {
+                       provider.functionsByOffset.put(offset, attributeList);
+                       return;
+               }
+
+               CompilationUnitHeader otherCU = null;
+
+               boolean isArtificial = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_artificial) > 0;
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               if (name.length() == 0) {
+                       // no name. see if we can get it from a declaration
+                       DereferencedAttributes deref = getDereferencedAttributes(attributeList, DwarfConstants.DW_AT_abstract_origin); 
+                       if (deref != null) {
+                               // this should either have a name or point to another
+                               // declaration
+                               otherCU = deref.header;
+                               AttributeList attributes = deref.attributeList;
+                               name = attributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+                               isArtificial |= attributes.getAttributeValueAsInt(DwarfConstants. DW_AT_artificial) > 0;
+                               if (name.length() == 0) {
+                                       deref = getDereferencedAttributes(attributes, DwarfConstants.DW_AT_specification); 
+                                       if (deref != null) {
+                                               // this should either have a name or point to another
+                                               // declaration
+                                               otherCU = deref.header;
+                                               attributes = deref.attributeList;
+                                               name = attributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+                                               isArtificial |= attributes.getAttributeValueAsInt(DwarfConstants. DW_AT_artificial) > 0;
+                                       }
+                               }
+                       }
+               }
+               if (name.length() == 0) {
+                       DereferencedAttributes deref = getDereferencedAttributes(attributeList, DwarfConstants.DW_AT_specification); 
+                       if (deref != null) {
+                               // this should either have a name or point to another
+                               // declaration
+                               otherCU = deref.header;
+                               AttributeList attributes = deref.attributeList;
+                               name = attributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+                       }
+               }
+
+               if (name.length() == 0) {
+                       // the name should either be an attribute of the compile unit, or be
+                       // in the declaration which according to the spec will always be
+                       // before its definition in the Dwarf.
+                       EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_SubprogramNameNotFound1 + Long.toHexString(offset) +
+                                       DwarfMessages.DwarfInfoReader_SubprogramNameNotFound2, null);
+                       return;
+               }
+
+               DwarfFunctionScope function = new DwarfFunctionScope(name, currentCompileUnitScope, null, null, null);
+               setupAddresses(attributeList, function);
+               
+               Scope originalParentScope = currentParentScope;
+               registerScope(offset, function);
+               currentParentScope = function;  // needed for getLocationProvider(), etc.
+               
+               AttributeValue frameBaseAttribute = attributeList.getAttribute(DwarfConstants.DW_AT_frame_base);
+               ILocationProvider locationProvider = getLocationProvider(frameBaseAttribute);
+               function.setLocationProvider(locationProvider);
+               
+               // Note: we may still have cases where DW_AT_low_pc and/or DW_AT_high_pc are 0x0
+               // (some "ignored inlined" functions in GCC).  We want to keep track of their scope
+               // (though not store them in the CU), because child tag parses expect to find a parent into 
+               // which to write their formal parameters and locals.
+               if (!function.getLowAddress().isZero() && !function.getHighAddress().isZero() && !isArtificial) {
+                       // find the declaration location
+                       int declLine = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_line);
+                       int declColumn = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_column);
+                       int declFileNum = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_file);
+                       
+                       if (otherCU != null)
+                               function.setDeclFile(otherCU.scope.getFileEntry(declFileNum));
+                       else
+                               function.setDeclFileNum(declFileNum);
+                       function.setDeclLine(declLine);
+                       function.setDeclColumn(declColumn);
+                       
+                       currentCompileUnitScope.addChild(function);
+                       
+                       // keep track of all functions by name for faster lookup
+                       List<IFunctionScope> functions = provider.functionsByName.get(name);
+                       if (functions == null) {
+                               functions = new ArrayList<IFunctionScope>();
+                               provider.functionsByName.put(name, functions);
+                       }
+                       functions.add(function);
+               }
+               
+               // if the entry has no children, then restore the original parent scope
+               if (!hasChildren)
+                       currentParentScope = originalParentScope;
+       }
+
+       /** 
+        * Get the already-parsed or forward reference to a type from a DW_AT_type attribute, if present
+        * @param attributeMap the map of Long, AttributeValue from AttributeList or Object, Object from Type
+        * @return offset to referenced type or 0 if no type attribute 
+        */
+       private IType getTypeOrReference(AttributeList attributeList, CompilationUnitHeader header) {
+               AttributeValue typeAttribute = attributeList.getAttribute(DwarfConstants.DW_AT_type);
+               if (typeAttribute == null)
+                       return null;
+               return getTypeOrReference(typeAttribute, header);
+       }
+       /** 
+        * Get the already-parsed or forward reference to a type from a DW_AT_type attribute, if present
+        * @param attributeMap the map of Long, AttributeValue from AttributeList or Object, Object from Type
+        * @return offset to referenced type or 0 if no type attribute 
+        */
+       private IType getTypeOrReference(AttributeValue typeAttribute, CompilationUnitHeader header) {
+               if (typeAttribute == null)
+                       return null;
+               
+               // get the offset into the .debug_info section
+               long debugInfoOffset = typeAttribute.getValueAsLong();
+               if (typeAttribute.getActualForm() == DwarfConstants.DW_FORM_ref_addr) {
+                       // this is already relative to the .debug_info section
+               } else {
+                       debugInfoOffset += header.debugInfoOffset;
+               }
+               
+               IType type = provider.typesByOffset.get(debugInfoOffset);
+               if (type == null) {
+                       type = new ForwardTypeReference(provider, debugInfoOffset);
+               }
+               return type;
+       }
+        
+       private void processInlinedSubroutine(long offset, AttributeList attributeList, boolean hasChildren) {
+               // functions with no high/low pc aren't real (probably an error)
+               if (!attributeList.hasCodeRangeAttributes()) {
+                       return;
+               }
+
+               DereferencedAttributes deref = getDereferencedAttributes(attributeList, DwarfConstants.DW_AT_abstract_origin);
+               if (deref == null) {
+                       if (attributeList.getAttribute(DwarfConstants.DW_AT_abstract_origin) != null) {
+                               // TODO: GCC-E can reference forward tags (!) so we need to handle these another way
+                       } else {
+                               assert(false);
+                       }
+                       return;
+               }
+               
+               CompilationUnitHeader otherCU = deref.header;
+               AttributeList origAttributes = deref.attributeList;
+               
+               // this should either have a name or point to another
+               // declaration
+               String name = origAttributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               if (name.length() == 0) {
+                       deref = getDereferencedAttributes(origAttributes, DwarfConstants.DW_AT_specification);
+                       if (deref != null) {
+                               // this should either have a name or point to another
+                               // declaration
+                               //otherCU = deref.header;
+                               AttributeList declarationAttributes = deref.attributeList;
+                               name = declarationAttributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+                       }
+               }
+
+               if (name.length() == 0) {
+                       // the name should either be an attribute of the compile unit, or be
+                       // in the declaration which according to the spec will always be
+                       // before its definition in the Dwarf.
+                       return;
+               }
+
+               // find the declaration location
+               int declLine = origAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_line);
+               int declColumn = origAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_column);
+               int declFileNum = origAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_file);
+               
+               if (declFileNum == 0) {
+                       assert(false);
+                       return;
+               }
+               
+               DwarfFunctionScope function = new DwarfFunctionScope(name, currentParentScope, null, null, null);
+               setupAddresses(attributeList, function);
+               
+               function.setDeclFile(otherCU.scope.getFileEntry(declFileNum));
+               function.setDeclLine(declLine);
+               function.setDeclColumn(declColumn);
+               
+               currentParentScope.addChild(function);
+               
+               registerScope(offset, function);
+               if (hasChildren)
+                       currentParentScope = function;
+               
+               // keep track of all functions by name for faster lookup
+               List<IFunctionScope> functions = provider.functionsByName.get(name);
+               if (functions == null) {
+                       functions = new ArrayList<IFunctionScope>();
+                       provider.functionsByName.put(name, functions);
+               }
+               functions.add(function);
+       }
+
+       private void processSubroutineType(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               SubroutineType type = new SubroutineType(currentParentScope, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               registerType(offset, type, hasChildren);
+               
+               // TODO: associate parameters with this type in child tag parse
+               
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+       
+       private void processClassType(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+               
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+
+               // if the name is mangled, unmangle it
+               name = unmangleType(name);
+               
+               // GCC may put the template parameter of an inherited class at the end of the name,
+               // so strip that off
+               // TODO: support template parameters at end of name or as separate DW_TAG_template_value_param
+               if (name.endsWith(">")) {
+                       int templateStart = name.indexOf("<");
+                       if (templateStart != -1)
+                               name = name.substring(0, templateStart);
+               }
+
+               int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
+
+               ClassType type = new ClassType(name, currentParentScope, byteSize, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               registerType(offset, type, hasChildren);
+               storeTypeByName(name, type);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+       
+       private void processStructType(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+
+               // if the name is mangled, unmangle it
+               name = unmangleType(name);
+
+               StructType type = new StructType(name, currentParentScope, byteSize, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               registerType(offset, type, hasChildren);
+               storeTypeByName(name, type);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processUnionType(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+
+               // if the name is mangled, unmangle it
+               name = unmangleType(name);
+
+               UnionType type = new UnionType(name, currentParentScope, byteSize, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               registerType(offset, type, hasChildren);
+               storeTypeByName(name, type);
+               
+               /*
+                * For an anonymous union, which has members accessible by methods in a class, ARM RVCT
+                * does not create an unnamed class member so you know the offset of the union's members.
+                * Instead, it just gives the anonymous union's type a name of the form "__C" followed
+                * by a number. And it places the union's DWARF info after all class member and inherited
+                * member DWARF info.
+                * 
+                * E.g., when you have 2 named members and 2 anonymous unions in this order:
+                *              4-byte union <anonymous 1>
+                *              4-byte long  long1
+                *              4-byte union <anonymous 2>
+                *              4-byte long  long2
+                * ARM RVCT DWARF info says the class has 2 members:
+                *              long1 at offset  4
+                *              long2 at offset 12
+                * ARM RVCT DWARF info is in the order:
+                *              member long1
+                *              member long2
+                *              type   union <anonymous 1>
+                *              type   union <anonymous 2>
+                * So the rules for handling anonymous unions in RVCT DWARF are:
+                *              1st read offsets and sizes of non-anonymous members, which leaves offset holes
+                *                      for anonymous unions
+                *              2nd read anonymous union type info, which have compiler-generated names of
+                *                      "__C" following by a number, and assign unnamed members to offset holes
+                */
+               boolean isRVCTAnonymousUnion = false;
+               try {
+                       isRVCTAnonymousUnion = name.startsWith("__C") && (name.length() > 3) && //$NON-NLS-1$
+                                                               (name.charAt(3) != '-') && (Long.parseLong(name.substring(3)) > -1);
+               } catch (NumberFormatException nfe) {}
+
+               // if needed, create an "unnamed" member field with an offset to be determined later
+               if (isRVCTAnonymousUnion && getCompositeParent(typeToParentMap.get(currentParentType)) != null) {
+                       ICompositeType compositeType = getCompositeParent(typeToParentMap.get(currentParentType));
+
+                       // unnamed member accessibility depends on the enclosing composite's type -
+                       // public for a struct or union, private for a class
+                       int accessibility = ICompositeType.ACCESS_PUBLIC;
+                       if (compositeType instanceof ClassType)
+                               accessibility = ICompositeType.ACCESS_PRIVATE;
+
+                       // empty field names confuse the expressions service
+                       String fieldName = "$unnamed$" + (compositeType.fieldCount() + 1); //$NON-NLS-1$
+
+                       // since we're generating a field, give it a -1 offset. We cannot tell the real
+                       // offset until we determine offsets of all previously defined members - which
+                       // may include inherited types not yet read in Dwarf info
+                       FieldType fieldType = new FieldType(fieldName, currentParentScope, compositeType, -1, 0, 0,
+                                       byteSize, accessibility, null);
+                       fieldType.setType(type);
+
+                       // add the member to the deepest nested (last added) compositeNesting
+                       // member
+                       compositeType.addField(fieldType);
+                       registerType(offset, fieldType, false);
+               }
+
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processInheritance(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               ICompositeType compositeType = getCompositeParent();
+               
+               // The allowed attributes are DW_AT_type, DW_AT_data_member_location,
+               // and DW_AT_accessibility
+               long fieldsOffset = 0;
+               byte[] offsetBlock = attributeList.getAttributeValueAsBytes(DwarfConstants.DW_AT_data_member_location);
+               // unsigned LEB128 encoding
+               if (offsetBlock.length > 0 && offsetBlock[0] == DwarfConstants.DW_OP_plus_uconst) {
+                       for (int i = 1, shift = 0; i < offsetBlock.length; i++) {
+                               fieldsOffset += (offsetBlock[i] & 0x7f) << shift;
+                               shift += 7;
+                       }
+               }
+
+               // default accessibility is private
+               int accessibility = ICompositeType.ACCESS_PRIVATE;
+               if (attributeList.getAttribute(DwarfConstants.DW_AT_accessibility) != null) {
+                       accessibility = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_accessibility);
+                       
+                       if (accessibility == DwarfConstants.DW_ACCESS_public)
+                               accessibility = ICompositeType.ACCESS_PUBLIC;
+                       else if (accessibility == DwarfConstants.DW_ACCESS_private)
+                               accessibility = ICompositeType.ACCESS_PRIVATE;
+                       else
+                               accessibility = ICompositeType.ACCESS_PROTECTED;
+               }
+               
+               InheritanceType type = new InheritanceType(currentParentScope, accessibility, fieldsOffset, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               
+               // add the member to the deepest nested (last added) compositeNesting
+               // member
+               if (compositeType != null)
+                       compositeType.addInheritance(type);
+               
+               registerType(offset, type, hasChildren);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processField(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               
+               // GCC-E has fields like "_vptr.BaseClass" which will be a problem for us 
+               // (since '.' is an operator); rename these here
+               name = name.replace('.', '$');
+       
+               int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
+               int bitSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_bit_size);
+               int bitOffset = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_bit_offset);
+
+               long fieldOffset = 0;
+               byte[] offsetBlock = attributeList.getAttributeValueAsBytes(DwarfConstants.DW_AT_data_member_location);
+               // unsigned LEB128 encoding
+               if (offsetBlock.length > 0 && offsetBlock[0] == DwarfConstants.DW_OP_plus_uconst) {
+                       for (int i = 1, shift = 0; i < offsetBlock.length; i++) {
+                               fieldOffset += (offsetBlock[i] & 0x7f) << shift;
+                               shift += 7;
+                       }
+               }
+
+               ICompositeType compositeType = getCompositeParent();
+
+               // default accessibility depends on the composite type -
+               // public for a struct or union, private for a class
+               int accessibility = ICompositeType.ACCESS_PUBLIC;
+               if (attributeList.getAttribute(DwarfConstants.DW_AT_accessibility) != null) {
+                       accessibility = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_accessibility);
+                       
+                       if (accessibility == DwarfConstants.DW_ACCESS_public)
+                               accessibility = ICompositeType.ACCESS_PUBLIC;
+                       else if (accessibility == DwarfConstants.DW_ACCESS_private)
+                               accessibility = ICompositeType.ACCESS_PRIVATE;
+                       else
+                               accessibility = ICompositeType.ACCESS_PROTECTED;
+               } else if (compositeType != null && compositeType instanceof ClassType)
+                       accessibility = ICompositeType.ACCESS_PRIVATE;
+
+               // Empty fields confuse the expressions service (#10369)
+               if (name.length() == 0) {
+                       if (compositeType != null) {
+                               name = "$unnamed$" + (compositeType.fieldCount() + 1); //$NON-NLS-1$
+                       } else {
+                               name = "$unnamed$"; //$NON-NLS-1$
+                       }
+               }
+
+               FieldType type = new FieldType(name, currentParentScope, compositeType, fieldOffset, bitSize, bitOffset,
+                               byteSize, accessibility, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               // add the member to the deepest nested (last added) compositeNesting
+               // member
+               if (compositeType != null)
+                       compositeType.addField(type);
+               registerType(offset, type, hasChildren);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processTemplateTypeParam(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               IType paramType = getTypeOrReference(attributeList.getAttribute(DwarfConstants.DW_AT_type), currentCUHeader);
+
+               TemplateParamType type = new TemplateParamType(name, paramType);
+               
+               ICompositeType compositeType = getCompositeParent();
+
+               // add the template param to the deepest nested (last added) compositeNesting
+               // member
+               if (compositeType != null)
+                       compositeType.addTemplateParam(type);
+               registerType(offset, type, hasChildren);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+       
+       private ICompositeType getCompositeParent() {
+               return getCompositeParent(currentParentType);
+       }
+       
+       private ICompositeType getCompositeParent(IType parent) {
+               while (parent != null) {
+                       if (parent instanceof ICompositeType)
+                               return ((ICompositeType) parent);
+                       parent = typeToParentMap.get(parent);
+               }
+               return null;
+       }
+
+       private void processArrayType(long offset, AttributeList attributeList, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
+
+               ArrayType type = new ArrayType(name, currentParentScope, byteSize, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               registerType(offset, type, hasChildren);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private IArrayType getArrayParent() {
+               IType parent = currentParentType;
+               while (parent != null) {
+                       if (parent instanceof IArrayType)
+                               return ((IArrayType) parent);
+                       parent = typeToParentMap.get(parent);
+               }
+               return null;
+       }
+
+       private void processArrayBoundType(long offset, AttributeList attributeList, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               long arrayBound = 0;
+               if (attributeList.getAttribute(DwarfConstants.DW_AT_upper_bound) != null)
+                       arrayBound = attributeList.getAttributeValueAsLong(DwarfConstants.DW_AT_upper_bound) + 1;
+
+               ArrayBoundType type = new ArrayBoundType(currentParentScope, arrayBound);
+
+               IArrayType array = getArrayParent();
+               if (array == null)
+                       throw new IllegalStateException();
+               array.addBound(type);
+
+               registerType(offset, type, hasChildren);
+               
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processReferenceType(long offset, AttributeList attributeList, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
+
+               if (byteSize == 0)
+                       byteSize = currentCUHeader.addressSize;
+               
+               ReferenceType type = new ReferenceType(name, currentParentScope, byteSize, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               registerType(offset, type, hasChildren);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processPointerType(long offset, AttributeList attributeList, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
+               
+               if (byteSize == 0)
+                       byteSize = currentCUHeader.addressSize;
+               
+               PointerType type = new PointerType(name, currentParentScope, byteSize, null);
+               type.setType(getTypeOrReferenceOrVoid(attributeList));
+               registerType(offset, type, hasChildren);
+               storeTypeByName(name, type);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processPtrToMemberType(long offset, AttributeList attributeList, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+
+               // unnamed data types don't get stored by name
+               if (name.length() == 0)
+                       name = "" + offset;
+               
+               PointerType type = new PointerType(name, currentParentScope, currentCUHeader.addressSize, null);
+               type.setType(getTypeOrReferenceOrVoid(attributeList));
+               registerType(offset, type, hasChildren);
+               storeTypeByName(name, type);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processConstType(long offset, AttributeList attributeList, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               ConstType type = new ConstType(currentParentScope, null);
+               type.setType(getTypeOrReferenceOrVoid(attributeList));
+               registerType(offset, type, hasChildren);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processVolatileType(long offset, AttributeList attributeList, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               VolatileType type = new VolatileType(currentParentScope, null);
+               type.setType(getTypeOrReferenceOrVoid(attributeList));
+               registerType(offset, type, hasChildren);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+       
+       // for void pointers, GCC will produce qualifiers and pointers without types or references,
+       // so create a void to be qualified or pointed to
+       private IType getTypeOrReferenceOrVoid(AttributeList attributeList) {
+               IType typeOrReference = getTypeOrReference(attributeList, currentCUHeader);
+               if (typeOrReference != null)
+                       return typeOrReference;
+               
+               if (moduleScope != null && voidType == null) {
+                       voidType = new CPPBasicType("void", moduleScope, IBasicType.t_void, 0, 0, null);
+               }
+
+               if (voidType != null)
+                       return voidType;
+
+               return new CPPBasicType("void", currentParentScope, IBasicType.t_void, 0, 0, null);
+       }
+
+       private void processEnumType(long offset, AttributeList attributeList, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               // if the name is mangled, unmangle it
+               name = unmangleType(name);
+
+               int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
+
+               Enumeration type = new Enumeration(name, currentParentScope, byteSize, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               registerType(offset, type, hasChildren);
+               storeTypeByName(name, type);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private Enumeration getEnumerationParent() {
+               IType parent = currentParentType;
+               while (parent != null) {
+                       if (parent instanceof Enumeration)
+                               return ((Enumeration) parent);
+                       parent = typeToParentMap.get(parent);
+               }
+               return null;
+       }
+       
+       private void processEnumerator(long offset, AttributeList attributeList) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               if (unmangler.isMangled(name)) {
+                       try {
+                               name = unmangler.unmangle(name);
+                       } catch (UnmanglingException ue) {
+                       }
+               }
+               long value = attributeList.getAttributeValueAsSignedLong(DwarfConstants.DW_AT_const_value);
+
+               Enumerator enumerator = new Enumerator(name, value);
+               
+               Enumeration enumeration = getEnumerationParent();
+               if (enumeration == null)
+                       throw new IllegalStateException();
+               enumeration.addEnumerator(enumerator);
+               ((Scope)enumeration.getScope()).addEnumerator(enumerator);
+
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(enumerator)); }
+       }
+
+       private void processTypeDef(long offset, AttributeList attributeList, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+
+               // if the name is mangled, unmangle it
+               name = unmangleType(name);
+
+               TypedefType type = new TypedefType(name, currentParentScope, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               registerType(offset, type, hasChildren);
+               storeTypeByName(name, type);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processBasicType(long offset, AttributeList attributeList, boolean hasChildren) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
+
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
+
+               int baseType = IBasicType.t_unspecified;
+               int qualifierBits = 0;
+               int encoding = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_encoding);
+
+               switch (encoding) {
+               case DwarfConstants.DW_ATE_boolean:
+                       baseType = ICPPBasicType.t_bool;
+                       break;
+               case DwarfConstants.DW_ATE_float:
+                       if (name.contains("float")) { //$NON-NLS-1$
+                               baseType = IBasicType.t_float;
+                       } else if (name.contains("long double")) { //$NON-NLS-1$
+                               baseType = IBasicType.t_double;
+                               qualifierBits |= ICPPBasicType.IS_LONG;
+                       } else if (name.contains("double")) { //$NON-NLS-1$
+                               baseType = IBasicType.t_double;
+                       }
+                       break;
+               case DwarfConstants.DW_ATE_signed:
+                       baseType = IBasicType.t_int;
+                       qualifierBits |= ICPPBasicType.IS_SIGNED;
+                       if (name.contains("short")) { //$NON-NLS-1$
+                               qualifierBits |= ICPPBasicType.IS_SHORT;
+                       } else if (name.contains("long long")) { //$NON-NLS-1$
+                               qualifierBits |= ICPPBasicType.IS_LONG_LONG;
+                       } else if (name.contains("long")) { //$NON-NLS-1$
+                               qualifierBits |= ICPPBasicType.IS_LONG;
+                       }
+                       break;
+               case DwarfConstants.DW_ATE_signed_char:
+                       baseType = IBasicType.t_char;
+                       qualifierBits |= ICPPBasicType.IS_SIGNED;
+                       break;
+               case DwarfConstants.DW_ATE_unsigned:
+                       baseType = IBasicType.t_int;
+                       qualifierBits |= ICPPBasicType.IS_UNSIGNED;
+                       if (name.contains("short")) { //$NON-NLS-1$
+                               qualifierBits |= ICPPBasicType.IS_SHORT;
+                       } else if (name.contains("long long")) { //$NON-NLS-1$
+                               qualifierBits |= ICPPBasicType.IS_LONG_LONG;
+                       } else if (name.contains("long")) { //$NON-NLS-1$
+                               qualifierBits |= ICPPBasicType.IS_LONG;
+                       }
+                       break;
+               case DwarfConstants.DW_ATE_unsigned_char:
+                       baseType = IBasicType.t_char;
+                       qualifierBits |= ICPPBasicType.IS_UNSIGNED;
+                       break;
+               case DwarfConstants.DW_ATE_complex_float:
+                       qualifierBits |= ICPPBasicType.IS_COMPLEX;
+                       if (name.contains("float")) { //$NON-NLS-1$
+                               baseType = IBasicType.t_float;
+                       } else if (name.contains("long double")) { //$NON-NLS-1$
+                               baseType = IBasicType.t_double;
+                               qualifierBits |= ICPPBasicType.IS_LONG;
+                       } else if (name.contains("double")) { //$NON-NLS-1$
+                               baseType = IBasicType.t_double;
+                       }
+                       break;
+               case DwarfConstants.DW_ATE_imaginary_float:
+                       qualifierBits |= ICPPBasicType.IS_IMAGINARY;
+                       if (name.contains("float")) { //$NON-NLS-1$
+                               baseType = IBasicType.t_float;
+                       } else if (name.contains("long double")) { //$NON-NLS-1$
+                               baseType = IBasicType.t_double;
+                               qualifierBits |= ICPPBasicType.IS_LONG;
+                       } else if (name.contains("double")) { //$NON-NLS-1$
+                               baseType = IBasicType.t_double;
+                       }
+                       break;
+               case DwarfConstants.DW_ATE_void:
+                       baseType = IBasicType.t_void;
+                       break;
+               case DwarfConstants.DW_ATE_address:
+               case DwarfConstants.DW_ATE_packed_decimal:
+               case DwarfConstants.DW_ATE_numeric_string:
+               case DwarfConstants.DW_ATE_edited:
+               case DwarfConstants.DW_ATE_signed_fixed:
+               case DwarfConstants.DW_ATE_unsigned_fixed:
+               case DwarfConstants.DW_ATE_decimal_float:
+               default:
+                       break;
+               }
+               
+               // RVCT has interesting conceptions about "encoding" here.  Be sure not to get confused later.
+               if (name.equals("void") && byteSize == 0) //$NON-NLS-1$
+                       baseType = IBasicType.t_void;
+               
+               CPPBasicType type = new CPPBasicType(name, currentParentScope, baseType, qualifierBits, byteSize, null);
+               type.setType(getTypeOrReference(attributeList, currentCUHeader));
+               registerType(offset, type, hasChildren);
+               storeTypeByName(name, type);
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
+       }
+
+       private void processVariable(long offset, AttributeList attributeList, boolean isParameter) {
+               if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(attributeList)); }
+
+               AttributeValue locationAttribute = attributeList.getAttribute(DwarfConstants.DW_AT_location);
+               ILocationProvider locationProvider = getLocationProvider(locationAttribute);
+               if (locationProvider == null) {
+                       // No location means either this is a placeholder (in a subprogram declaration) 
+                       // or it may have been optimized out.  See section
+                       // 2.6 of the Dwarf3 spec. for now we're ignoring it but we may be able
+                       // to show it in the view with some special decoration to indicate that
+                       // it's been optimized out
+                       
+                       // assume it is a forward reference if we're inside a function (formal_parameter or local)...
+                       provider.functionsByOffset.put(offset, attributeList);
+                       return;
+               }
+
+               // variables can have abstract origins with most of their contents
+               CompilationUnitHeader otherCU = currentCUHeader;
+               AttributeList otherAttributes = attributeList;
+               String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+               if (name.length() == 0) {
+                       // no name.
+                       // if there is a DW_AT_specification or DW_AT_abstract_origin attribute, use it to get variable attributes
+                       DereferencedAttributes deref = getDereferencedAttributes(attributeList, DwarfConstants.DW_AT_specification);
+                       if (deref == null)
+                               deref = getDereferencedAttributes(attributeList, DwarfConstants.DW_AT_abstract_origin);
+                       if (deref != null) {
+                               // this should either have a name or point to another
+                               // declaration
+                               otherCU = deref.header;
+                               otherAttributes = deref.attributeList;
+                               name = otherAttributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
+                       }
+               }
+
+               boolean global = (otherAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_external) == 1);
+
+               // if the name is mangled, unmangle it
+               if (name.startsWith("_Z")) {
+                       name = unmangle(name);
+               } else if (global) {
+                       // GCCE uses DW_AT_MIPS_linkage_name for the mangled name of an externally visible variable
+                       String mangledName = otherAttributes.getAttributeValueAsString(DwarfConstants.DW_AT_MIPS_linkage_name);
+                       if (unmangler.isMangled(mangledName)) {
+                               try {
+                                       name = unmangler.unmangle(mangledName);
+                               } catch (UnmanglingException ue) {
+                               }
+                       }
+               }
+
+               IType type = getTypeOrReference(otherAttributes.getAttribute(DwarfConstants.DW_AT_type), otherCU);
+               if (type != null) {
+                       long startScope = attributeList.getAttributeValueAsLong(DwarfConstants.DW_AT_start_scope);
+                       boolean isDeclared = otherAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_artificial) <= 0;
+                       
+                       int definingFileNum = otherAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_file);
+                       if (definingFileNum > 0 && attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_declaration) > 0) {
+                               // variable is declared here, but not defined here
+                               definingFileNum = 0;
+                       }
+
+                       IPath definingFile = null;
+
+                       // find the file it's defined in
+                       if (definingFileNum > 0) {
+                               // find the enclosing compile unit to get access to its list of
+                               // .debug_line file names
+                               IScope cuScope = currentParentScope;
+                               while (cuScope != null && !(cuScope instanceof DwarfCompileUnit))
+                                       cuScope = cuScope.getParent();
+
+                               if (cuScope != null) {
+                                       definingFile = ((DwarfCompileUnit) cuScope).getFileEntry(definingFileNum);
+                               }
+                       }
+
+                       DwarfVariable variable = new DwarfVariable(name, 
+                                                       global ? moduleScope : currentParentScope, 
+                                                       locationProvider,
+                                                       type,
+                                                       isDeclared,
+                                                       definingFile);
+
+                       variable.setStartScope(startScope);
+                       
+                       if (isParameter) {
+                               if (currentParentScope instanceof FunctionScope) {
+                                       ((FunctionScope) currentParentScope).addParameter(variable);
+                               } else {
+                                       assert (false);
+                               }
+                       } else {
+                               if (global) {
+                                       // add global variables to the module scope 
+                                       moduleScope.addVariable(variable);
+                                       // AND to the CU scope
+                                       if (currentCompileUnitScope != null) {
+                                               currentCompileUnitScope.addVariable(variable);
+                                       }
+                               } else {
+                                       // the parent scope could be compile unit, function or
+                                       // lexical block
+                                       currentParentScope.addVariable(variable);
+                               }
+
+                               // keep track of all variables by name for faster lookup
+                               List<IVariable> variables = provider.variablesByName.get(name);
+                               if (variables == null) {
+                                       variables = new ArrayList<IVariable>();
+                                       provider.variablesByName.put(name, variables);
+                               }
+                               variables.add(variable);
+                       }
+
+                       if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(variable)); }
+               }
+       }
+
+
+       private ILocationProvider getLocationProvider(AttributeValue locationValue) {
+               if (locationValue != null) {
+                       byte actualForm = locationValue.getActualForm();
+                       if (actualForm == DwarfConstants.DW_FORM_data4) {
+                               // location list
+                               Collection<LocationEntry> entryList = getLocationRecord(locationValue.getValueAsLong());
+                               if (entryList != null) {
+                                       return new LocationList(entryList.toArray(new LocationEntry[entryList.size()]),
+                                                       exeReader.getByteOrder(),
+                                                       currentCUHeader.addressSize, currentParentScope);
+                               }
+                       } else if (actualForm == DwarfConstants.DW_FORM_block
+                                       || actualForm == DwarfConstants.DW_FORM_block1
+                                       || actualForm == DwarfConstants.DW_FORM_block2
+                                       || actualForm == DwarfConstants.DW_FORM_block4) {
+                               // location expression
+                               IStreamBuffer locationData = new MemoryStreamBuffer(locationValue.getValueAsBytes(), exeReader.getByteOrder());
+                               return new LocationExpression(locationData, 
+                                               currentCUHeader.addressSize,
+                                               currentParentScope);
+                       } else {
+                               // should not happen according to the spec
+                               assert (false);
+                       }
+               }
+
+               return null;
+       }
+
+       private void dumpSymbols() {
+               if (DEBUG) {
+                       PrintStream out = null;
+                       try {
+                               out = new PrintStream(new File(dumpFileName));
+                       } catch (FileNotFoundException e) {
+                               System.out.println(DwarfMessages.DwarfInfoReader_DumpFileOpenOrCreateFailed + dumpFileName);
+                               return;
+                       }
+                       
+                       // If to write to console
+                       // PrintStream out = System.out;
+                       
+                       out.println("Module - " + symbolFilePath);
+                       out.println("   Variables - " + moduleScope.getVariables().size());
+                       out.println("   Compile units - " + moduleScope.getChildren().size());
+                       out.println();
+
+                       for (IScope cu : moduleScope.getChildren()) {
+                               out.println("   Compile unit - " + cu.toString());
+                               out.println("           Variables - " + cu.getVariables().size());
+                               out.println("           Functions - " + cu.getChildren().size());
+                               out.println();
+
+                               for (IScope func : cu.getChildren()) {
+                                       out.println("           Function - " + func.toString());
+                                       out.println("                   Variables - " + func.getVariables().size());
+                                       out.println("                   Parameters - " + ((IFunctionScope) func).getParameters().size());
+                                       out.println("                   Lexical blocks - " + func.getChildren().size());
+                                       out.println();
+
+                                       // not accurate: can contain IFunctionScope too!
+                                       for (IScope block : func.getChildren()) {
+                                               out.println("                   Lexical block - " + block.toString());
+                                               out.println("                           Variables - " + block.getVariables().size());
+                                               out.println();
+                                       }
+                               }
+                       }
+                       
+                       out.close();
+               }
+       }
+
+       public void parseForFrameIndices() {
+               synchronized (provider) {
+                       if (!provider.frameDescEntries.isEmpty())
+                               return;
+                       
+                       IExecutableSection frameSection = exeReader.findExecutableSection(DWARF_DEBUG_FRAME);
+                       if (frameSection == null)
+                               return;
+                       
+                       IStreamBuffer buffer = frameSection.getBuffer();
+                       buffer.position(0);
+                       
+                       int addressSize = 4;    // TODO: 64-bit Dwarf
+                       long cie_id = addressSize == 4 ? 0xffffffff : ~0L;
+                       
+                       // in the first pass, just get a mapping of PC ranges to FDEs,
+                       // so we can locate entries quickly (don't pre-parse CIEs or decompile FDE instructions yet)
+                       while (buffer.position() < buffer.capacity()) {
+                               try {
+                                       long fdePtr = buffer.position();
+                                       long headerLength = readAddress(buffer, addressSize);
+                                       long nextPosition = buffer.position() + headerLength;
+                                       
+                                       long ciePtr = readAddress(buffer, addressSize);
+                                       if (ciePtr != cie_id) {
+                                               long initialLocation = readAddress(buffer, addressSize);
+                                               long addressRange = readAddress(buffer, addressSize);
+                                               IStreamBuffer instructions = buffer.wrapSubsection(nextPosition - buffer.position());
+                                               IRangeList.Entry entry = new IRangeList.Entry(initialLocation, initialLocation + addressRange);
+                                               FrameDescriptionEntry fde = new FrameDescriptionEntry(fdePtr, ciePtr,
+                                                               entry.low, entry.high,
+                                                               instructions, addressSize);
+                                               provider.frameDescEntries.put(entry, fde);
+                                       }
+                                       
+                                       buffer.position(nextPosition);
+                               } catch (Throwable t) {
+                                       EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_FrameIndicesReadFailed, t);
+                                       break;
+                               }
+                               
+                       }
+               }
+       }
+
+       /**
+        * Parse a CIE
+        * @param ciePtr
+        * @param addressSize 
+        * @param framePC 
+        * @return the CIE or <code>null</code> in case of error
+        */
+       public CommonInformationEntry parseCommonInfoEntry(Long ciePtr, int addressSize, IAddress framePC) throws IOException {
+               synchronized (provider) {
+                       IExecutableSection frameSection = exeReader.findExecutableSection(DWARF_DEBUG_FRAME);
+                       if (frameSection == null)
+                               return null;
+                       
+                       IStreamBuffer buffer = frameSection.getBuffer();
+                       buffer.position(ciePtr);
+                       
+                       long headerLength = readAddress(buffer, addressSize);
+                       if (headerLength > buffer.capacity()) {
+                               assert(false);
+                               return null;
+                       }
+                       
+                       long nextPosition = buffer.position() + headerLength;
+                               
+                       /* cie_id = */ readAddress(buffer, addressSize);
+                       
+                       byte version = buffer.get();
+                       String augmentation = readString(buffer);
+                       long codeAlignmentFactor = read_unsigned_leb128(buffer);
+                       long dataAlignmentFactor = read_signed_leb128(buffer);
+                       int returnAddressRegister = version < 3 ? buffer.get() & 0xff : (int) read_unsigned_leb128(buffer);
+                       
+       
+                       IStreamBuffer instructions = buffer.wrapSubsection(nextPosition - buffer.position());
+                       
+                       String producer = null;
+                       ICompileUnitScope cuScope = provider.getCompileUnitForAddress(framePC);
+                       if (cuScope instanceof DwarfCompileUnit)
+                               producer = ((DwarfCompileUnit) cuScope).getAttributeList().getAttributeValueAsString(DwarfConstants.DW_AT_producer);
+                       
+                       return new CommonInformationEntry(codeAlignmentFactor, dataAlignmentFactor, 
+                                       returnAddressRegister, version, instructions, addressSize, 
+                                       producer, augmentation);
+               }
+       }
+       
+       private void storeTypeByName(String name, IType type) {
+               if (name.length() == 0)
+                       return;
+
+               List<IType> typeList = provider.typesByName.get(name);
+               if (typeList == null) {
+                       typeList = new ArrayList<IType>();
+                       
+                       // for a template, remove extra spaces and composite type names (e.g., "class")
+                       if (name.indexOf('<') != -1) {
+                               while (name.contains("  ")) //$NON-NLS-1$
+                                       name = name.replaceAll("  ", " "); //$NON-NLS-1$ //$NON-NLS-2$
+                               name = name.replaceAll(", ", ","); //$NON-NLS-1$ //$NON-NLS-2$
+                               name = name.replaceAll("class ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                               name = name.replaceAll("struct ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                               name = name.replaceAll("union ", ""); //$NON-NLS-1$ //$NON-NLS-2$
+                       }
+                       provider.typesByName.put(name, typeList);
+               }
+               typeList.add(type);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfMessages.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfMessages.java
new file mode 100644 (file)
index 0000000..d372bca
--- /dev/null
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import org.eclipse.osgi.util.NLS;
+
+public class DwarfMessages extends NLS {
+       private static final String BUNDLE_NAME = "org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfMessages"; //$NON-NLS-1$
+
+       public static String DwarfDebugInfoProvider_FailedToReadCIE;
+
+       public static String DwarfDebugInfoProvider_DwarfProviderFor;
+
+       public static String DwarfDebugInfoProvider_NotParsingType1;
+       public static String DwarfDebugInfoProvider_NotParsingType2;
+
+       public static String DwarfDebugInfoProvider_CannotResolveCompUnit1;
+       public static String DwarfDebugInfoProvider_CannotResolveCompUnit2;
+
+       public static String DwarfDebugInfoProvider_UnhandledType;
+
+       public static String DwarfFrameRegisters_CannotReadRegister;
+
+       public static String DwarfFrameRegisters_CannotWriteRegister;
+
+       public static String DwarfFrameRegisters_ErrorCalculatingLocation;
+
+       public static String DwarfFrameRegisters_NoCommonInfoEntry;
+
+       public static String DwarfInfoReader_DumpFileOpenOrCreateFailed;
+       
+       public static String DwarfInfoReader_FrameIndicesReadFailed;
+       
+       public static String DwarfInfoReader_ParseDebugInfoSectionFailed1;
+       public static String DwarfInfoReader_ParseDebugInfoSectionFailed2;
+       
+       public static String DwarfInfoReader_ParseSectionSourceFilesFailed1;
+       public static String DwarfInfoReader_ParseSectionSourceFilesFailed2;
+       
+       public static String DwarfInfoReader_ParseTraceInfoSectionFailed1;
+       public static String DwarfInfoReader_ParseTraceInfoSectionFailed2;
+       
+       public static String DwarfInfoReader_RangeReadFailed;
+       
+       public static String DwarfInfoReader_ReadDebugInfo;
+       
+       public static String DwarfInfoReader_ReadingSymbolInfo;
+       
+       public static String DwarfInfoReader_ReadType;
+       
+       public static String DwarfInfoReader_SubprogramNameNotFound1;
+       public static String DwarfInfoReader_SubprogramNameNotFound2;
+       
+       public static String DwarfInfoReader_TraceAddressParse1;
+       public static String DwarfInfoReader_TraceAddressParse2;
+       
+       public static String DwarfInfoReader_TraceAddressesParseFor;
+       public static String DwarfInfoReader_TraceFinishedAddressesParse;
+       
+       public static String DwarfInfoReader_TraceAddressParseFor;
+       public static String DwarfInfoReader_TraceFinishedAddressParse;
+       
+       public static String DwarfInfoReader_TraceFinishedInitialParse;
+       
+       public static String DwarfInfoReader_TraceFinishedQuickParse;
+       
+       public static String DwarfInfoReader_TraceInitialParseFor;
+       
+       public static String DwarfInfoReader_TraceParseTypes1;
+       public static String DwarfInfoReader_TraceParseTypes2;
+       
+       public static String DwarfInfoReader_TraceQuickParse;
+       
+       public static String DwarfInfoReader_TraceScopeAddressParse1;
+       public static String DwarfInfoReader_TraceScopeAddressParse2;
+       
+       public static String DwarfInfoReader_TraceTypeParse1;
+       public static String DwarfInfoReader_TraceTypeParse2;
+
+       public static String UnknownVariableAddress;
+       public static String NotImplementedFormat;
+       public static String InternalErrorFormat;
+
+       public static String LocationExpression_BadStackSize;
+
+       public static String LocationExpression_DW_OP;
+
+       public static String LocationExpression_MultiRegisterVariable;
+
+       public static String LocationExpression_UnexpectedOperand;
+
+       static {
+               // initialize resource bundle
+               NLS.initializeMessages(BUNDLE_NAME, DwarfMessages.class);
+       }
+
+       private DwarfMessages() {
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfMessages.properties b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfMessages.properties
new file mode 100644 (file)
index 0000000..2fe9c42
--- /dev/null
@@ -0,0 +1,58 @@
+###############################################################################
+# Copyright (c) 2010 Nokia and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Nokia - Initial API and implementation
+###############################################################################
+UnknownVariableAddress=Unknown variable address
+NotImplementedFormat=Not implemented ({0}) 
+DwarfDebugInfoProvider_CannotResolveCompUnit1=Cannot resolve compilation unit header for type at 
+DwarfDebugInfoProvider_CannotResolveCompUnit2=\ in 
+DwarfDebugInfoProvider_DwarfProviderFor=DWARF debug info provider for 
+DwarfDebugInfoProvider_FailedToReadCIE=Failed to read CIE at 
+DwarfDebugInfoProvider_NotParsingType1=Cannot parse type at 
+DwarfDebugInfoProvider_NotParsingType2=\ in 
+DwarfDebugInfoProvider_UnhandledType=<<unhandled type>>
+DwarfFrameRegisters_CannotReadRegister=Cannot read register {0} at {1}
+DwarfFrameRegisters_CannotWriteRegister=Cannot write register {0} at {1}
+DwarfFrameRegisters_ErrorCalculatingLocation=Internal error calculating location
+DwarfFrameRegisters_NoCommonInfoEntry=No CIE for {0}
+DwarfInfoReader_DumpFileOpenOrCreateFailed=Failed to open or create the dump file: 
+DwarfInfoReader_FrameIndicesReadFailed=Failed to read frame indices
+DwarfInfoReader_ParseDebugInfoSectionFailed1=Failed to parse debug info from section 
+DwarfInfoReader_ParseDebugInfoSectionFailed2=\ in file 
+DwarfInfoReader_ParseSectionSourceFilesFailed1=Failed to parse source files from section 
+DwarfInfoReader_ParseSectionSourceFilesFailed2=\ in file 
+DwarfInfoReader_ParseTraceInfoSectionFailed1=Failed to parse type debug info from section 
+DwarfInfoReader_ParseTraceInfoSectionFailed2=\ in file 
+DwarfInfoReader_RangeReadFailed=Failed to read ranges
+DwarfInfoReader_ReadDebugInfo=Read Debug Info
+DwarfInfoReader_ReadingSymbolInfo=Reading Debug Symbol Information: 
+DwarfInfoReader_ReadType=Read type 
+DwarfInfoReader_SubprogramNameNotFound1=Name of subprogram at 
+DwarfInfoReader_SubprogramNameNotFound2=\ not found
+DwarfInfoReader_TraceAddressParse1=Address parse for 
+DwarfInfoReader_TraceAddressParse2=\ : 
+DwarfInfoReader_TraceAddressesParseFor=Addresses parse for 
+DwarfInfoReader_TraceFinishedAddressesParse=Finished addresses parse
+DwarfInfoReader_TraceAddressParseFor=Address parse for 
+DwarfInfoReader_TraceFinishedAddressParse=Finished address parse
+DwarfInfoReader_TraceFinishedInitialParse=Finished initial parse
+DwarfInfoReader_TraceFinishedQuickParse=Finished quick parse
+DwarfInfoReader_TraceInitialParseFor=Initial parse for 
+DwarfInfoReader_TraceParseTypes1=Parsing types for 
+DwarfInfoReader_TraceParseTypes2=\ @ 
+DwarfInfoReader_TraceQuickParse=Quick parse for 
+DwarfInfoReader_TraceScopeAddressParse1=Address parse of 
+DwarfInfoReader_TraceScopeAddressParse2=\ @ 
+DwarfInfoReader_TraceTypeParse1=Type parse of 
+DwarfInfoReader_TraceTypeParse2=\ : 
+InternalErrorFormat=Internal error ({0}) 
+LocationExpression_BadStackSize=Stack size not 1
+LocationExpression_DW_OP=DW_OP 
+LocationExpression_MultiRegisterVariable=multi-register variable
+LocationExpression_UnexpectedOperand=Unexpected DW_OP 
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfModuleScope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfModuleScope.java
new file mode 100644 (file)
index 0000000..737f4b4
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISection;
+import org.eclipse.cdt.debug.edc.internal.symbols.ModuleLineEntryProvider;
+import org.eclipse.cdt.debug.edc.internal.symbols.Scope;
+import org.eclipse.cdt.debug.edc.services.IFrameRegisterProvider;
+import org.eclipse.cdt.debug.edc.symbols.ICompileUnitScope;
+import org.eclipse.cdt.debug.edc.symbols.IEnumerator;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.IModuleLineEntryProvider;
+import org.eclipse.cdt.debug.edc.symbols.IModuleScope;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+import org.eclipse.cdt.utils.Addr32;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * This represents the high-level view of an executable module's symbolics.
+ */
+public class DwarfModuleScope extends Scope implements IModuleScope {
+
+       private final DwarfDebugInfoProvider provider;
+       private ModuleLineEntryProvider lineEntryMapper;
+
+       public DwarfModuleScope(DwarfDebugInfoProvider provider) {
+               super("", null, null, null);
+               this.provider = provider;
+               
+               if (provider == null) {
+                       lowAddress = Addr32.ZERO;
+                       highAddress = Addr32.ZERO;
+               } else {
+                       name = provider.getSymbolFile().lastSegment();
+                                       
+                       // for now, use the code sections' ranges
+                       lowAddress = Addr32.MAX;
+                       highAddress = Addr32.ZERO;
+                       for (ISection section : provider.getExecutableSymbolicsReader().getSections()) {
+                               if (section.getProperties().get(ISection.PROPERTY_NAME).equals(ISection.NAME_DATA)) {
+                                       if (section.getLinkAddress().compareTo(lowAddress) < 0)
+                                               lowAddress = section.getLinkAddress();
+                                       IAddress end = section.getLinkAddress().add(section.getSize());
+                                       if (end.compareTo(highAddress) > 0)
+                                               highAddress = end;
+                               }
+                       }
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IModuleScope#getSymbolFile()
+        */
+       public IPath getSymbolFile() {
+               return provider.getSymbolFile();
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IModuleScope#getCompileUnitForAddress(org.eclipse.cdt.core.IAddress)
+        */
+       public ICompileUnitScope getCompileUnitForAddress(IAddress linkAddress) {
+               if (provider != null)
+                       return provider.getCompileUnitForAddress(linkAddress);
+               else
+                       return null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IModuleScope#getCompileUnitForFile(org.eclipse.core.runtime.IPath)
+        */
+       public List<ICompileUnitScope> getCompileUnitsForFile(IPath filePath) {
+               if (provider != null)
+                       return provider.getCompileUnitsForFile(filePath);
+               else
+                       return Collections.emptyList();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IModuleScope#getFunctionsByName(java.lang.String)
+        */
+       public Collection<IFunctionScope> getFunctionsByName(String name) {
+               if (provider != null)
+                       return provider.getFunctionsByName(name);
+               else
+                       return Collections.emptyList();
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IModuleScope#getVariablesByName(java.lang.String)
+        */
+       public Collection<IVariable> getVariablesByName(String name, boolean globalsOnly) {
+               // at the module scope, the variables we want are global
+               if (provider != null) 
+                       return provider.getVariablesByName(name, globalsOnly);
+               else
+                       return Collections.emptyList();
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getScopeAtAddress(org.eclipse.cdt.core.IAddress)
+        */
+       @Override
+       public IScope getScopeAtAddress(IAddress linkAddress) {
+               ensureParsed();
+               return super.getScopeAtAddress(linkAddress);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getEnumerators()
+        */
+       @Override
+       public Collection<IEnumerator> getEnumerators() {
+               ensureParsed();
+               return super.getEnumerators();
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getChildren()
+        */
+       @Override
+       public Collection<IScope> getChildren() {
+               ensureParsed();
+               return super.getChildren();
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getVariables()
+        */
+       @Override
+       public Collection<IVariable> getVariables() {
+               ensureParsedForVariables();
+               return super.getVariables();
+       }
+       
+       private void ensureParsed() {
+               if (provider != null) 
+                       provider.ensureParsedInitially();               
+       }
+       
+       private void ensureParsedForVariables() {
+               if (provider != null) 
+                       provider.ensureParsedForVariables();            
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IModuleScope#getTypes()
+        */
+       public Collection<IType> getTypes() {
+               if (provider != null)
+                       return provider.getTypes();
+               else
+                       return Collections.emptyList();
+       }
+
+       /**
+        * Fixup ranges after a full-module address parse.
+        */
+       /*
+       public void fixupRanges() {
+               System.out.println("Fixing up ranges for " + getChildren().size() + " children");
+               
+               // fix up scope addresses in case compiler doesn't generate them.
+               for (IScope cu : getChildren()) {
+                       ((DwarfCompileUnit) cu).fixupRanges();
+               }
+
+               IAddress newLowAddress = new Addr64(BigInteger.valueOf(0xFFFFFFFFL));
+               IAddress newHighAddress = new Addr64(BigInteger.valueOf(0));
+
+               // now fix up the module scope
+               for (IScope cu : getChildren()) {
+                       if (cu.getLowAddress().compareTo(newLowAddress) < 0) {
+                               newLowAddress = cu.getLowAddress();
+                       }
+
+                       if (cu.getHighAddress().compareTo(newHighAddress) > 0) {
+                               newHighAddress = cu.getHighAddress();
+                       }
+               }
+
+               this.lowAddress = newLowAddress;
+               this.highAddress = newHighAddress;
+       }
+       */
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.IModuleScope#getModuleLineEntryProvider()
+        */
+       public IModuleLineEntryProvider getModuleLineEntryProvider() {
+               if (lineEntryMapper == null) {
+                       lineEntryMapper = new ModuleLineEntryProvider();
+
+                       // handle the currently parsed children 
+                       for (IScope scope : getChildren()) {
+                               if (scope instanceof ICompileUnitScope) {
+                                       lineEntryMapper.addCompileUnit((ICompileUnitScope) scope);
+                               }
+                       }
+               }
+               return lineEntryMapper;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#addChild(org.eclipse.cdt.debug.edc.internal.symbols.IScope)
+        */
+       @Override
+       public void addChild(IScope scope) {
+               super.addChild(scope);
+               
+               // initial module scope range is a guess
+               mergeScopeRange(scope);
+               
+               if (scope instanceof ICompileUnitScope && lineEntryMapper != null) {
+                       lineEntryMapper.addCompileUnit((ICompileUnitScope) scope);
+               }
+       }
+
+       /** 
+        * Update info when a compile unit has been fully parsed.
+        * @param scope
+        */
+       public void updateLineInfoForCU(ICompileUnitScope scope) {
+               // be sure the decl entries for inlined functions are detected
+               if (lineEntryMapper != null)
+                       lineEntryMapper.addCompileUnit(scope);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.symbols.IModuleScope#getFrameRegisterProvider()
+        */
+       public IFrameRegisterProvider getFrameRegisterProvider() {
+               if (provider != null)
+                       return provider.getFrameRegisterProvider();
+               else
+                       return null;
+       }
+       
+       /**
+        * Help garbage collection
+        */
+       public void dispose() {
+               lineEntryMapper = null;
+               super.dispose();
+       }
+}
+
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfVariable.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfVariable.java
new file mode 100644 (file)
index 0000000..c99be39
--- /dev/null
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.Variable;
+import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.core.runtime.IPath;
+
+public class DwarfVariable extends Variable {
+
+       public DwarfVariable(String name, IScope scope, ILocationProvider locationProvider, 
+                       IType type, boolean isDeclared, IPath definingFile) {
+               super(name, scope, null, locationProvider, isDeclared, definingFile);
+
+               this.type = type;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/EDCSymbolReader.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/EDCSymbolReader.java
new file mode 100644 (file)
index 0000000..7df0952
--- /dev/null
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.nio.ByteOrder;
+import java.util.Collection;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISection;
+import org.eclipse.cdt.debug.edc.internal.symbols.files.BaseExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.symbols.IDebugInfoProvider;
+import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSection;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.symbols.IModuleScope;
+import org.eclipse.cdt.debug.edc.symbols.ISymbol;
+import org.eclipse.cdt.debug.edc.symbols.IUnmangler;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * This class handles the high-level retrieval of symbolic information, using 
+ * {@link IDebugInfoProvider} and {@link IExecutableSymbolicsReader}.
+ */
+public class EDCSymbolReader implements IEDCSymbolReader {
+
+       private static final String[] NO_SOURCE_FILES = new String[0];
+
+       private static final IModuleScope EMPTY_MODULE_SCOPE = new DwarfModuleScope(null);
+       
+       private IDebugInfoProvider debugInfoProvider;
+       private IExecutableSymbolicsReader exeSymReader;
+
+       public EDCSymbolReader(IExecutableSymbolicsReader exeSymReader, IDebugInfoProvider debugInfoProvider) {
+               if (exeSymReader == null)
+                       throw new IllegalArgumentException();
+               
+               this.exeSymReader = exeSymReader;
+               this.debugInfoProvider = debugInfoProvider;
+               
+               // we expect these two files to be the same
+               if (debugInfoProvider != null)
+                       if (!debugInfoProvider.getSymbolFile().equals(exeSymReader.getSymbolFile()))
+                               throw new IllegalArgumentException();
+       }
+
+       public void shutDown() {
+               if (exeSymReader != null) {
+                       exeSymReader.dispose();
+                       exeSymReader = null;
+               }
+               if (debugInfoProvider != null) {
+                       debugInfoProvider.dispose();
+                       debugInfoProvider = null;
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.exe.IExecutableSymbolicsReader#dispose()
+        */
+       public void dispose() {
+               exeSymReader.dispose();
+       }
+       
+       public Collection<IExecutableSection> getExecutableSections() {
+               return exeSymReader.getExecutableSections();
+       }
+       
+       public IExecutableSection findExecutableSection(String sectionName) {
+               return exeSymReader.findExecutableSection(sectionName);
+       }
+       
+       public Collection<ISection> getSections() {
+               return exeSymReader.getSections();
+       }
+
+       public IAddress getBaseLinkAddress() {
+               return exeSymReader.getBaseLinkAddress();
+       }
+
+       public long getModificationDate() {
+               return exeSymReader.getModificationDate();
+       }
+       
+       public Collection<ISymbol> findSymbols(String name) {
+               return exeSymReader.findSymbols(name);
+       }
+
+       public Collection<ISymbol> findUnmangledSymbols(String name) {
+               return exeSymReader.findUnmangledSymbols(name);
+       }
+       
+       public Collection<ISymbol> getSymbols() {
+               return exeSymReader.getSymbols();
+       }
+
+       public ISymbol getSymbolAtAddress(IAddress linkAddress) {
+               return exeSymReader.getSymbolAtAddress(linkAddress);
+       }
+
+       public IPath getSymbolFile() {
+               return debugInfoProvider != null ? debugInfoProvider.getSymbolFile() :
+                       (exeSymReader != null ? exeSymReader.getSymbolFile() : null);
+       }
+
+       public ByteOrder getByteOrder() {
+               return exeSymReader.getByteOrder();
+       }
+       
+       public IModuleScope getModuleScope() {
+               if (debugInfoProvider != null)
+                       return debugInfoProvider.getModuleScope();
+               else
+                       return EMPTY_MODULE_SCOPE;
+       }
+
+       public String[] getSourceFiles() {
+               if (debugInfoProvider != null)
+               {
+                       final String[][] resultHolder = new String[1][];
+                       Job quickParseJob = new Job("Reading Debug Symbol Information: " + debugInfoProvider.getSymbolFile().toOSString()) {
+
+                               @Override
+                               protected IStatus run(IProgressMonitor monitor) {
+                                       String[] sourceFiles = getSourceFiles(monitor);
+                                       resultHolder[0] = sourceFiles;
+                                       return Status.OK_STATUS;
+                               }
+                       };
+                       
+                       try {
+                               quickParseJob.schedule();
+                               quickParseJob.join();
+                       } catch (InterruptedException e) {
+                               EDCDebugger.getMessageLogger().logError(null, e);
+                       }
+                       return resultHolder[0];
+               }
+               else
+                       return NO_SOURCE_FILES;
+       }
+
+       public String[] getSourceFiles(IProgressMonitor monitor) {
+               if (debugInfoProvider != null)
+                       return debugInfoProvider.getSourceFiles(monitor);
+               else
+                       return NO_SOURCE_FILES;
+       }
+
+       public boolean hasRecognizedDebugInformation() {
+               return debugInfoProvider != null;
+       }
+       
+       public IDebugInfoProvider getDebugInfoProvider() {
+               return debugInfoProvider;
+       }
+       
+       public IUnmangler getUnmangler() {
+               if (exeSymReader instanceof BaseExecutableSymbolicsReader)
+                       return ((BaseExecutableSymbolicsReader) exeSymReader).getUnmangler();
+               return null;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/LocationEntry.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/LocationEntry.java
new file mode 100644 (file)
index 0000000..685dd7c
--- /dev/null
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.util.Arrays;
+
+public class LocationEntry {
+
+       private final long highPC;
+       private final long lowPC;
+       private final byte[] bytes;
+
+       public LocationEntry(long lowPC, long highPC, byte[] bytes) {
+               this.lowPC = lowPC;
+               this.highPC = highPC;
+               this.bytes = bytes;
+       }
+
+       /** Get the link address for the exclusive high end of the range. */
+       public long getHighPC() {
+               return highPC;
+       }
+
+       /** Get the link address for the inclusive low end of the range. */
+       public long getLowPC() {
+               return lowPC;
+       }
+
+       public byte[] getBytes() {
+               return bytes;
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append("LocationEntry ["); //$NON-NLS-1$
+               if (bytes != null) {
+                       builder.append("bytes="); //$NON-NLS-1$
+                       builder.append(Arrays.toString(bytes));
+                       builder.append(", "); //$NON-NLS-1$
+               }
+               builder.append("highPC="); //$NON-NLS-1$
+               builder.append(highPC);
+               builder.append(", lowPC="); //$NON-NLS-1$
+               builder.append(lowPC);
+               builder.append("]"); //$NON-NLS-1$
+               return builder.toString();
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/LocationExpression.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/LocationExpression.java
new file mode 100644 (file)
index 0000000..0125fcc
--- /dev/null
@@ -0,0 +1,323 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.symbols.InvalidVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.MemoryVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.RegisterVariableLocation;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
+import org.eclipse.cdt.debug.edc.symbols.IRegisterVariableLocation;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+public class LocationExpression implements ILocationProvider {
+
+       protected final IStreamBuffer location;
+       protected final int addressSize;
+       protected final IScope scope;
+
+       public LocationExpression(IStreamBuffer location, int addressSize, IScope scope) {
+               this.location = location;
+               this.addressSize = addressSize;
+               this.scope = scope;
+       }
+
+       synchronized public IVariableLocation getLocation(EDCServicesTracker tracker, IFrameDMContext context, IAddress forLinkAddress, boolean isNonLocalConstVariable) {
+
+               if (location == null) {
+                       return null;
+               }
+               
+               // This is intentionally small.  No existing code that I've seen has more 
+               // than a sprinkling of operands, much less ones that push. 
+               IVariableLocation[] opStack = new IVariableLocation[8];
+               int opStackPtr = 0;
+                               
+               location.position(0);
+               
+               try {
+                       while (location.hasRemaining()) {
+                               byte opcodeB = location.get();
+                               int opcode = 0xFF & opcodeB;
+
+                               if (opcode >= DwarfConstants.DW_OP_lit0 && opcode <= DwarfConstants.DW_OP_lit31) {
+                                       opStack[opStackPtr++] = new MemoryVariableLocation(tracker, 
+                                                       context, 
+                                                       BigInteger.valueOf(opcode - DwarfConstants.DW_OP_lit0), true);
+                               }
+                               else if (opcode >= DwarfConstants.DW_OP_reg0 && opcode <= DwarfConstants.DW_OP_reg31) {
+                                       opStack[opStackPtr++] = new RegisterVariableLocation(tracker, context, null, (opcode - DwarfConstants.DW_OP_reg0));
+                               }
+                               else if (opcode >= DwarfConstants.DW_OP_breg0 && opcode <= DwarfConstants.DW_OP_breg31) {
+                                       RegisterVariableLocation loc = new RegisterVariableLocation(tracker, context, null, (opcode - DwarfConstants.DW_OP_breg0));
+                                       try {
+                                               BigInteger value = loc.readValue(addressSize);
+                                               
+                                               long offset = DwarfInfoReader.read_signed_leb128(location);
+                                               opStack[opStackPtr++] = new MemoryVariableLocation(tracker, context,
+                                                               value.add(BigInteger.valueOf(offset)), true);
+                                       } catch (CoreException e) {
+                                               return new InvalidVariableLocation(e.getMessage());
+                                       }
+                               } else {
+
+                                       switch (opcode) {
+                                       case DwarfConstants.DW_OP_nop:
+                                               // ignore
+                                               break;
+                                               
+                                       case DwarfConstants.DW_OP_addr: /* Constant address. */
+                                               long addrValue = DwarfInfoReader.readAddress(location, addressSize);
+                                               opStack[opStackPtr++] = new MemoryVariableLocation(tracker, context, 
+                                                               BigInteger.valueOf(addrValue), true, isNonLocalConstVariable);
+                                               break;
+
+                                       case DwarfConstants.DW_OP_deref: {
+                                               ensureStack(opStackPtr, 1);
+                                               try {
+                                                       BigInteger addr = opStack[opStackPtr - 1].readValue(addressSize);
+                                                       IVariableLocation loc = new MemoryVariableLocation(tracker, context,
+                                                                       addr, true, isNonLocalConstVariable);
+                                                       opStack[opStackPtr - 1] = loc;
+                                               } catch (CoreException e) {
+                                                       return new InvalidVariableLocation(e.getMessage());
+                                               }
+                                               break;
+                                       }
+
+                                       case DwarfConstants.DW_OP_plus_uconst: {
+                                               ensureStack(opStackPtr, 1);
+                                               long offset = DwarfInfoReader.read_unsigned_leb128(location);
+                                               opStack[opStackPtr-1] = opStack[opStackPtr-1].addOffset(offset);
+                                               break;
+                                       }
+                                       
+                                       case DwarfConstants.DW_OP_const1u: /*
+                                                                                                                * Unsigned 1-byte
+                                                                                                                * constant.
+                                                                                                                */
+                                       case DwarfConstants.DW_OP_const1s: /*
+                                                                                                                * Signed 1-byte
+                                                                                                                * constant.
+                                                                                                                */
+                                       case DwarfConstants.DW_OP_const2u: /*
+                                                                                                                * Unsigned 2-byte
+                                                                                                                * constant.
+                                                                                                                */
+                                       case DwarfConstants.DW_OP_const2s: /*
+                                                                                                                * Signed 2-byte
+                                                                                                                * constant.
+                                                                                                                */
+                                       case DwarfConstants.DW_OP_const4u: /*
+                                                                                                                * Unsigned 4-byte
+                                                                                                                * constant.
+                                                                                                                */
+                                       case DwarfConstants.DW_OP_const4s: /*
+                                                                                                                * Signed 4-byte
+                                                                                                                * constant.
+                                                                                                                */
+                                       case DwarfConstants.DW_OP_const8u: /*
+                                                                                                                * Unsigned 8-byte
+                                                                                                                * constant.
+                                                                                                                */
+                                       case DwarfConstants.DW_OP_const8s: /*
+                                                                                                                * Signed 8-byte
+                                                                                                                * constant.
+                                                                                                                */
+                                       case DwarfConstants.DW_OP_constu: /* Unsigned LEB128 constant. */
+                                       case DwarfConstants.DW_OP_consts: /* Signed LEB128 constant. */
+                                       case DwarfConstants.DW_OP_dup:
+                                       case DwarfConstants.DW_OP_drop:
+                                       case DwarfConstants.DW_OP_over:
+                                       case DwarfConstants.DW_OP_pick: /* 1-byte stack index. */
+                                       case DwarfConstants.DW_OP_swap:
+                                       case DwarfConstants.DW_OP_rot:
+                                       case DwarfConstants.DW_OP_xderef:
+                                       case DwarfConstants.DW_OP_abs:
+                                       case DwarfConstants.DW_OP_and:
+                                       case DwarfConstants.DW_OP_div:
+                                       case DwarfConstants.DW_OP_minus:
+                                       case DwarfConstants.DW_OP_mod:
+                                       case DwarfConstants.DW_OP_mul:
+                                       case DwarfConstants.DW_OP_neg:
+                                       case DwarfConstants.DW_OP_not:
+                                       case DwarfConstants.DW_OP_or:
+                                       case DwarfConstants.DW_OP_plus:
+                                       case DwarfConstants.DW_OP_shl:
+                                       case DwarfConstants.DW_OP_shr:
+                                       case DwarfConstants.DW_OP_shra:
+                                       case DwarfConstants.DW_OP_xor:
+                                       case DwarfConstants.DW_OP_bra: /* Signed 2-byte constant. */
+                                       case DwarfConstants.DW_OP_eq:
+                                       case DwarfConstants.DW_OP_ge:
+                                       case DwarfConstants.DW_OP_gt:
+                                       case DwarfConstants.DW_OP_le:
+                                       case DwarfConstants.DW_OP_lt:
+                                       case DwarfConstants.DW_OP_ne:
+                                       case DwarfConstants.DW_OP_skip: /* Signed 2-byte constant. */
+                                               return new InvalidVariableLocation(MessageFormat.format(
+                                                               DwarfMessages.NotImplementedFormat, DwarfMessages.LocationExpression_DW_OP + opcode));
+
+                                       case DwarfConstants.DW_OP_regx: /* Unsigned LEB128 register. */
+                                               long regNum = DwarfInfoReader.read_unsigned_leb128(location);
+                                               opStack[opStackPtr++] = new RegisterVariableLocation(tracker, context, null, ((int) regNum));
+                                               break;
+                                               
+                                       case DwarfConstants.DW_OP_fbreg: /* Signed LEB128 offset. */
+                                               long offset = DwarfInfoReader.read_signed_leb128(location);
+                                               
+                                               IFunctionScope functionScope = null;
+                                               functionScope = getFunctionScope(forLinkAddress);
+                                               
+                                               IVariableLocation framePtrLoc = functionScope.getFrameBaseLocation().getLocation(tracker,
+                                                               context, forLinkAddress, false);
+                                               if (framePtrLoc != null) {
+                                                       if (framePtrLoc instanceof InvalidVariableLocation)
+                                                               return framePtrLoc;
+
+                                                       // first resolve the frame base value and then add
+                                                       // the offset
+                                                       if (framePtrLoc instanceof IRegisterVariableLocation) {
+                                                               BigInteger frame = framePtrLoc.readValue(addressSize);
+                                                               
+                                                               opStack[opStackPtr++] = new MemoryVariableLocation(tracker, context, 
+                                                                               frame.add(BigInteger.valueOf(offset)), true);
+                                                       } else {
+                                                               opStack[opStackPtr++] = framePtrLoc.addOffset(offset);
+                                                       }
+                                               }
+                                               
+                                               break;
+
+                                       case DwarfConstants.DW_OP_piece: 
+                                               /*
+                                               * ULEB128 size of piece
+                                               * addressed.
+                                               * TODO: GCC emits this for long long (is a composition operator
+                                               * that combines values -- this may tax the IVariableLocation concept)
+                                               */
+                                               assert (false);
+                                               return new InvalidVariableLocation(MessageFormat.format(DwarfMessages.NotImplementedFormat,
+                                                               DwarfMessages.LocationExpression_MultiRegisterVariable));
+                                               
+                                       case DwarfConstants.DW_OP_bregx: /*
+                                                                                                        * ULEB128 register followed
+                                                                                                        * by SLEB128 off.
+                                                                                                        */
+                                       case DwarfConstants.DW_OP_deref_size: /*
+                                                                                                                * 1-byte size of data
+                                                                                                                * retrieved.
+                                                                                                                */
+                                       case DwarfConstants.DW_OP_xderef_size: /*
+                                                                                                                        * 1-byte size of
+                                                                                                                        * data retrieved.
+                                                                                                                        */
+                                       case DwarfConstants.DW_OP_push_object_address:
+                                       case DwarfConstants.DW_OP_call2:
+                                       case DwarfConstants.DW_OP_call4:
+                                       case DwarfConstants.DW_OP_call_ref:
+                                               assert (false);
+                                               return new InvalidVariableLocation(MessageFormat.format(DwarfMessages.NotImplementedFormat,
+                                                               DwarfMessages.LocationExpression_DW_OP + opcode));
+
+                                       default:
+                                               assert (false);
+                                               return new InvalidVariableLocation(MessageFormat.format(DwarfMessages.InternalErrorFormat,
+                                                               DwarfMessages.LocationExpression_UnexpectedOperand + opcode));
+                                       }
+
+                               }
+
+                       }
+               } catch (CoreException e) {
+                       return new InvalidVariableLocation(e.getMessage());
+               } catch (Exception e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+
+               if (opStackPtr != 1) {
+                       assert(false);
+                       return new InvalidVariableLocation(MessageFormat.format(DwarfMessages.InternalErrorFormat,
+                       DwarfMessages.LocationExpression_BadStackSize));
+               }
+                       
+               return opStack[0];
+       }
+
+       /**
+        */
+       private void ensureStack(int opStackPtr, int needed) throws CoreException {
+               if (opStackPtr < needed) {
+                       throw EDCDebugger.newCoreException(MessageFormat.format(
+                                       DwarfMessages.InternalErrorFormat,
+                                       MessageFormat.format("expected {0} stack operands but had {1}", needed, opStackPtr)));
+               }
+       }
+
+       /**
+        * @param forLinkAddress
+        * @param functionScope
+        * @return
+        * @throws CoreException
+        */
+       private IFunctionScope getFunctionScope(IAddress forLinkAddress) throws CoreException {
+               IFunctionScope functionScope = null;
+               
+               if (scope instanceof IFunctionScope) {
+                       functionScope = (IFunctionScope) scope;
+               } else {
+                       IScope parent = scope.getParent();
+                       while (parent != null && !(parent instanceof IFunctionScope)) {
+                               parent = parent.getParent();
+                       }
+
+                       if (parent == null) {
+                               throw EDCDebugger.newCoreException("No function scope for " + scope + " at " + forLinkAddress.toHexAddressString());
+                       } else {
+                               functionScope = (IFunctionScope) parent;
+                       }
+               }
+
+               // inlined functions may be nested
+               while (functionScope.getParent() instanceof IFunctionScope)
+                       functionScope = (IFunctionScope) functionScope.getParent();
+               return functionScope;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.ILocationProvider#isLocationKnown(org.eclipse.cdt.core.IAddress)
+        */
+       public boolean isLocationKnown(IAddress forLinkAddress) {
+               // a location expression has the lifetime of its scope
+               return true;
+       }
+       
+       public IScope getScope() {
+               return scope;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.ILocationProvider#lifetimeMustMatchScope()
+        */
+       public boolean lifetimeMustMatchScope() {
+               return true;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/LocationList.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/LocationList.java
new file mode 100644 (file)
index 0000000..2d6b121
--- /dev/null
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.nio.ByteOrder;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.MemoryStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.symbols.InvalidVariableLocation;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
+import org.eclipse.cdt.debug.edc.symbols.IModuleScope;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+
+public class LocationList implements ILocationProvider {
+
+       protected LocationEntry[] locationList;
+       protected int addressSize;
+       protected IScope scope;
+       protected ByteOrder byteOrder;
+
+       public LocationList(LocationEntry[] locationList, ByteOrder byteOrder, int addressSize, IScope scope) {
+               this.locationList = locationList;
+               this.byteOrder = byteOrder;
+               this.addressSize = addressSize;
+               this.scope = scope;
+       }
+
+       public LocationEntry[] getLocationEntries() {
+               return locationList;
+       }
+
+       public IVariableLocation getLocation(EDCServicesTracker tracker, IFrameDMContext context, IAddress forLinkAddress, boolean isNonLocalConstVariable) {
+               
+               if (locationList != null) {
+                       IScope searchScope = scope;
+                       do {
+                               // the scope may be an inlined function scope, whose frame base is only provided in a parent.
+                               IVariableLocation location = searchForLocation(tracker, context, forLinkAddress, searchScope);
+                               if (location != null) {
+                                       return location;
+                               }
+                               searchScope = searchScope.getParent();
+                       } while (!(searchScope instanceof IModuleScope));
+               }
+               
+               // variable may exist in the current scope, but not be live at the given
+               // address
+               return locationList != null ? new InvalidVariableLocation(DwarfMessages.UnknownVariableAddress) : null;
+       }
+
+       private IVariableLocation searchForLocation(EDCServicesTracker tracker,
+                       IFrameDMContext context, IAddress forLinkAddress,
+                       IScope scope) {
+               long address = forLinkAddress.getValue().longValue();
+               
+               // find the location entry for the given address
+               for (LocationEntry entry : locationList) {
+                       if (address >= entry.getLowPC() && address < entry.getHighPC()) {
+                               IStreamBuffer locationData = new MemoryStreamBuffer(entry.getBytes(), byteOrder);
+                               LocationExpression expression = new LocationExpression(locationData, addressSize, scope);
+                               return expression.getLocation(tracker, context, forLinkAddress, false);
+                       }
+               }
+               
+               return null;
+       }
+
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.ILocationProvider#isLocationKnown(org.eclipse.cdt.core.IAddress)
+        */
+       public boolean isLocationKnown(IAddress forLinkAddress) {
+               long address = forLinkAddress.getValue().longValue();
+               
+               for (LocationEntry entry : locationList) {
+                       if (address >= entry.getLowPC() && address < entry.getHighPC()) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.ILocationProvider#lifetimeMustMatchScope()
+        */
+       public boolean lifetimeMustMatchScope() {
+               return false;   // may or may not match
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/RangeList.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/RangeList.java
new file mode 100644 (file)
index 0000000..51f77c4
--- /dev/null
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.eclipse.cdt.debug.edc.symbols.IRangeList;
+
+/**
+ * This is a range of non-contiguous addresses 
+ */
+public class RangeList implements IRangeList {
+       /** consecutive start, end entries */
+       private List<Long> ranges = new ArrayList<Long>(); 
+       private long low = Long.MAX_VALUE, high = Long.MIN_VALUE;
+       
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return "[0x" + Long.toHexString(getLowAddress()) + " to 0x" + Long.toHexString(getHighAddress()) + ")";
+       }
+       
+       public void addRange(long start, long end) {
+               if (!ranges.isEmpty()) {
+                       if (ranges.get(ranges.size() - 1) == start) {
+                               ranges.set(ranges.size() - 1, end);
+                               if (end > high)
+                                       high = end;
+                               return;
+                       }
+               }
+               ranges.add(start);
+               ranges.add(end);
+               
+               // track these dynamically since the list is not guaranteed to be ordered
+               if (start < low)
+                       low = start;
+               if (end > high)
+                       high = end;
+       }
+       
+       public long getLowAddress() {
+               if (ranges.isEmpty())
+                       return 0;
+               else 
+                       return low;
+       }
+
+       public long getHighAddress() {
+               if (ranges.isEmpty())
+                       return 0;
+               else 
+                       return high;
+       }
+       
+       /** Get an iterator over the ranges.  Fetch two entries at a time,
+        * which describe a [start, end) range. */
+       public Iterator<Entry> iterator() {
+               return new Iterator<Entry>() {
+                       int index = 0;
+
+                       public boolean hasNext() {
+                               return index < ranges.size();
+                       }
+
+                       public Entry next() {
+                               if (index >= ranges.size())
+                                       throw new NoSuchElementException();
+                               index += 2;
+                               return new IRangeList.Entry(ranges.get(index - 2), ranges.get(index - 1));
+                       }
+
+                       public void remove() {
+                               // TODO Auto-generated method stub
+                               
+                       }
+                       
+               };
+       }
+
+       /**
+        * Fixup a range list by adding a new low range
+        * @param addr
+        */
+       public void addLowRange(long addr) {
+               if (low > addr) {
+                       low = addr;
+                       if (!ranges.isEmpty()) {
+                               ranges.set(0, low);
+                       }
+               }
+       }
+
+       /**
+        * Fixup a range list by adding a new high range
+        * @param addr
+        */
+       public void addHighRange(long addr) {
+               if (high < addr) {
+                       high = addr;
+                       if (!ranges.isEmpty()) {
+                               ranges.set(ranges.size() - 1, addr);
+                       }
+               }
+               
+       }
+       
+       /**
+        * Tell if an address is in a range.
+        * @param addr
+        */
+       public boolean isInRange(long addr) {
+               for (Entry entry : this) {
+                       if (entry.low >= addr && addr < entry.high)
+                               return true;
+               }
+               return false;
+       }
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/BufferedRandomReadAccessFile.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/BufferedRandomReadAccessFile.java
new file mode 100644 (file)
index 0000000..ae5d7d9
--- /dev/null
@@ -0,0 +1,388 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.elf;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.FileStreamBuffer;
+
+/**
+ * Buffering version of the {@link IRandomReadAccessFile} interface that uses the
+ * {@link IStreamBuffer} implementation.
+ */
+public class BufferedRandomReadAccessFile implements
+               IRandomReadAccessFile {
+
+       /** source file */
+       private RandomAccessFile file;
+       
+       /** endian-aware buffer */
+       private FileStreamBuffer buffer;
+       /** native Java (big endian) buffer */
+       private FileStreamBuffer bigEndianBuffer;
+
+       /** current basis pointer */
+       private long filePointer;
+
+       /**
+        * @param osString
+        * @throws IOException 
+        */
+       public BufferedRandomReadAccessFile(String file, boolean isle) throws IOException {
+               this.file = new RandomAccessFile(file, "r"); //$NON-NLS-1$
+               // for ELF-aware reading
+               this.buffer = new FileStreamBuffer(this.file,  isle ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
+               // for native DataInput APIs
+               this.bigEndianBuffer = new FileStreamBuffer(this.file, ByteOrder.BIG_ENDIAN);
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readFully(byte[])
+        */
+       public void readFully(byte[] b) throws IOException {
+               try {
+                       bigEndianBuffer.get(b);
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readFully(byte[], int, int)
+        */
+       public void readFully(byte[] b, int off, int len) throws IOException {
+               try {
+                       bigEndianBuffer.get(b, off, len);
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#skipBytes(int)
+        */
+       public int skipBytes(int n) throws IOException {
+               long cap = bigEndianBuffer.capacity();
+               long cur = bigEndianBuffer.position();
+               long pos = Math.min(cap, cur + n);
+               bigEndianBuffer.position(pos);
+               buffer.position(pos);
+               return (int) (pos - cur);
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readBoolean()
+        */
+       public boolean readBoolean() throws IOException {
+               try {
+                       return bigEndianBuffer.get() != 0;
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readByte()
+        */
+       public byte readByte() throws IOException {
+               try {
+                       return bigEndianBuffer.get();
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readUnsignedByte()
+        */
+       public int readUnsignedByte() throws IOException {
+               try {
+                       return bigEndianBuffer.get() & 0xff;
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readShort()
+        */
+       public short readShort() throws IOException {
+               try {
+                       return bigEndianBuffer.getShort();
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readUnsignedShort()
+        */
+       public int readUnsignedShort() throws IOException {
+               try {
+                       return bigEndianBuffer.getShort() & 0xffff;
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readChar()
+        */
+       public char readChar() throws IOException {
+               try {
+                       return bigEndianBuffer.getChar();
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readInt()
+        */
+       public int readInt() throws IOException {
+               try {
+                       return bigEndianBuffer.getInt();
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readLong()
+        */
+       public long readLong() throws IOException {
+               try {
+                       return bigEndianBuffer.getLong();
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readFloat()
+        */
+       public float readFloat() throws IOException {
+               try {
+                       return Float.intBitsToFloat(bigEndianBuffer.getInt());
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readDouble()
+        */
+       public double readDouble() throws IOException {
+               try {
+                       return Double.longBitsToDouble(bigEndianBuffer.getLong());
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readLine()
+        */
+       public String readLine() throws IOException {
+               try {
+                       StringBuilder sb = new StringBuilder();
+                       try {
+                               int b;
+                               while ((b = bigEndianBuffer.get()) != 0) {
+                                       sb.append((char) (b & 0xff));
+                               }
+                       } catch (BufferUnderflowException e) {
+                               if (sb.length() == 0)
+                                       return null;
+                       }
+                       return sb.toString();
+               } finally {
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.DataInput#readUTF()
+        */
+       public String readUTF() throws IOException {
+               try {
+                       short length = bigEndianBuffer.getShort();
+                       StringBuilder sb = new StringBuilder();
+                       while (length-- > 0) {
+                               // TODO
+                               int c = (bigEndianBuffer.get()) & 0xff;
+                               if (c >= 0x80)
+                                       assert false;
+                               sb.append(c);
+                       }
+                       return sb.toString();
+               } finally {             
+                       buffer.position(bigEndianBuffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see java.io.Closeable#close()
+        */
+       public void close() throws IOException {
+               file.close();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#setEndian(boolean)
+        */
+       public void setEndian(boolean le) {
+               buffer.setOrder(le ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
+               
+               // keep bigEndianBuffer the same
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#setFileOffset(long)
+        */
+       public void setFileOffset(long offset) throws IOException {
+               this.filePointer = offset;
+               try {
+                       buffer.position(offset);
+               } catch (IllegalArgumentException e) {
+                       throw (IOException) (new IOException().initCause(e));
+               } finally {
+                       bigEndianBuffer.position(offset);
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#getFilePointer()
+        */
+       public long getFilePointer() throws IOException {
+               return filePointer;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#seek(long)
+        */
+       public void seek(long pos) throws IOException {
+               try {
+                       buffer.position(pos + filePointer);
+               } catch (IllegalArgumentException e) {
+                       throw (IOException) (new IOException().initCause(e));
+               } finally {
+                       bigEndianBuffer.position(pos + filePointer);
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#readShortE()
+        */
+       public short readShortE() throws IOException {
+               try {
+                        return buffer.getShort();
+               } finally {
+                       bigEndianBuffer.position(buffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#readIntE()
+        */
+       public long readIntE() throws IOException {
+               try {
+                       return buffer.getInt();
+               } finally {
+                       bigEndianBuffer.position(buffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#readLongE()
+        */
+       public long readLongE() throws IOException {
+               try {
+                       return buffer.getLong();
+               } finally {
+                       bigEndianBuffer.position(buffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#readFullyE(byte[])
+        */
+       public void readFullyE(byte[] bytes) throws IOException {
+               try {
+                       buffer.get(bytes);
+                       if (buffer.getOrder() != ByteOrder.BIG_ENDIAN) {
+                               for(int i=0; i < (bytes.length / 2); i++)
+                               {
+                                       byte tmp = bytes[i];
+                                       bytes[i] = bytes[bytes.length - i -1];
+                                       bytes[bytes.length - i -1] = tmp; 
+                               }
+                       }
+               } finally {
+                       bigEndianBuffer.position(buffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#read(byte[], int, int)
+        */
+       public int read(byte[] b, int off, int len) throws IOException {
+               try {
+                       long max = bigEndianBuffer.capacity();
+                       int toRead = (int) Math.min(max - (off + len), len);
+                       buffer.get(b, off, toRead);
+                       return toRead;
+               } finally {
+                       bigEndianBuffer.position(buffer.position());
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#read(byte[])
+        */
+       public int read(byte[] b) throws IOException {
+               return read(b, 0, b.length);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#length()
+        */
+       public long length() throws IOException {
+               return buffer.capacity();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomReadAccessFile#createReadByteBuffer(long, long)
+        */
+       public ByteBuffer createReadByteBuffer(long offset, long size)
+                       throws IOException {
+               // we don't use this in EDC, so this is slower than wanted
+               // TODO
+               assert false;
+               try {
+                       byte[] contents = new byte[(int) size];
+                       long cur = buffer.position();
+                       buffer.position(offset);
+                       buffer.get(contents);
+                       buffer.position(cur);
+                       return ByteBuffer.wrap(contents);
+               } catch (IllegalArgumentException e) {
+                       throw (IOException) (new IOException().initCause(e));
+               }
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/ERandomAccessFile.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/ERandomAccessFile.java
new file mode 100644 (file)
index 0000000..d03dfd9
--- /dev/null
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.elf;
+
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel.MapMode;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.elf.IRandomReadAccessFile;
+
+/**
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ERandomAccessFile extends RandomAccessFile implements IRandomReadAccessFile {
+       private boolean isle;
+    private long    ptr_offset;
+    int val[] = new int[4];
+               
+       public ERandomAccessFile(String file, String mode) throws IOException {
+               super(file, mode);
+       }
+
+       public ERandomAccessFile(File file, String mode) throws IOException {
+               super(file, mode);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomAccessFile#setEndian(boolean)
+        */
+       public void setEndian(boolean le)
+       {
+               isle = le;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomAccessFile#readShortE()
+        */
+       public final short readShortE() throws IOException {
+               val[0] = read();
+               val[1] = read();
+               if ((val[0] | val[1]) < 0)
+                   throw new EOFException();
+               if ( isle ) {
+                       return (short)((val[1] << 8) + val[0]);
+               }
+               return (short)((val[0] << 8) + val[1]);
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomAccessFile#readIntE()
+        */
+       public final long readIntE() throws IOException
+       {
+               val[0] = read();
+               val[1] = read();
+               val[2] = read();
+               val[3] = read();
+               if ((val[0] | val[1] | val[2] | val[3]) < 0)
+                   throw new EOFException();
+               if ( isle ) {
+                       return ((val[3] << 24) + (val[2] << 16) + (val[1] << 8) + val[0]);
+               }
+               return ((val[0] << 24) + (val[1] << 16) + (val[2] << 8) + val[3]);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomAccessFile#readLongE()
+        */
+       public final long readLongE() throws IOException
+       {
+               byte [] bytes = new byte[8];
+               long result = 0;
+               super.readFully(bytes);
+               int shift = 0;          
+               if ( isle ) 
+                       for(int i=7; i >= 0; i-- )
+                       {
+                               shift = i*8;
+                               result += ( ((long)bytes[i]) << shift ) & ( 0xffL << shift );
+                       }
+           else
+                       for(int i=0; i <= 7; i++ )
+                       {
+                               shift = (7-i)*8;
+                               result += ( ((long)bytes[i]) << shift ) & ( 0xffL << shift );
+                       }
+               return result;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomAccessFile#readFullyE(byte[])
+        */
+       public final void readFullyE(byte [] bytes) throws IOException
+       {
+               super.readFully(bytes);
+               byte tmp = 0;
+               if( isle )
+                       for(int i=0; i < (bytes.length / 2); i++)
+                       {
+                               tmp = bytes[i];
+                               bytes[i] = bytes[bytes.length - i -1];
+                               bytes[bytes.length - i -1] = tmp; 
+                       }
+       }
+
+    /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomAccessFile#setFileOffset(long)
+        */
+    public void setFileOffset( long offset ) throws IOException {
+        ptr_offset = offset;
+        super.seek( offset );
+    }
+
+    /* (non-Javadoc)
+        * @see org.eclipse.cdt.utils.IRandomAccessFile#getFilePointer()
+        */
+    @Override
+       public long getFilePointer() throws IOException {
+        long ptr = super.getFilePointer();
+        ptr = ptr - ptr_offset;
+        return ptr;
+    }
+
+    @Override
+       public void seek( long pos ) throws IOException {
+        long real_pos = pos + ptr_offset;
+        super.seek( real_pos );
+    }
+    
+    /* (non-Javadoc)
+     * @see org.eclipse.cdt.utils.IRandomReadAccessFile#createByteBuffer(long, long)
+     */
+    public ByteBuffer createReadByteBuffer(long offset, long size) throws IOException {
+       return getChannel().map(MapMode.READ_ONLY, offset, size).load().asReadOnlyBuffer();
+    }
+}
+
+
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/Elf.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/Elf.java
new file mode 100644 (file)
index 0000000..88759f2
--- /dev/null
@@ -0,0 +1,1231 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2010 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - initial API and implementation
+ *     Markus Schorn (Wind River Systems)
+ *     Ed Swartz (Nokia) - temporary fork into EDC to adapt to IRandomReadAccessFile
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.elf;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.core.IAddressFactory;
+import org.eclipse.cdt.core.ISymbolReader;
+import org.eclipse.cdt.utils.Addr32;
+import org.eclipse.cdt.utils.Addr32Factory;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.cdt.utils.Addr64Factory;
+
+public class Elf {
+       public final static int ELF32_ADDR_SIZE = 4;
+       public final static int ELF32_OFF_SIZE = 4;
+       public final static int ELF64_ADDR_SIZE = 8;
+       public final static int ELF64_OFF_SIZE = 8;
+
+       protected IRandomReadAccessFile efile;
+
+       protected ELFhdr ehdr;
+       protected Section[] sections;
+       protected String file;
+       protected byte[] section_strtab;
+
+       private int syms = 0;
+       private Symbol[] symbols;
+       private Symbol[] symtab_symbols;
+       private Section symtab_sym;
+       private Symbol[] dynsym_symbols;
+       private Section dynsym_sym;
+       private boolean sections_mapped; // Have sections been mapped? Used to clean up properly in Elf.Dispose.
+
+       protected String EMPTY_STRING = ""; //$NON-NLS-1$
+
+       public class ELFhdr {
+
+               /* e_ident offsets */
+               public final static int EI_MAG0 = 0;
+               public final static int EI_MAG1 = 1;
+               public final static int EI_MAG2 = 2;
+               public final static int EI_MAG3 = 3;
+               public final static int EI_CLASS = 4;
+               public final static int EI_DATA = 5;
+               public final static int EI_VERSION = 6;
+               public final static int EI_PAD = 7;
+               public final static int EI_NDENT = 16;
+
+               /* e_ident[EI_CLASS] */
+               public final static int ELFCLASSNONE = 0;
+               public final static int ELFCLASS32 = 1;
+               public final static int ELFCLASS64 = 2;
+
+               /* e_ident[EI_DATA] */
+               public final static int ELFDATANONE = 0;
+               public final static int ELFDATA2LSB = 1;
+               public final static int ELFDATA2MSB = 2;
+
+               /* values of e_type */
+               public final static int ET_NONE = 0;
+               public final static int ET_REL = 1;
+               public final static int ET_EXEC = 2;
+               public final static int ET_DYN = 3;
+               public final static int ET_CORE = 4;
+               public final static int ET_LOPROC = 0xff00;
+               public final static int ET_HIPROC = 0xffff;
+
+               /* values of e_machine */
+               public final static int EM_NONE = 0;
+               public final static int EM_M32 = 1;
+               public final static int EM_SPARC = 2;
+               public final static int EM_386 = 3;
+               public final static int EM_68K = 4;
+               public final static int EM_88K = 5;
+               public final static int EM_486 = 6;
+               public final static int EM_860 = 7;
+               public final static int EM_MIPS = 8;
+               public final static int EM_MIPS_RS3_LE = 10;
+               public final static int EM_RS6000 = 11;
+               public final static int EM_PARISC = 15;
+               public final static int EM_nCUBE = 16;
+               public final static int EM_VPP550 = 17;
+               public final static int EM_SPARC32PLUS = 18;
+               public final static int EM_PPC = 20;
+               public final static int EM_PPC64 = 21;
+               public final static int EM_ARM = 40;
+               public final static int EM_SH = 42;
+               public final static int EM_SPARCV9 = 43;
+               public final static int EM_TRICORE = 44;
+               public final static int EM_H8_300 = 46;
+               public final static int EM_H8_300H = 47;
+               public final static int EM_IA_64 = 50;
+               public final static int EM_COLDFIRE = 52;
+               public final static int EM_STARCORE = 58;
+               public final static int EM_X86_64 = 62;         
+               public final static int EM_ST100 = 60;
+               
+               /** @since 5.2 */
+               public final static int EM_68HC08 = 71; /* Freescale MC68HC08 Microcontroller */
+               
+               public final static int EM_AVR = 83;
+               public final static int EM_FR30 = 84; /* Fujitsu FR30 */
+               public final static int EM_V850 = 87;
+               public final static int EM_M32R = 88;
+               public final static int EM_MN10300 = 89;
+               public final static int EM_MN10200 = 90;
+               public final static int EM_XTENSA = 94;
+               public final static int EM_MSP430 = 105;
+               public final static int EM_BLACKFIN = 106;
+               public final static int EM_EXCESS = 111;
+               public final static int EM_NIOSII = 113;
+               public final static int EM_C166 = 116;
+               public final static int EM_M16C = 117;
+               
+               /** @since 5.2 */
+               public final static int EM_RS08 = 132;   /* Freescale RS08 embedded processor */
+               
+               public final static int EM_MMDSP = 160;
+               public final static int EM_NIOS = 0xFEBB;
+               public final static int EM_CYGNUS_POWERPC = 0x9025;
+               public final static int EM_CYGNUS_M32R = 0x9041;
+               public final static int EM_CYGNUS_V850 = 0x9080;
+               public final static int EM_CYGNUS_MN10200 = 0xdead;
+               public final static int EM_CYGNUS_MN10300 = 0xbeef;
+               public final static int EM_CYGNUS_FR30 = 0x3330;
+               public final static int EM_XSTORMY16 = 0xad45;
+               public final static int EM_CYGNUS_FRV = 0x5441;
+               public final static int EM_IQ2000 = 0xFEBA;
+               public static final int EM_XILINX_MICROBLAZE = 0xbaab;
+               public static final int EM_SDMA = 0xcafe;
+               public static final int EM_CRADLE = 0x4d55; 
+                       
+               public byte e_ident[] = new byte[EI_NDENT];
+               public int e_type; /* file type (Elf32_Half) */
+               public int e_machine; /* machine type (Elf32_Half) */
+               public long e_version; /* version number (Elf32_Word) */
+               public IAddress e_entry; /* entry point (Elf32_Addr) */
+               public long e_phoff; /* Program hdr offset (Elf32_Off) */
+               public long e_shoff; /* Section hdr offset (Elf32_Off) */
+               public long e_flags; /* Processor flags (Elf32_Word) */
+               public short e_ehsize; /* sizeof ehdr (Elf32_Half) */
+               public short e_phentsize; /* Program header entry size (Elf32_Half) */
+               public short e_phnum; /* Number of program headers (Elf32_Half) */
+               public short e_shentsize; /* Section header entry size (Elf32_Half) */
+               public short e_shnum; /* Number of section headers (Elf32_Half) */
+               public short e_shstrndx; /* String table index (Elf32_Half) */
+
+               protected ELFhdr() throws IOException {
+                       efile.seek(0);
+                       efile.readFully(e_ident);
+                       if (e_ident[ELFhdr.EI_MAG0] != 0x7f || e_ident[ELFhdr.EI_MAG1] != 'E' || e_ident[ELFhdr.EI_MAG2] != 'L'
+                                       || e_ident[ELFhdr.EI_MAG3] != 'F')
+                               throw new IOException(CCorePlugin.getResourceString("Util.exception.notELF")); //$NON-NLS-1$
+                       efile.setEndian(e_ident[ELFhdr.EI_DATA] == ELFhdr.ELFDATA2LSB);
+                       e_type = efile.readShortE();
+                       e_machine = efile.readShortE();
+                       e_version = efile.readIntE();
+                       switch (e_ident[ELFhdr.EI_CLASS]) {
+                               case ELFhdr.ELFCLASS32 : {
+                                       byte[] addrArray = new byte[ELF32_ADDR_SIZE];
+                                       efile.readFullyE(addrArray);
+                                       e_entry = new Addr32(addrArray);
+                                       e_phoff = efile.readIntE();
+                                       e_shoff = efile.readIntE();
+                               }
+                                       break;
+                               case ELFhdr.ELFCLASS64 : {
+                                       byte[] addrArray = new byte[ELF64_ADDR_SIZE];
+                                       efile.readFullyE(addrArray);
+                                       e_entry = new Addr64(addrArray);
+                                       e_phoff = readUnsignedLong(efile);
+                                       e_shoff = readUnsignedLong(efile);
+                               }
+                                       break;
+                               case ELFhdr.ELFCLASSNONE :
+                               default :
+                                       throw new IOException("Unknown ELF class " + e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
+                       }
+                       e_flags = efile.readIntE();
+                       e_ehsize = efile.readShortE();
+                       e_phentsize = efile.readShortE();
+                       e_phnum = efile.readShortE();
+                       e_shentsize = efile.readShortE();
+                       e_shnum = efile.readShortE();
+                       e_shstrndx = efile.readShortE();
+               }
+
+               protected ELFhdr(byte[] bytes) throws IOException {
+                       if (bytes.length <= e_ident.length) {
+                               throw new EOFException(CCorePlugin.getResourceString("Util.exception.notELF")); //$NON-NLS-1$
+                       }
+                       System.arraycopy(bytes, 0, e_ident, 0, e_ident.length);
+                       if (e_ident[ELFhdr.EI_MAG0] != 0x7f || e_ident[ELFhdr.EI_MAG1] != 'E' || e_ident[ELFhdr.EI_MAG2] != 'L'
+                                       || e_ident[ELFhdr.EI_MAG3] != 'F')
+                               throw new IOException(CCorePlugin.getResourceString("Util.exception.notELF")); //$NON-NLS-1$
+                       boolean isle = (e_ident[ELFhdr.EI_DATA] == ELFhdr.ELFDATA2LSB);
+                       int offset = e_ident.length;
+                       e_type = makeShort(bytes, offset, isle);
+                       offset += 2;
+                       e_machine = makeShort(bytes, offset, isle);
+                       offset += 2;
+                       e_version = makeInt(bytes, offset, isle);
+                       offset += 4;
+                       switch (e_ident[ELFhdr.EI_CLASS]) {
+                               case ELFhdr.ELFCLASS32 : {
+                                       byte[] addrArray = new byte[ELF32_ADDR_SIZE];
+                                       System.arraycopy(bytes, offset, addrArray, 0, ELF32_ADDR_SIZE);
+                                       offset += ELF32_ADDR_SIZE;
+                                       e_entry = new Addr32(addrArray);
+                                       e_phoff = makeInt(bytes, offset, isle);
+                                       offset += ELF32_OFF_SIZE;
+                                       e_shoff = makeInt(bytes, offset, isle);
+                                       offset += ELF32_OFF_SIZE;
+                               }
+                                       break;
+                               case ELFhdr.ELFCLASS64 : {
+                                       byte[] addrArray = new byte[ELF64_ADDR_SIZE];
+                                       System.arraycopy(bytes, offset, addrArray, 0, ELF64_ADDR_SIZE);
+                                       offset += ELF64_ADDR_SIZE;
+                                       e_entry = new Addr64(addrArray);
+                                       e_phoff = makeUnsignedLong(bytes, offset, isle);
+                                       offset += ELF64_OFF_SIZE;
+                                       e_shoff = makeUnsignedLong(bytes, offset, isle);
+                                       offset += ELF64_OFF_SIZE;
+                               }
+                                       break;
+                               case ELFhdr.ELFCLASSNONE :
+                               default :
+                                       throw new IOException("Unknown ELF class " + e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
+                       }
+                       e_flags = makeInt(bytes, offset, isle);
+                       offset += 4;
+                       e_ehsize = makeShort(bytes, offset, isle);
+                       offset += 2;
+                       e_phentsize = makeShort(bytes, offset, isle);
+                       offset += 2;
+                       e_phnum = makeShort(bytes, offset, isle);
+                       offset += 2;
+                       e_shentsize = makeShort(bytes, offset, isle);
+                       offset += 2;
+                       e_shnum = makeShort(bytes, offset, isle);
+                       offset += 2;
+                       e_shstrndx = makeShort(bytes, offset, isle);
+                       offset += 2;
+               }
+
+               private final short makeShort(byte[] val, int offset, boolean isle) throws IOException {
+                       if (val.length < offset + 2)
+                               throw new IOException();
+                       if (isle) {
+                               return (short) ( (val[offset + 1] << 8) + val[offset + 0]);
+                       }
+                       return (short) ( (val[offset + 0] << 8) + val[offset + 1]);
+               }
+
+               private final long makeInt(byte[] val, int offset, boolean isle) throws IOException {
+                       if (val.length < offset + 4)
+                               throw new IOException();
+                       if (isle) {
+                               return ( (val[offset + 3] << 24) + (val[offset + 2] << 16) + (val[offset + 1] << 8) + val[offset + 0]);
+                       }
+                       return ( (val[offset + 0] << 24) + (val[offset + 1] << 16) + (val[offset + 2] << 8) + val[offset + 3]);
+               }
+
+               private final long makeLong(byte[] val, int offset, boolean isle) throws IOException {
+                       long result = 0;
+                       int shift = 0;
+                       if (isle)
+                               for (int i = 7; i >= 0; i--) {
+                                       shift = i * 8;
+                                       result += ( ((long)val[offset + i]) << shift) & (0xffL << shift);
+                               }
+                       else
+                               for (int i = 0; i <= 7; i++) {
+                                       shift = (7 - i) * 8;
+                                       result += ( ((long)val[offset + i]) << shift) & (0xffL << shift);
+                               }
+                       return result;
+               }
+
+               private final long makeUnsignedLong(byte[] val, int offset, boolean isle) throws IOException {
+                       long result = makeLong(val, offset, isle);
+                       if (result < 0) {
+                               throw new IOException("Maximal file offset is " + Long.toHexString(Long.MAX_VALUE) + //$NON-NLS-1$
+                                               " given offset is " + Long.toHexString(result)); //$NON-NLS-1$
+                       }
+                       return result;
+
+               }
+
+       }
+
+       public class Section {
+
+               /* sh_type */
+               public final static int SHT_NULL = 0;
+               public final static int SHT_PROGBITS = 1;
+               public final static int SHT_SYMTAB = 2;
+               public final static int SHT_STRTAB = 3;
+               public final static int SHT_RELA = 4;
+               public final static int SHT_HASH = 5;
+               public final static int SHT_DYNAMIC = 6;
+               public final static int SHT_NOTE = 7;
+               public final static int SHT_NOBITS = 8;
+               public final static int SHT_REL = 9;
+               public final static int SHT_SHLIB = 10;
+               public final static int SHT_DYNSYM = 11;
+
+               public final static int SHT_LOPROC = 0x70000000;
+
+               /* sh_flags */
+               public final static int SHF_WRITE = 1;
+               public final static int SHF_ALLOC = 2;
+               public final static int SHF_EXECINTR = 4;
+
+               public long sh_name;
+               public long sh_type;
+               public long sh_flags;
+               public IAddress sh_addr;
+               public long sh_offset;
+               public long sh_size;
+               public long sh_link;
+               public long sh_info;
+               public long sh_addralign;
+               public long sh_entsize;
+
+               /**
+                * @since 5.1
+                */
+               public ByteBuffer mapSectionData() throws IOException {
+                       sections_mapped = true;
+                       return efile.createReadByteBuffer(sh_offset, sh_size);
+               }
+
+               public byte[] loadSectionData() throws IOException {
+                       byte[] data = new byte[(int)sh_size];
+                       efile.seek(sh_offset);
+                       efile.read(data);
+                       return data;
+               }
+
+               @Override
+               public String toString() {
+                       try {
+                               if (section_strtab == null) {
+                                       final int shstrndx= ehdr.e_shstrndx & 0xffff; // unsigned short
+                                       if (shstrndx > sections.length || shstrndx < 0)
+                                               return EMPTY_STRING;
+                                       int size = (int)sections[shstrndx].sh_size;
+                                       if (size <= 0 || size > efile.length())
+                                               return EMPTY_STRING;
+                                       section_strtab = new byte[size];
+                                       efile.seek(sections[shstrndx].sh_offset);
+                                       efile.read(section_strtab);
+                               }
+                               int str_size = 0;
+                               if (sh_name > section_strtab.length) {
+                                       return EMPTY_STRING;
+                               }
+                               while (section_strtab[(int)sh_name + str_size] != 0)
+                                       str_size++;
+                               return new String(section_strtab, (int)sh_name, str_size);
+                       } catch (IOException e) {
+                               return EMPTY_STRING;
+                       }
+               }
+       }
+
+       protected String string_from_elf_section(Elf.Section section, int index) throws IOException {
+               if (index > section.sh_size) {
+                       return EMPTY_STRING;
+               }
+               
+               StringBuffer str = new StringBuffer();
+               //Most string symbols will be less than 50 bytes in size
+               byte [] tmp = new byte[50];             
+               
+               efile.seek(section.sh_offset + index);
+               while(true) {
+                       int len = efile.read(tmp);
+                       for(int i = 0; i < len; i++) {
+                               if(tmp[i] == 0) {
+                                       len = 0;
+                                       break;
+                               }
+                               str.append((char)tmp[i]);
+                       }                       
+                       if(len <= 0) {
+                               break;
+                       }
+               }
+
+               return str.toString();
+       }
+
+       public class Symbol implements Comparable<Object> {
+
+               /* Symbol bindings */
+               public final static int STB_LOCAL = 0;
+               public final static int STB_GLOBAL = 1;
+               public final static int STB_WEAK = 2;
+               /* Symbol type */
+               public final static int STT_NOTYPE = 0;
+               public final static int STT_OBJECT = 1;
+               public final static int STT_FUNC = 2;
+               public final static int STT_SECTION = 3;
+               public final static int STT_FILE = 4;
+               /* Special Indexes */
+               public final static int SHN_UNDEF = 0;
+               public final static int SHN_LORESERVE = 0xffffff00;
+               public final static int SHN_LOPROC = 0xffffff00;
+               public final static int SHN_HIPROC = 0xffffff1f;
+               public final static int SHN_LOOS = 0xffffff20;
+               public final static int SHN_HIOS = 0xffffff3f;
+               public final static int SHN_ABS = 0xfffffff1;
+               public final static int SHN_COMMON = 0xfffffff2;
+               public final static int SHN_XINDEX = 0xffffffff;
+               public final static int SHN_HIRESERVE = 0xffffffff;
+
+               /* NOTE: 64 bit and 32 bit ELF sections has different order */
+               public long st_name;
+               public IAddress st_value;
+               public long st_size;
+               public short st_info;
+               public short st_other;
+               public short st_shndx;
+
+               private String name = null;
+
+               private final Section sym_section;
+
+               public Symbol(Section section) {
+                       sym_section = section;
+               }
+
+               public int st_type() {
+                       return st_info & 0xf;
+               }
+
+               public int st_bind() {
+                       return (st_info >> 4) & 0xf;
+               }
+
+               public int compareTo(Object obj) {
+                       /*
+                        * long thisVal = 0; long anotherVal = 0; if ( obj instanceof Symbol ) {
+                        * Symbol sym = (Symbol)obj; thisVal = this.st_value; anotherVal =
+                        * sym.st_value; } else if ( obj instanceof Long ) { Long val =
+                        * (Long)obj; anotherVal = val.longValue(); thisVal = this.st_value; }
+                        * return (thisVal <anotherVal ? -1 : (thisVal==anotherVal ? 0 :
+                        * 1));
+                        */
+                       return this.st_value.compareTo( ((Symbol)obj).st_value);
+               }
+
+               @Override
+               public String toString() {
+                       if (name == null) {
+                               try {
+                                       Section sections[] = getSections();
+                                       Section symstr = sections[(int)sym_section.sh_link];
+                                       name = string_from_elf_section(symstr, (int)st_name);
+                               } catch (IOException e) {
+                                       return EMPTY_STRING;
+                               }
+                       }
+                       return name;
+               }
+
+       }
+
+       /**
+        * We have to implement a separate compararator since when we do the binary
+        * search down below we are using a Long and a Symbol object and the Long
+        * doesn't know how to compare against a Symbol so if we compare Symbol vs
+        * Long it is ok, but not if we do Long vs Symbol.
+        */
+
+       class SymbolComparator implements Comparator<Object> {
+
+               IAddress val1, val2;
+               public int compare(Object o1, Object o2) {
+
+                       if (o1 instanceof IAddress) {
+                               val1 = (IAddress)o1;
+                       } else if (o1 instanceof Symbol) {
+                               val1 = ((Symbol)o1).st_value;
+                       } else {
+                               return -1;
+                       }
+
+                       if (o2 instanceof IAddress) {
+                               val2 = (IAddress)o2;
+                       } else if (o2 instanceof Symbol) {
+                               val2 = ((Symbol)o2).st_value;
+                       } else {
+                               return -1;
+                       }
+                       return val1.compareTo(val2);
+               }
+       }
+
+       public class PHdr {
+
+               public final static int PT_NULL = 0;
+               public final static int PT_LOAD = 1;
+               public final static int PT_DYNAMIC = 2;
+               public final static int PT_INTERP = 3;
+               public final static int PT_NOTE = 4;
+               public final static int PT_SHLIB = 5;
+               public final static int PT_PHDR = 6;
+
+               public final static int PF_X = 1;
+               public final static int PF_W = 2;
+               public final static int PF_R = 4;
+               /* NOTE: 64 bit and 32 bit ELF have different order and size of elements */
+               public long p_type;
+               public long p_offset;
+               public IAddress p_vaddr;
+               public IAddress p_paddr;
+               public long p_filesz;
+               public long p_memsz;
+               public long p_flags;
+               public long p_align;
+       }
+
+       public PHdr[] getPHdrs() throws IOException {
+               if (ehdr.e_phnum == 0) {
+                       return new PHdr[0];
+               }
+               efile.seek(ehdr.e_phoff);
+               final int length= ehdr.e_phnum & 0xffff; // interpret as unsigned short
+               PHdr phdrs[] = new PHdr[length];
+               for (int i = 0; i < length; i++) {
+                       phdrs[i] = new PHdr();
+                       switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
+                               case ELFhdr.ELFCLASS32 : {
+                                       byte[] addrArray = new byte[ELF32_ADDR_SIZE];
+
+                                       phdrs[i].p_type = efile.readIntE();
+                                       phdrs[i].p_offset = efile.readIntE();
+                                       efile.readFullyE(addrArray);
+                                       phdrs[i].p_vaddr = new Addr32(addrArray);
+                                       efile.readFullyE(addrArray);
+                                       phdrs[i].p_paddr = new Addr32(addrArray);
+                                       phdrs[i].p_filesz = efile.readIntE();
+                                       phdrs[i].p_memsz = efile.readIntE();
+                                       phdrs[i].p_flags = efile.readIntE();
+                                       phdrs[i].p_align = efile.readIntE();
+                               }
+                                       break;
+                               case ELFhdr.ELFCLASS64 : {
+                                       byte[] addrArray = new byte[ELF64_ADDR_SIZE];
+
+                                       phdrs[i].p_type = efile.readIntE();
+                                       phdrs[i].p_flags = efile.readIntE();
+                                       phdrs[i].p_offset = readUnsignedLong(efile);
+                                       efile.readFullyE(addrArray);
+                                       phdrs[i].p_vaddr = new Addr64(addrArray);
+                                       efile.readFullyE(addrArray);
+                                       phdrs[i].p_paddr = new Addr64(addrArray);
+                                       phdrs[i].p_filesz = readUnsignedLong(efile);
+                                       phdrs[i].p_memsz = readUnsignedLong(efile);
+                                       phdrs[i].p_align = readUnsignedLong(efile);
+                               }
+                                       break;
+                               case ELFhdr.ELFCLASSNONE :
+                               default :
+                                       throw new IOException("Unknown ELF class " + ehdr.e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
+                       }
+
+               }
+               return phdrs;
+       }
+
+       public class Dynamic {
+
+               public final static int DYN_ENT_SIZE_32 = 8;
+               public final static int DYN_ENT_SIZE_64 = 16;
+
+               public final static int DT_NULL = 0;
+               public final static int DT_NEEDED = 1;
+               public final static int DT_PLTRELSZ = 2;
+               public final static int DT_PLTGOT = 3;
+               public final static int DT_HASH = 4;
+               public final static int DT_STRTAB = 5;
+               public final static int DT_SYMTAB = 6;
+               public final static int DT_RELA = 7;
+               public final static int DT_RELASZ = 8;
+               public final static int DT_RELAENT = 9;
+               public final static int DT_STRSZ = 10;
+               public final static int DT_SYMENT = 11;
+               public final static int DT_INIT = 12;
+               public final static int DT_FINI = 13;
+               public final static int DT_SONAME = 14;
+               public final static int DT_RPATH = 15;
+               public long d_tag;
+               public long d_val;
+               private final Section section;
+               private String name;
+
+               protected Dynamic(Section section) {
+                       this.section = section;
+               }
+
+               @Override
+               public String toString() {
+                       if (name == null) {
+                               switch ((int)d_tag) {
+                                       case DT_NEEDED :
+                                       case DT_SONAME :
+                                       case DT_RPATH :
+                                               try {
+                                                       Section symstr = sections[(int)section.sh_link];
+                                                       name = string_from_elf_section(symstr, (int)d_val);
+                                               } catch (IOException e) {
+                                                       name = EMPTY_STRING;
+                                               }
+                                               break;
+                                       default :
+                                               name = EMPTY_STRING;
+                               }
+                       }
+                       return name;
+               }
+       }
+
+       public Dynamic[] getDynamicSections(Section section) throws IOException {
+               if (section.sh_type != Section.SHT_DYNAMIC) {
+                       return new Dynamic[0];
+               }
+               ArrayList<Dynamic> dynList = new ArrayList<Dynamic>();
+               efile.seek(section.sh_offset);
+               int off = 0;
+               // We must assume the section is a table ignoring the sh_entsize as it
+               // is not
+               // set for MIPS.
+               while (off < section.sh_size) {
+                       Dynamic dynEnt = new Dynamic(section);
+                       switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
+                               case ELFhdr.ELFCLASS32 : {
+                                       dynEnt.d_tag = efile.readIntE();
+                                       dynEnt.d_val = efile.readIntE();
+                                       off += Dynamic.DYN_ENT_SIZE_32;
+                               }
+                                       break;
+                               case ELFhdr.ELFCLASS64 : {
+                                       dynEnt.d_tag = efile.readLongE();
+                                       dynEnt.d_val = efile.readLongE();
+                                       off += Dynamic.DYN_ENT_SIZE_64;
+                               }
+                                       break;
+                               case ELFhdr.ELFCLASSNONE :
+                               default :
+                                       throw new IOException("Unknown ELF class " + ehdr.e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
+                       }
+
+                       if (dynEnt.d_tag != Dynamic.DT_NULL)
+                               dynList.add(dynEnt);
+               }
+               return dynList.toArray(new Dynamic[0]);
+       }
+
+       private void commonSetup(IRandomReadAccessFile rraFile, String file, long offset) throws IOException {
+               try {
+                       efile = rraFile;
+                       efile.seek(offset);
+                       ehdr = new ELFhdr();
+                       this.file = file;
+               } finally {
+                       if (ehdr == null) {
+                               dispose();
+                       }
+               }
+       }
+
+       //A hollow entry, to be used with caution in controlled situations
+       protected Elf() {
+       }
+
+       public Elf(String file, long offset) throws IOException {
+               commonSetup(new ERandomAccessFile(file, "r"), file, offset); //$NON-NLS-1$
+       }
+
+       public Elf(String file) throws IOException {
+               commonSetup(new ERandomAccessFile(file, "r"), file, 0); //$NON-NLS-1$
+       }
+
+       public Elf(IRandomReadAccessFile rraFile, String file, long offset) throws IOException {
+               commonSetup(rraFile, file, offset);
+       }
+       
+       public ELFhdr getELFhdr() throws IOException {
+               return ehdr;
+       }
+
+       public class Attribute {
+
+               public static final int ELF_TYPE_EXE = 1;
+               public static final int ELF_TYPE_SHLIB = 2;
+               public static final int ELF_TYPE_OBJ = 3;
+               public static final int ELF_TYPE_CORE = 4;
+
+               public static final int DEBUG_TYPE_NONE = 0;
+               public static final int DEBUG_TYPE_STABS = 1;
+               public static final int DEBUG_TYPE_DWARF = 2;
+
+               String cpu;
+               int type;
+               int debugType;
+               boolean bDebug;
+               boolean isle;
+               IAddressFactory addressFactory;
+
+               public String getCPU() {
+                       return cpu;
+               }
+
+               public int getType() {
+                       return type;
+               }
+
+               public boolean hasDebug() {
+                       return debugType != DEBUG_TYPE_NONE;
+               }
+
+               public int getDebugType() {
+                       return debugType;
+               }
+
+               public boolean isLittleEndian() {
+                       return isle;
+               }
+
+               public IAddressFactory getAddressFactory() {
+                       return addressFactory;
+               }
+       }
+
+       public Attribute getAttributes() throws IOException {
+               Attribute attrib = new Attribute();
+
+               switch (ehdr.e_type) {
+                       case Elf.ELFhdr.ET_CORE :
+                               attrib.type = Attribute.ELF_TYPE_CORE;
+                               break;
+                       case Elf.ELFhdr.ET_EXEC :
+                               attrib.type = Attribute.ELF_TYPE_EXE;
+                               break;
+                       case Elf.ELFhdr.ET_REL :
+                               attrib.type = Attribute.ELF_TYPE_OBJ;
+                               break;
+                       case Elf.ELFhdr.ET_DYN :
+                               attrib.type = Attribute.ELF_TYPE_SHLIB;
+                               break;
+               }
+
+               switch (ehdr.e_machine & 0xFFFF) {
+                       case Elf.ELFhdr.EM_386 :
+                       case Elf.ELFhdr.EM_486 :
+                               attrib.cpu = "x86"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_68K :
+                               attrib.cpu = "m68k"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_PPC :
+                       case Elf.ELFhdr.EM_CYGNUS_POWERPC :
+                       case Elf.ELFhdr.EM_RS6000 :
+                               attrib.cpu = "ppc"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_PPC64 :
+                               attrib.cpu = "ppc64"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_SH :
+                               attrib.cpu = "sh"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_ARM :
+                               attrib.cpu = "arm"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_MIPS_RS3_LE :
+                       case Elf.ELFhdr.EM_MIPS :
+                               attrib.cpu = "mips"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_SPARC32PLUS :
+                       case Elf.ELFhdr.EM_SPARC :
+                       case Elf.ELFhdr.EM_SPARCV9 :
+                               attrib.cpu = "sparc"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_H8_300 :
+                       case Elf.ELFhdr.EM_H8_300H :
+                               attrib.cpu = "h8300"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_V850 :
+                       case Elf.ELFhdr.EM_CYGNUS_V850 :
+                               attrib.cpu = "v850"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_MN10300 :
+                       case Elf.ELFhdr.EM_CYGNUS_MN10300 :
+                               attrib.cpu = "mn10300"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_MN10200 :
+                       case Elf.ELFhdr.EM_CYGNUS_MN10200 :
+                               attrib.cpu = "mn10200"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_M32R :
+                               attrib.cpu = "m32r"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_FR30 :
+                       case Elf.ELFhdr.EM_CYGNUS_FR30 :
+                               attrib.cpu = "fr30"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_XSTORMY16 :
+                               attrib.cpu = "xstormy16"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_CYGNUS_FRV :
+                               attrib.cpu = "frv"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_IQ2000 :
+                               attrib.cpu = "iq2000"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_EXCESS :
+                               attrib.cpu = "excess"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_NIOSII :
+                               attrib.cpu = "alteranios2"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_NIOS :
+                               attrib.cpu = "alteranios"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_IA_64 :
+                               attrib.cpu = "ia64"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_COLDFIRE:
+                               attrib.cpu = "coldfire"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_AVR :
+                               attrib.cpu = "avr"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_MSP430 :
+                               attrib.cpu = "msp430"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_XTENSA:
+                               attrib.cpu = "xtensa"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_ST100:
+                               attrib.cpu = "st100"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_X86_64:
+                               attrib.cpu = "x86_64"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_XILINX_MICROBLAZE:
+                               attrib.cpu = "microblaze"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_C166:
+                               attrib.cpu = "c166"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_TRICORE:
+                               attrib.cpu = "TriCore"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_M16C:
+                               attrib.cpu = "M16C"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_STARCORE:
+                               attrib.cpu = "StarCore"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_BLACKFIN :
+                               attrib.cpu = "bfin"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_SDMA:
+                               attrib.cpu = "sdma"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_CRADLE:
+                               attrib.cpu = "cradle"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_MMDSP:
+                               attrib.cpu = "mmdsp"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_68HC08:
+                               attrib.cpu = "hc08"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_RS08:
+                               attrib.cpu = "rs08"; //$NON-NLS-1$
+                               break;
+                       case Elf.ELFhdr.EM_NONE :
+                       default :
+                               attrib.cpu = "none"; //$NON-NLS-1$
+               }
+               switch (ehdr.e_ident[Elf.ELFhdr.EI_DATA]) {
+                       case Elf.ELFhdr.ELFDATA2LSB :
+                               attrib.isle = true;
+                               break;
+                       case Elf.ELFhdr.ELFDATA2MSB :
+                               attrib.isle = false;
+                               break;
+               }
+               switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
+                       case ELFhdr.ELFCLASS32 :
+                               attrib.addressFactory = new Addr32Factory();
+                               break;
+                       case ELFhdr.ELFCLASS64 :
+                               attrib.addressFactory = new Addr64Factory();
+                               break;
+                       case ELFhdr.ELFCLASSNONE :
+                       default :
+                               attrib.addressFactory = null;
+               }
+               // getSections
+               // find .debug using toString
+               Section[] sec = getSections();
+               if (sec != null) {
+                       for (int i = 0; i < sec.length; i++) {
+                               String s = sec[i].toString();
+                               if (s.startsWith(".debug")) { //$NON-NLS-1$
+                                       attrib.debugType = Attribute.DEBUG_TYPE_DWARF;
+                                       break;
+                               } else if (s.equals(".stab")) { //$NON-NLS-1$
+                                       attrib.debugType = Attribute.DEBUG_TYPE_STABS;
+                                       break;
+                               }
+                       }
+               }
+               return attrib;
+       }
+
+       public static Attribute getAttributes(String file) throws IOException {
+               Elf elf = new Elf(file);
+               Attribute attrib = elf.getAttributes();
+               elf.dispose();
+               return attrib;
+       }
+
+       public static Attribute getAttributes(byte[] array) throws IOException {
+
+               Elf emptyElf = new Elf();
+               emptyElf.ehdr = emptyElf.new ELFhdr(array);
+               emptyElf.sections = new Elf.Section[0];
+               Attribute attrib = emptyElf.getAttributes();
+               emptyElf.dispose();
+
+               return attrib;
+       }
+
+       public static boolean isElfHeader(byte[] e_ident) {
+               if (e_ident.length < 4 || e_ident[ELFhdr.EI_MAG0] != 0x7f || e_ident[ELFhdr.EI_MAG1] != 'E'
+                               || e_ident[ELFhdr.EI_MAG2] != 'L' || e_ident[ELFhdr.EI_MAG3] != 'F')
+                       return false;
+               return true;
+       }
+
+       public void dispose() {
+               try {
+                       if (efile != null) {
+                               efile.close();
+                               efile = null;
+                               
+                               // ensure the mappings get cleaned up
+                               if (sections_mapped)
+                                       System.gc();
+                       }
+               } catch (IOException e) {
+               }
+       }
+
+       /**
+        * Make sure we do not leak the fds.
+        */
+       @Override
+       protected void finalize() throws Throwable {
+               try {
+                       dispose();
+               } finally {
+                       super.finalize();
+               }
+       }
+
+       public Section getSectionByName(String name) throws IOException {
+               if (sections == null)
+                       getSections();
+               for (int i = 0; i < sections.length; i++) {
+                       if (sections[i].toString().equals(name)) {
+                               return sections[i];
+                       }
+               }
+               return null;
+       }
+
+       public Section[] getSections(int type) throws IOException {
+               if (sections == null)
+                       getSections();
+               ArrayList<Section> slist = new ArrayList<Section>();
+               for (int i = 0; i < sections.length; i++) {
+                       if (sections[i].sh_type == type)
+                               slist.add(sections[i]);
+               }
+               return slist.toArray(new Section[0]);
+       }
+
+       public Section[] getSections() throws IOException {
+               if (sections == null) {
+                       if (ehdr.e_shoff == 0) {
+                               sections = new Section[0];
+                               return sections;
+                       }
+                       final int length= ehdr.e_shnum & 0xffff; // unsigned short
+                       sections = new Section[length];
+                       for (int i = 0; i < length; i++) {
+                               efile.seek(ehdr.e_shoff + i * (ehdr.e_shentsize & 0xffff));     // unsigned short
+                               sections[i] = new Section();
+                               sections[i].sh_name = efile.readIntE();
+                               sections[i].sh_type = efile.readIntE();
+                               switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
+                                       case ELFhdr.ELFCLASS32 : {
+                                               byte[] addrArray = new byte[ELF32_ADDR_SIZE];
+                                               sections[i].sh_flags = efile.readIntE();
+                                               efile.readFullyE(addrArray);
+                                               sections[i].sh_addr = new Addr32(addrArray);
+                                               sections[i].sh_offset = efile.readIntE();
+                                               sections[i].sh_size = efile.readIntE();
+                                       }
+                                               break;
+                                       case ELFhdr.ELFCLASS64 : {
+                                               byte[] addrArray = new byte[ELF64_ADDR_SIZE];
+                                               sections[i].sh_flags = efile.readLongE();
+                                               efile.readFullyE(addrArray);
+                                               sections[i].sh_addr = new Addr64(addrArray);
+                                               sections[i].sh_offset = readUnsignedLong(efile);
+                                               sections[i].sh_size = readUnsignedLong(efile);
+                                       }
+                                               break;
+                                       case ELFhdr.ELFCLASSNONE :
+                                       default :
+                                               throw new IOException("Unknown ELF class " + ehdr.e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
+                               }
+
+                               sections[i].sh_link = efile.readIntE();
+                               sections[i].sh_info = efile.readIntE();
+                               switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
+                                       case ELFhdr.ELFCLASS32 : {
+                                               sections[i].sh_addralign = efile.readIntE();
+                                               sections[i].sh_entsize = efile.readIntE();
+                                       }
+                                               break;
+                                       case ELFhdr.ELFCLASS64 : {
+                                               sections[i].sh_addralign = efile.readLongE();
+                                               sections[i].sh_entsize = readUnsignedLong(efile);
+                                       }
+                                               break;
+                                       case ELFhdr.ELFCLASSNONE :
+                                       default :
+                                               throw new IOException("Unknown ELF class " + ehdr.e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
+                               }
+                               if (sections[i].sh_type == Section.SHT_SYMTAB)
+                                       syms = i;
+                               if (syms == 0 && sections[i].sh_type == Section.SHT_DYNSYM)
+                                       syms = i;
+                       }
+               }
+               return sections;
+       }
+
+       private Symbol[] loadSymbolsBySection(Section section) throws IOException {
+               int numSyms = 1;
+               if (section.sh_entsize != 0) {
+                       numSyms = (int)section.sh_size / (int)section.sh_entsize;
+               }
+               ArrayList<Symbol> symList = new ArrayList<Symbol>(numSyms);
+               long offset = section.sh_offset;
+               for (int c = 0; c < numSyms; offset += section.sh_entsize, c++) {
+                       efile.seek(offset);
+                       Symbol symbol = new Symbol(section);
+                       switch (ehdr.e_ident[ELFhdr.EI_CLASS]) {
+                               case ELFhdr.ELFCLASS32 : {
+                                       byte[] addrArray = new byte[ELF32_ADDR_SIZE];
+
+                                       symbol.st_name = efile.readIntE();
+                                       efile.readFullyE(addrArray);
+                                       symbol.st_value = new Addr32(addrArray);
+                                       symbol.st_size = efile.readIntE();
+                                       symbol.st_info = efile.readByte();
+                                       symbol.st_other = efile.readByte();
+                                       symbol.st_shndx = efile.readShortE();
+                               }
+                                       break;
+                               case ELFhdr.ELFCLASS64 : {
+                                       byte[] addrArray = new byte[ELF64_ADDR_SIZE];
+
+                                       symbol.st_name = efile.readIntE();
+                                       symbol.st_info = efile.readByte();
+                                       symbol.st_other = efile.readByte();
+                                       symbol.st_shndx = efile.readShortE();
+                                       efile.readFullyE(addrArray);
+                                       symbol.st_value = new Addr64(addrArray);
+                                       symbol.st_size = readUnsignedLong(efile);
+                               }
+                                       break;
+                               case ELFhdr.ELFCLASSNONE :
+                               default :
+                                       throw new IOException("Unknown ELF class " + ehdr.e_ident[ELFhdr.EI_CLASS]); //$NON-NLS-1$
+                       }
+                       if (symbol.st_info == 0)
+                               continue;
+                       symList.add(symbol);
+               }
+               Symbol[] results = symList.toArray(new Symbol[0]);
+               Arrays.sort(results);
+               return results;
+       }
+
+       public void loadSymbols() throws IOException {
+               if (symbols == null) {
+                       Section section[] = getSections(Section.SHT_SYMTAB);
+                       if (section.length > 0) {
+                               symtab_sym = section[0];
+                               symtab_symbols = loadSymbolsBySection(section[0]);
+                       } else {
+                               symtab_sym = null;
+                               symtab_symbols = new Symbol[0];
+                       }
+
+                       section = getSections(Section.SHT_DYNSYM);
+                       if (section.length > 0) {
+                               dynsym_sym = section[0];
+                               dynsym_symbols = loadSymbolsBySection(section[0]);
+                       } else {
+                               dynsym_sym = null;
+                               dynsym_symbols = new Symbol[0];
+                       }
+
+                       if (symtab_sym != null) {
+                               // sym = symtab_sym;
+                               symbols = symtab_symbols;
+                       } else if (dynsym_sym != null) {
+                               // sym = dynsym_sym;
+                               symbols = dynsym_symbols;
+                       }
+               }
+       }
+
+       public Symbol[] getSymbols() {
+               return symbols;
+       }
+
+       public Symbol[] getDynamicSymbols() {
+               return dynsym_symbols;
+       }
+
+       public Symbol[] getSymtabSymbols() {
+               return symtab_symbols;
+       }
+
+       /* return the address of the function that address is in */
+       public Symbol getSymbol(IAddress vma) {
+               if (symbols == null) {
+                       return null;
+               }
+
+               //@@@ If this works, move it to a single instance in this class.
+               SymbolComparator symbol_comparator = new SymbolComparator();
+
+               int ndx = Arrays.binarySearch(symbols, vma, symbol_comparator);
+               if (ndx > 0)
+                       return symbols[ndx];
+               if (ndx == -1) {
+                       return null;
+               }
+               ndx = -ndx - 1;
+               return symbols[ndx - 1];
+       }
+       /*
+        * public long swapInt( long val ) { if ( ehdr.e_ident[ELFhdr.EI_DATA] ==
+        * ELFhdr.ELFDATA2LSB ) { short tmp[] = new short[4]; tmp[0] = (short)(val &
+        * 0x00ff); tmp[1] = (short)((val >> 8) & 0x00ff); tmp[2] = (short)((val >>
+        * 16) & 0x00ff); tmp[3] = (short)((val >> 24) & 0x00ff); return ((tmp[0] < <
+        * 24) + (tmp[1] < < 16) + (tmp[2] < < 8) + tmp[3]); } return val; }
+        * 
+        * public int swapShort( short val ) { if ( ehdr.e_ident[ELFhdr.EI_DATA] ==
+        * ELFhdr.ELFDATA2LSB ) { short tmp[] = new short[2]; tmp[0] = (short)(val &
+        * 0x00ff); tmp[1] = (short)((val >> 8) & 0x00ff); return (short)((tmp[0] < <
+        * 8) + tmp[1]); } return val; }
+        */
+       public String getFilename() {
+               return file;
+       }
+
+       protected long readUnsignedLong(IRandomReadAccessFile file) throws IOException {
+               long result = file.readLongE();
+               if (result < 0) {
+                       throw new IOException("Maximal file offset is " + Long.toHexString(Long.MAX_VALUE) + //$NON-NLS-1$
+                                       " given offset is " + Long.toHexString(result)); //$NON-NLS-1$
+               }
+               return result;
+       }
+
+       /* TODO: not used in EDC
+       private ISymbolReader createDwarfReader() {
+               DwarfReader reader = null;
+               // Check if Dwarf data exists
+               try {
+                       reader = new DwarfReader(this);
+               } catch (IOException e) {
+                       // No Dwarf data in the Elf.
+               }
+               return reader;
+       }
+       */
+       
+       public ISymbolReader getSymbolReader() {
+               ISymbolReader reader = null;
+               //reader = createDwarfReader(); // TODO: not used in EDC
+               return reader;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/IRandomReadAccessFile.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/IRandomReadAccessFile.java
new file mode 100644 (file)
index 0000000..02fac0e
--- /dev/null
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     QNX Software Systems - Initial API and implementation
+ *     Nokia - split out interface
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.elf;
+
+import java.io.Closeable;
+import java.io.DataInput;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+
+/**
+ * Abstraction for the file reading used by the ERandomAccessFile and Elf classes.
+ * <p>
+ * This provides endian-aware streamed read access to a file (methods ending in 'E').  
+ * The {@link #setEndian(boolean)} call must be invoked prior to calling them.
+ * <p>
+ * This interface permits clients to interleave calls to the big-endian {@link DataInput}
+ * methods as well as the mixed-endian methods in this interface.  The endianness
+ * may also be changed at will.
+ * 
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @since 7.0
+ */
+public interface IRandomReadAccessFile extends DataInput, Closeable {
+
+       /**
+        * Set endianness of file content.
+        * @param le true for little-endian, false for big-endian.
+        */
+       void setEndian(boolean le);
+
+       /** 
+        * Set a base offset from which seek() and getFilePointer() measure,
+        * and seek there. 
+        */
+       void setFileOffset(long offset) throws IOException;
+       
+       /** 
+        * Get the basis for seek operations
+        * @see #setFileOffset(long)
+        * @return offset
+        * @throws IOException
+        */
+       long getFilePointer() throws IOException;
+       
+       /**
+        * Seek relative to the pointer set by {@link #setFileOffset(long)}. 
+        * @see RandomAccessFile#seek(long) 
+        */
+       void seek(long pos) throws IOException;
+
+       /** 
+        * Read 2 bytes and construct a short according to endianness. 
+        * @see DataInput#readShort() 
+        */
+       short readShortE() throws IOException;
+
+       /** 
+        * Read 4 bytes and construct an int according to endianness. 
+        * @see DataInput#readInt() 
+        */
+       long readIntE() throws IOException;
+       
+       /** 
+        * Read 8 bytes and construct a long according to endianness. 
+        * @see DataInput#readLong() 
+        */
+       long readLongE() throws IOException;
+
+       /**
+        * Read content and swap the entire range as if it were one large
+        * integer, according to the endianness.
+        * <p>
+        * This assumes the incoming data is big-endian, so only swaps if
+        * {@link #setEndian(boolean)} was called with 'true'.
+        * @see DataInput#readFully(byte[]) 
+        */
+       void readFullyE(byte[] bytes) throws IOException;
+
+       /** @see RandomAccessFile#read(byte[], int, int) */
+       int read(byte b[], int off, int len) throws IOException;
+
+       /** 
+        * @see RandomAccessFile#read(byte[]) 
+        */
+    int read(byte b[]) throws IOException;
+       
+    /**
+     * @see RandomAccessFile#length() 
+     */
+    long length() throws IOException;
+
+    /** 
+     * Get a read-only buffer for the given range
+     * @param offset absolute offset (<b>not</b> relative to {@link #setFileOffset(long)}).
+     * @param size the size in bytes; may not extend beyond EOF. 
+     */
+    ByteBuffer createReadByteBuffer(long offset, long size) throws IOException;
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/README.txt b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/elf/README.txt
new file mode 100644 (file)
index 0000000..df03177
--- /dev/null
@@ -0,0 +1,6 @@
+
+This is a fork of the Elf and related classes from org.eclipse.cdt.core.utils
+which is intended to to merged back into CDT core for the 7.1 or 8.0 release.
+Don't add any new functionality to these.
+
+       https://bugs.eclipse.org/bugs/show_bug.cgi?id=315420
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/BaseExecutableSymbolicsReader.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/BaseExecutableSymbolicsReader.java
new file mode 100644 (file)
index 0000000..0f3ce6b
--- /dev/null
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISection;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSection;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.symbols.ISymbol;
+import org.eclipse.cdt.debug.edc.symbols.IUnmangler;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Base implementation of a symbolics reader.  Subclasses populae sections and symbols
+ * on construction. 
+ */
+public abstract class BaseExecutableSymbolicsReader implements IExecutableSymbolicsReader {
+
+       protected final IPath binaryFile;
+       
+       protected Map<String, IExecutableSection> executableSections = new HashMap<String, IExecutableSection>();
+       protected List<ISection> sections = new ArrayList<ISection>();
+       protected List<ISymbol> symbols = new ArrayList<ISymbol>();
+       protected IAddress exeBaseAddress;
+       protected long modificationDate;
+       protected ISectionMapper sectionMapper;
+       
+       protected IUnmangler unmangler;
+
+       /**
+        * 
+        */
+       public BaseExecutableSymbolicsReader(IPath binaryFile) {
+               this.binaryFile = binaryFile;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.exe.IExecutableSymbolicsReader#dispose()
+        */
+       public void dispose() {
+               if (sectionMapper != null) {
+                       sectionMapper.dispose();
+                       sectionMapper = null;
+               }
+               sections.clear();
+               symbols.clear();
+       }
+       
+       public IPath getSymbolFile() {
+               return binaryFile;
+       }
+
+       public Collection<IExecutableSection> getExecutableSections() {
+               return Collections.unmodifiableCollection(executableSections.values());
+       }
+
+       public IExecutableSection findExecutableSection(String sectionName) {
+               return executableSections.get(sectionName);
+       }
+
+       public Collection<ISection> getSections() {
+               return Collections.unmodifiableCollection(sections);
+       }
+
+       public Collection<ISymbol> getSymbols() {
+               return Collections.unmodifiableCollection(symbols);
+       }
+
+       public ISymbol getSymbolAtAddress(IAddress linkAddress) {
+               int insertion = Collections.binarySearch(symbols, linkAddress);
+               if (insertion >= 0) {
+                       return symbols.get(insertion);
+               }
+       
+               if (insertion == -1) {
+                       return null;
+               }
+       
+               insertion = -insertion - 1;
+       
+               ISymbol symbol = symbols.get(insertion - 1);
+               if (linkAddress.compareTo(symbol.getAddress().add(symbol.getSize())) < 0) {
+                       return symbol;
+               }
+       
+               return null;
+       }
+
+       public IAddress getBaseLinkAddress() {
+               return exeBaseAddress;
+       }
+
+       public long getModificationDate() {
+               return modificationDate;
+       }
+       
+       public Collection<ISymbol> findSymbols(String name) {
+               List<ISymbol> matchSymbols = new ArrayList<ISymbol>();
+               
+               // look for exact symbols
+               for (ISymbol symbol : symbols) {
+                       String symName = symbol.getName();
+                       if (symName.equals(name)) {
+                               matchSymbols.add(symbol);
+                       }
+               }
+               if (!matchSymbols.isEmpty())
+                       return matchSymbols;
+               
+               // try for a decorated symbol if no match
+               if (unmangler != null) {
+                       for (ISymbol symbol : symbols) {
+                               String symName = unmangler.undecorate(symbol.getName());
+                               if (symName.equals(name)) {
+                                       matchSymbols.add(symbol);
+                               }
+                       }
+               }
+               
+               return matchSymbols;
+       }
+       
+       public Collection<ISymbol> findUnmangledSymbols(String name) {
+               List<ISymbol> matchSymbols = new ArrayList<ISymbol>();
+
+               if (unmangler != null) {
+                       name = unmangler.undecorate(name);
+                       
+                       String nameNoSpaces = name.replaceAll("\\s", "");
+                       
+                       // remove full qualifier
+                       if (nameNoSpaces.startsWith("::"))
+                               nameNoSpaces = nameNoSpaces.substring(2);
+                       
+                       boolean nameNoArguments = !nameNoSpaces.endsWith(")");
+                       
+                       // avoid unmangling a lot of irrelevant symbols by filtering out symbols not containing the base name
+                       String undecoratedBase = nameNoSpaces;
+                       int idx = undecoratedBase.lastIndexOf(':');
+                       if (idx >= 0)
+                               undecoratedBase = undecoratedBase.substring(idx+1);
+                       idx = undecoratedBase.indexOf('(');
+                       if (idx >= 0)
+                               undecoratedBase = undecoratedBase.substring(0, idx);
+                       
+                       for (ISymbol symbol : symbols) {
+                               String symName = symbol.getName();
+                               if (!symName.contains(undecoratedBase))
+                                       continue;
+                               
+                               try {
+                                       String unmangled = unmangler.unmangle(unmangler.undecorate(symName));
+                                       if (unmangled != null) {
+                                               String unmangledNoSpaces;
+                                               // remove any 'const' which is in front of '(' for now
+                                               unmangledNoSpaces = unmangled.replaceAll("\\bconst\\s*(?=\\()", "");
+                                               unmangledNoSpaces = unmangledNoSpaces.replaceAll("\\s", "");
+                                               
+                                               // remove full qualifier
+                                               if (unmangledNoSpaces.startsWith("::"))
+                                                       unmangledNoSpaces = unmangledNoSpaces.substring(2);
+                                               
+                                               if (nameNoSpaces.equals(unmangledNoSpaces)) {
+                                                       matchSymbols.add(symbol);
+                                               } else if (nameNoArguments) {
+                                                       // try to match the name against a function
+                                                       idx = unmangledNoSpaces.lastIndexOf('(');
+                                                       if (idx >= 0) {
+                                                               String unmangledNoArguments = unmangledNoSpaces.substring(0, idx);
+                                                               if (unmangledNoArguments.equals(nameNoSpaces)) {
+                                                                       matchSymbols.add(symbol);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               } catch (UnmanglingException e) {
+                                       // nope
+                               }
+                       }
+                       if (!matchSymbols.isEmpty())
+                               return matchSymbols;
+               }
+               
+               return matchSymbols;
+       }
+
+       public IUnmangler getUnmangler() {
+               return unmangler;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/DebugInfoProviderFactory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/DebugInfoProviderFactory.java
new file mode 100644 (file)
index 0000000..404e256
--- /dev/null
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.symbols.IDebugInfoProvider;
+import org.eclipse.cdt.debug.edc.symbols.IDebugInfoProviderFactory;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * Factory for creating debug symbolics providers from executables.
+ */
+public class DebugInfoProviderFactory {
+       private static Map<String, IDebugInfoProviderFactory> providerMap = new HashMap<String, IDebugInfoProviderFactory>();
+       
+       static {
+               initializeExtensions();
+       }
+       
+       /**
+        * Create a debug info provider for the given binary (usually the executable being
+        * debugged).  It's up to a {@link IDebugInfoProviderFactory}
+        * implementation to determine how it maps a binary to a symbolics file. 
+        * @param binaryPath path to a host file 
+        * @param exeReader the reader for that file, or <code>null</code> 
+        * @return {@link IDebugInfoProvider} or <code>null</code> if nothing supports it
+        */
+       public static IDebugInfoProvider createFor(IPath binaryPath, IExecutableSymbolicsReader exeReader) {
+               for (Map.Entry<String, IDebugInfoProviderFactory> entry: providerMap.entrySet()) {
+                       String name = entry.getKey();
+                       IDebugInfoProviderFactory providerProvider = entry.getValue();
+                       try {
+                               IDebugInfoProvider provider = providerProvider.createDebugInfoProvider(binaryPath, exeReader);
+                               if (provider != null)
+                                       return provider;
+                       } catch (Throwable t) {
+                               EDCDebugger.getMessageLogger().logError("Debug info reader " + name + " failed", t);
+                       }
+               }
+               return null;
+       }
+       
+       protected static void initializeExtensions() {
+               IConfigurationElement[] elements = 
+                       Platform.getExtensionRegistry().getConfigurationElementsFor(IDebugInfoProviderFactory.EXTENSION_ID);
+               for (IConfigurationElement element : elements) {
+                       try {
+                               String name = element.getAttribute("name"); //$NON-NLS-1$
+                               IDebugInfoProviderFactory formatProvider = 
+                                       (IDebugInfoProviderFactory) element.createExecutableExtension("class"); //$NON-NLS-1$
+                               providerMap.put(name, formatProvider);
+                       } catch (Exception e) {
+                               EDCDebugger.getMessageLogger().logError("Could not create executable symbolics provider extension", e);
+                       }
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ElfExecutableSymbolicsReader.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ElfExecutableSymbolicsReader.java
new file mode 100644 (file)
index 0000000..901b5e6
--- /dev/null
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.io.IOException;
+import java.nio.ByteOrder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISection;
+import org.eclipse.cdt.debug.edc.internal.symbols.Section;
+import org.eclipse.cdt.debug.edc.internal.symbols.Symbol;
+import org.eclipse.cdt.debug.edc.internal.symbols.elf.Elf;
+import org.eclipse.cdt.debug.edc.internal.symbols.elf.Elf.PHdr;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSection;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * This class handles reading ELF files for the purposes of detecting symbolics.  
+ */
+public class ElfExecutableSymbolicsReader extends BaseExecutableSymbolicsReader {
+       protected boolean isLE;
+
+       public ElfExecutableSymbolicsReader(IPath binaryFile, Elf elf) throws IOException {
+               super(binaryFile);
+               
+               Elf.ELFhdr header = elf.getELFhdr();
+               isLE = header.e_ident[Elf.ELFhdr.EI_DATA] == Elf.ELFhdr.ELFDATA2LSB;
+               exeBaseAddress = getExeSegment(elf).p_vaddr;
+               modificationDate = binaryFile.toFile().lastModified();
+               
+               sectionMapper = new SectionMapper(binaryFile, isLE);
+               
+               recordSections(elf);
+               readSymbols(elf);
+               
+               // TODO: better selection.  We assume for now that all ELF targets we know about (ARM, Linux) use the same mangling.
+               unmangler = new UnmanglerEABI();
+       }
+       
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return "ELF symbolics reader for " + binaryFile; //$NON-NLS-1$
+       }
+       
+       /**
+        * Determine the executable format and record the sections.
+        * @param elfFile 
+        * 
+        * @throws IOException if file contents cannot be read
+        */
+       private void recordSections(Elf elfFile) throws IOException {
+               
+               // start from zero so that we can use it as index to the array list
+               // for quick access.
+               int id = 0;
+               Map<String, Object> props;
+
+               // Use segments instead of sections in the Elf file.
+               PHdr[] segments = elfFile.getPHdrs();
+
+               for (PHdr s : segments) {
+                       if (s.p_type == PHdr.PT_LOAD) {
+                               props = new HashMap<String, Object>();
+
+                               if ((s.p_flags & PHdr.PF_X) != 0)
+                                       props.put(ISection.PROPERTY_NAME, ISection.NAME_TEXT);
+                               else
+                                       // There is no clear way to tell if a segment is
+                                       // data or bss segment.
+                                       props.put(ISection.PROPERTY_NAME, ISection.NAME_DATA);
+
+                               Section section = new Section(id++, s.p_memsz, s.p_vaddr, props);
+                               sections.add(section);
+                       }
+               }
+               
+               // remember how to map the sections
+               Elf.Section[] sections = elfFile.getSections();
+               for (Elf.Section section : sections) {
+                       String name = section.toString();
+                       
+                       if (name.length() > 0) {
+                               if (executableSections.containsKey(name))
+                                       throw new IllegalStateException("duplicate section " + name);
+                               IExecutableSection exeSection = new ExecutableSection(sectionMapper, name, 
+                                               new SectionInfo(section.sh_offset, section.sh_size));
+                               executableSections.put(name, exeSection);
+                       }
+               }
+       }
+       
+       protected void readSymbols(Elf elfFile) throws IOException {
+               // load the symbol table
+               elfFile.loadSymbols();
+               Set<IAddress> symbolAddressSet = new TreeSet<IAddress>();
+               
+               for (Elf.Symbol symbol : elfFile.getSymtabSymbols()) {
+                       String name = symbol.toString();
+                       // Multiple symbol entries for the same address are generated.
+                       // Do not add duplicate symbols with 0 size to the list since it confuses
+                       // debugger
+                       if (name.length() > 0) {                        
+                               if (symbol.st_size != 0 || !symbolAddressSet.contains(symbol.st_value)) {
+                                       // need to get rid of labels with size 0
+                                       if (symbol.st_size != 0 || !name.startsWith("|")) {
+                                               symbols.add(new Symbol(symbol.toString(), symbol.st_value, symbol.st_size));
+                                               symbolAddressSet.add(symbol.st_value);
+                                       }
+                               }
+                       }
+               }
+               
+               // now sort it by address for faster lookups
+               Collections.sort(symbols);
+       }
+       
+       /**
+        * Find the executable (text) segment of the elf file, assuming there is
+        * only one that segment.
+        * 
+        * @param elf
+        * @return exe segment header or null on error.
+        * @throws IOException
+        */
+       private PHdr getExeSegment(Elf elf) throws IOException {
+               PHdr[] segments = elf.getPHdrs();
+
+               for (PHdr s : segments) {
+                       if (s.p_type == PHdr.PT_LOAD && ((s.p_flags & PHdr.PF_X) != 0))
+                               return s;
+               }
+
+               return null;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IExecutableSymbolicsReader#getByteOrder()
+        */
+       public ByteOrder getByteOrder() {
+               return isLE ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN;
+       }
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ElfExecutableSymbolicsReaderFactory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ElfExecutableSymbolicsReaderFactory.java
new file mode 100644 (file)
index 0000000..f43aef0
--- /dev/null
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.debug.edc.internal.symbols.elf.BufferedRandomReadAccessFile;
+import org.eclipse.cdt.debug.edc.internal.symbols.elf.Elf;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReaderFactory;
+import org.eclipse.cdt.utils.elf.Elf.ELFhdr;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Factory for creating readers of symbolics in executables.
+ */
+public class ElfExecutableSymbolicsReaderFactory implements IExecutableSymbolicsReaderFactory {
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IExecutableSymbolicsReaderFactory#getConfidence(org.eclipse.core.runtime.IPath)
+        */
+       public int getConfidence(IPath binaryFile) {
+               Elf elfFile = getElfFile(binaryFile);
+               if (elfFile == null) {
+                       // treat the symbol file as an executable, if existing
+                       IPath symbolFilePath = ExecutableSymbolicsReaderFactory.findSymbolicsFile(binaryFile);
+                       if (symbolFilePath != null) {
+                               elfFile = getElfFile(symbolFilePath);
+                       }
+               }
+               return elfFile != null ? IExecutableSymbolicsReaderFactory.NORMAL_CONFIDENCE :
+                       IExecutableSymbolicsReaderFactory.NO_CONFIDENCE;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IExecutableSymbolicsReaderFactory#createExecutableSymbolicsReader(org.eclipse.core.runtime.IPath)
+        */
+       public IExecutableSymbolicsReader createExecutableSymbolicsReader(
+                       IPath binaryFile) {
+
+               IExecutableSymbolicsReader reader = detectExecutable(binaryFile);
+               if (reader == null) {
+                       // treat the symbol file as an executable, if existing
+                       IPath symbolFilePath = ExecutableSymbolicsReaderFactory.findSymbolicsFile(binaryFile);
+                       if (symbolFilePath != null) {
+                               reader = detectExecutable(symbolFilePath);
+                       }
+               }
+               
+               return reader;
+       }
+       
+       private IExecutableSymbolicsReader detectExecutable(IPath binaryFile) {
+               try {
+                       Elf elfFile = getElfFile(binaryFile);
+                       if (elfFile != null) {
+                               return new ElfExecutableSymbolicsReader(binaryFile, elfFile);
+                       }
+               } catch (IOException e) {
+                       // this class elides actual I/O errors with format errors; ignore
+               }
+               return null;
+       }
+       
+       private Elf getElfFile(IPath binaryFile) {
+               try {
+                       // quickly check the endianness (Elf repeats this)
+                       FileInputStream fis = new FileInputStream(binaryFile.toOSString());
+                       byte[] e_ident = new byte[16];
+                       fis.read(e_ident);
+                       if (e_ident[ELFhdr.EI_MAG0] != 0x7f || e_ident[ELFhdr.EI_MAG1] != 'E' || e_ident[ELFhdr.EI_MAG2] != 'L'
+                                       || e_ident[ELFhdr.EI_MAG3] != 'F')
+                               throw new IOException(CCorePlugin.getResourceString("Util.exception.notELF")); //$NON-NLS-1$
+                       
+                       boolean isle = (e_ident[ELFhdr.EI_DATA] == ELFhdr.ELFDATA2LSB);
+                       
+                       // If this constructor succeeds, it's ELF
+                       Elf elf = new Elf(new BufferedRandomReadAccessFile(binaryFile.toOSString(), isle), 
+                                       binaryFile.toOSString(), 0);
+                       return elf;
+               } catch (IOException e) {
+                       // this class elides actual I/O errors with format errors; ignore
+               }
+
+               return null;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ExecutableSection.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ExecutableSection.java
new file mode 100644 (file)
index 0000000..e626b89
--- /dev/null
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.io.IOException;
+
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSection;
+
+/**
+ * 
+ */
+public class ExecutableSection implements IExecutableSection {
+
+       private final String name;
+       private final ISectionMapper executableSectionMapper;
+       private final SectionInfo section;
+       private IStreamBuffer buffer;
+       private boolean deadSection;
+
+       /**
+        * @param section
+        * @param name
+        * @param elfExecutableSymbolicsReader
+        */
+       public ExecutableSection(ISectionMapper executableSectionMapper,
+                       String name,
+                       SectionInfo section) {
+               this.executableSectionMapper = executableSectionMapper;
+               this.name = name;
+               this.section = section;
+               this.deadSection = false;
+       }
+
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return name + " @ " + section + (deadSection ? " <<BROKEN>>": ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.exe.IExecutableSection#getName()
+        */
+       public String getName() {
+               return name;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.exe.IExecutableSection#getBuffer()
+        */
+       public IStreamBuffer getBuffer() {
+               if (buffer == null && !deadSection) {
+                       try {
+                               buffer = executableSectionMapper.getSectionBuffer(section);
+                       } catch (IOException e) {
+                               deadSection = true;
+                               EDCDebugger.getMessageLogger().logError("Failed to read section " + name, e);
+                       }  
+               }
+               return buffer;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.exe.IExecutableSection#dispose()
+        */
+       public void dispose() {
+               executableSectionMapper.releaseSectionBuffer(section);
+               buffer = null;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ExecutableSymbolicsReaderFactory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ExecutableSymbolicsReaderFactory.java
new file mode 100644 (file)
index 0000000..bbf9b7c
--- /dev/null
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReaderFactory;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * Factory for creating readers of symbolics in executables.
+ */
+public class ExecutableSymbolicsReaderFactory {
+       
+       private static final String SYM_EXTENSION = "sym";
+       private static final String DBG_EXTENSION = "dbg";
+       
+       private static Map<String, IExecutableSymbolicsReaderFactory> providerMap = new HashMap<String, IExecutableSymbolicsReaderFactory>();
+       
+       static {
+               initializeExtensions();
+       }
+
+       public static IExecutableSymbolicsReader createFor(IPath binaryFile) {
+               IExecutableSymbolicsReaderFactory provider = null;
+               String providerName = null;
+               int highestConfidence = IExecutableSymbolicsReaderFactory.NO_CONFIDENCE;
+
+               // find the extension with the highest confidence for this binary
+               for (Map.Entry<String, IExecutableSymbolicsReaderFactory> entry : providerMap.entrySet()) {
+                       IExecutableSymbolicsReaderFactory factory = entry.getValue();
+                       try {
+                               int confidence = factory.getConfidence(binaryFile);
+                               if (confidence > highestConfidence) {
+                                       highestConfidence = confidence;
+                                       provider = factory;
+                                       providerName = entry.getKey();
+                               }
+                       } catch (Throwable t) {
+                               EDCDebugger.getMessageLogger().logError("Executable reader " + entry.getKey() + " failed", t);
+                       }
+               }
+
+               if (provider != null) {
+                       try {
+                               IExecutableSymbolicsReader reader = provider.createExecutableSymbolicsReader(binaryFile);
+                               if (reader != null)
+                                       return reader;
+                       } catch (Throwable t) {
+                               EDCDebugger.getMessageLogger().logError("Executable reader " + providerName + " failed", t);
+                       }
+               }
+
+               return null;
+       }
+       
+       /**
+        * Get a symbolics file which is associated with the given executable.
+        * @param binaryFile
+        * @return IPath or <code>null</code> if no candidate (or already looks like a sym file) 
+        */
+       public static IPath findSymbolicsFile(IPath binaryFile) {
+
+               // Check to see if there is a sym file we should use for the symbols
+               //
+               // Note: there may be for "foo.exe" --> "foo.exe.sym" or "foo.sym"
+               //
+               // Note #2: there may be BOTH.  Pick the newest one.
+               //
+               List<IPath> candidates = new ArrayList<IPath>();
+               
+               IPath symFile;
+               symFile = binaryFile.removeFileExtension().addFileExtension(SYM_EXTENSION);
+               if (symFile.toFile().exists()) 
+                       candidates.add(symFile);
+               symFile = binaryFile.removeFileExtension().addFileExtension(DBG_EXTENSION);
+               if (symFile.toFile().exists()) 
+                       candidates.add(symFile);
+               
+               symFile = binaryFile.addFileExtension(SYM_EXTENSION);
+               if (symFile.toFile().exists())
+                       candidates.add(symFile);
+               symFile = binaryFile.addFileExtension(DBG_EXTENSION);
+               if (symFile.toFile().exists())
+                       candidates.add(symFile);
+               
+               if (candidates.isEmpty())
+                       return null;
+               
+               if (candidates.size() > 1) {
+                       Collections.sort(candidates, new java.util.Comparator<IPath>() {
+                               public int compare(IPath o1, IPath o2) {
+                                       long diff = o1.toFile().lastModified() - o2.toFile().lastModified();
+                                       return diff > 0 ? -1 : diff < 0 ? 1 : 0;
+                               }
+                       });
+               }
+               
+               return candidates.get(0);
+       }
+       
+       protected static void initializeExtensions() {
+               IConfigurationElement[] elements = 
+                       Platform.getExtensionRegistry().getConfigurationElementsFor(IExecutableSymbolicsReaderFactory.EXTENSION_ID);
+               for (IConfigurationElement element : elements) {
+                       try {
+                               String name = element.getAttribute("name"); //$NON-NLS-1$
+                               IExecutableSymbolicsReaderFactory formatProvider = 
+                                       (IExecutableSymbolicsReaderFactory) element.createExecutableExtension("class"); //$NON-NLS-1$
+                               providerMap.put(name, formatProvider);
+                       } catch (Exception e) {
+                               EDCDebugger.getMessageLogger().logError("Could not create executable symbolics provider extension", e);
+                       }
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/FileStatistics.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/FileStatistics.java
new file mode 100644 (file)
index 0000000..c04d184
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+/**
+ * Statistics tracking for file operations (used for debugging and unit tests)
+ */
+public class FileStatistics {
+       /** if set, dump info to console at runtme */
+       public static boolean DEBUG = false;
+       /** # of executables opened in session */
+       public static int executablesOpened;
+       /** # of executables currently open in session */
+       public static int executablesOpen;
+       /** amount of memory for buffers currently allocated on heap */ 
+       public static long currentHeapAllocatedBuffers;
+       /** amount of memory for buffers currently allocated in memory maps */
+       /** amount of memory for buffers ever allocated on heap */ 
+       public static long totalHeapAllocatedBuffers;
+       public static long currentMemoryMappedBuffers;
+       /** amount of memory for buffers ever allocated in memory maps */ 
+       public static long totalMemoryMappedBuffers;
+       
+       /** Log interesting information */ 
+       public static void log(String line) {
+               if (DEBUG)
+                       System.out.println(line);
+       }
+       
+       private static String now() {
+               Calendar cal = Calendar.getInstance();
+           DateFormat sdf = SimpleDateFormat.getTimeInstance();
+           return sdf.format(cal.getTime());
+       }
+       
+       public static void dump() {
+               System.out.println("File statistics at " + now() + ":");
+               System.out.println("\t# executables opened: " + executablesOpened);
+               System.out.println("\t# executables still open: " + executablesOpen);
+               System.out.println("\tcurrent heap buffer allocation: " + currentHeapAllocatedBuffers);
+               System.out.println("\ttotal heap buffer allocation: " + totalHeapAllocatedBuffers);
+               System.out.println("\tcurrent memory mapped buffer allocation: " + currentMemoryMappedBuffers);
+               System.out.println("\ttotal memory mapped buffer allocation: " + totalMemoryMappedBuffers);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ISectionMapper.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ISectionMapper.java
new file mode 100644 (file)
index 0000000..fcc11e8
--- /dev/null
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.io.IOException;
+
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Handle mapping sections of an executable into memory and caching the content.
+ * This may hold files open and consume heap and system memory.
+ */
+public interface ISectionMapper {
+       /**
+        * Get the associated file on which content is mapped.
+        */
+       IPath getMappedFile();
+       
+       /**
+        * Get the contents of a section.  The buffer may be cached or may be fetched on-demand,
+        * so there is no (memory) limit on its size.
+        * The buffer has the appropriate endianness for the file.
+        * @param section a backend-specific object representing a section 
+        * @return an {@link IStreamBuffer} for the contents
+        * @throws IOException if contents could not be (re-)read.
+        */
+       IStreamBuffer getSectionBuffer(SectionInfo section) throws IOException;
+
+       /**
+        * Explicitly release a section's buffer.  References to the previously-returned
+        * ByteBuffer may become invalid.
+        */
+       void releaseSectionBuffer(SectionInfo section);
+       
+       /**
+        * Free any cached content and close any open files.
+        */
+       void dispose();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/PEFileExecutableSymbolicsReader.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/PEFileExecutableSymbolicsReader.java
new file mode 100644 (file)
index 0000000..55a2a8b
--- /dev/null
@@ -0,0 +1,276 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteOrder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISection;
+import org.eclipse.cdt.debug.edc.internal.symbols.Section;
+import org.eclipse.cdt.debug.edc.internal.symbols.Symbol;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSection;
+import org.eclipse.cdt.debug.edc.symbols.ISymbol;
+import org.eclipse.cdt.utils.Addr32;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.cdt.utils.coff.Coff.SectionHeader;
+import org.eclipse.cdt.utils.coff.PE;
+import org.eclipse.cdt.utils.coff.PE.NTOptionalHeader;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * This class handles PE-COFF files for the purpose of supporting symbolics. 
+ */
+public class PEFileExecutableSymbolicsReader extends BaseExecutableSymbolicsReader {
+       
+       static public final String CODEVIEW_SECTION_NAME = "CodeView_Data";
+       /** .CRT is another initialized data section utilized by the Microsoft C/C++ run-time libraries 
+        * @since 5.2
+        */
+       public final static String _CRT = ".CRT"; //$NON-NLS-1$
+       
+       protected boolean isLE;
+       protected Map<Integer, ISection> sectionsByPEID = new HashMap<Integer, ISection>();
+
+       public PEFileExecutableSymbolicsReader(IPath binaryFile, PE peFile) throws IOException {
+               super(binaryFile);
+               isLE = true;
+               exeBaseAddress = new Addr32(peFile.getNTOptionalHeader().ImageBase);
+               modificationDate = binaryFile.toFile().lastModified();
+               
+               sectionMapper = new SectionMapper(binaryFile, isLE);
+               
+               recordSections(peFile);
+               
+               // TODO: better selection.
+               boolean isWin32 = false, isEABI = false;
+               for (ISymbol symbol : symbols) {
+                       String symname = symbol.getName();
+                       if (symname.startsWith("__Z") && symname.endsWith("v")) {
+                               isWin32 = true;
+                               isEABI = true;
+                               break;
+                       } else if (symname.startsWith("_Z") && symname.endsWith("v")) {
+                               isEABI = true;
+                               break;
+                       } else if (symname.contains("@") && symname.contains("?")) {
+                               isWin32 = true;
+                               break;
+                       }
+               }
+               if (isWin32 && isEABI)
+                       unmangler = new UnmanglerWin32EABI();
+               else if (isEABI)
+                       unmangler = new UnmanglerEABI();
+               else
+                       unmangler = new UnmanglerWin32();
+                       
+               
+       }
+       
+       /**
+        * Determine the executable format and record the sections.
+        * @param peFile 
+        * 
+        * @throws IOException if file reading fails
+        */
+       private void recordSections(PE peFile) throws IOException {
+               // start from zero so that we can use it as index to the array list
+               // for quick access.
+               int id = 0;
+               Map<String, Object> props;
+
+               SectionHeader[] secHeaders = peFile.getSectionHeaders();
+               long imageBase = peFile.getNTOptionalHeader().ImageBase & 0xffffffffL;
+               SectionHeader rDataHeader = null;
+               int peSectionID = 0;
+
+               for (SectionHeader s : secHeaders) {
+                       peSectionID++;
+                       String name = new String(s.s_name).trim();
+                       if (name.startsWith("/")) //$NON-NLS-1$
+                       {
+                               int stringTableOffset = Integer.parseInt(name.substring(1));
+                               name = peFile.getStringTableEntry(stringTableOffset);
+                       }
+
+                       // Remember how to map this section
+                       if (executableSections.containsKey(name))
+                               throw new IllegalStateException("duplicate section " + name);
+                       IExecutableSection exeSection = new ExecutableSection(sectionMapper, name, 
+                                       new SectionInfo(s.s_scnptr, s.s_paddr));
+                       executableSections.put(name, exeSection);
+
+                       String sectionName = name;
+                       // Convert the name to our unified name.
+                       if (sectionName.equals(SectionHeader._TEXT))
+                               name = ISection.NAME_TEXT;
+                       else if (sectionName.equals(SectionHeader._DATA) || sectionName.equals(_CRT))
+                               name = ISection.NAME_DATA;
+                       else if (sectionName.equals(".rdata")) // add this name in SectionHeader ?
+                       {
+                               name = ISection.NAME_RODATA;
+                               rDataHeader = s;
+                       }
+                       else if (sectionName.equals(SectionHeader._BSS))
+                               name = ISection.NAME_BSS;
+                       else { // ignore other section.
+                               continue;
+                       }
+
+                       // Well, PE is a _modified_ version of COFF, where
+                       // section.s_paddr of COFF becomes "VirtualSize"
+                       // (memory size of the section) in PE, while s_size
+                       // is raw data size (file size of the section).
+                       long size = s.s_paddr; // not s_size !
+
+                       props = new HashMap<String, Object>();
+                       props.put(ISection.PROPERTY_NAME, name);
+
+                       // Note the s_vaddr is relative to image base.
+                       // For Section we need absolute address.
+                       Section newSection = new Section(id++, size, new Addr64(Long.toString(imageBase + s.s_vaddr)), props);
+                       sections.add(newSection);
+                       sectionsByPEID.put(peSectionID, newSection);
+               }
+
+               // load the symbol table
+               //
+               /*
+                * Note this "rawSymbols" array contains both standard and auxiliary
+                * symbol records. It's assumed symbols in the array are in the same
+                * order they appear in the symbol table section, no sorting of any kind
+                * is done.
+                * 
+                * Actually auxiliary symbols should not be treated the same as standard
+                * symbols by Coff and PE in CDT core. But fixing that would break API,
+                * which is not allowed for CDT 7.0 at this time......... 04/07/10
+                */
+               org.eclipse.cdt.utils.coff.Coff.Symbol[] rawSymbols = peFile.getSymbols();
+               
+               for (int i=0; i < rawSymbols.length; i++) {
+                       org.eclipse.cdt.utils.coff.Coff.Symbol symbol = rawSymbols[i];
+
+                       if (!(symbol.n_type == 0)) // Change to Coff.isNoSymbol for CDT 8.0.
+                       {
+                               String symName = symbol.getName(peFile.getStringTable());
+                               symbols.add(new Symbol(symName, new Addr32(symbol.n_value), 1));
+                       }
+
+                       // skip auxiliary symbol record(s) if any as otherwise they may
+                       // give us bogus match in any symbol table lookup.
+                       if (symbol.n_numaux > 0) {
+                               i += symbol.n_numaux; 
+                       }
+               }
+               
+               if (rDataHeader != null)
+                       checkForCodeView(peFile, rDataHeader, imageBase, id);
+
+               // now sort it by address for faster lookups
+               Collections.sort(symbols);
+       }
+
+       private void checkForCodeView(PE peFile, SectionHeader rDataHeader, long imageBase, int id) throws IOException { //$NON-NLS-1$
+               // figure out the file offset of the debug directory
+               // entries
+               final int IMAGE_DIRECTORY_ENTRY_DEBUG = 6;
+               final int DEBUGDIRSZ = 28;
+               NTOptionalHeader ntHeader = peFile.getNTOptionalHeader();
+               if (ntHeader == null
+                               || ntHeader.NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_DEBUG)
+                       return;
+
+               int debugDir = ntHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
+               if (debugDir == 0)
+                       return;
+
+               int debugFormats = ntHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size / 28;
+               if (debugFormats == 0)
+                       return;
+
+               int offsetInto_rdata = debugDir
+                               - rDataHeader.s_vaddr;
+               int fileOffset = rDataHeader.s_scnptr
+                               + offsetInto_rdata;
+               RandomAccessFile accessFile = new RandomAccessFile(
+                               binaryFile.toOSString(), "r");
+
+               // loop through the debug directories looking for
+               // CodeView (type 2)
+               for (int j = 0; j < debugFormats; j++) {
+                       PE.IMAGE_DEBUG_DIRECTORY dir = new PE.IMAGE_DEBUG_DIRECTORY(
+                                       accessFile, fileOffset);
+
+                       if ((dir.Type == 2) && (dir.SizeOfData > 0)) {
+                               // CodeView found, seek to actual data
+                               int debugBase = dir.PointerToRawData;
+                               accessFile.seek(debugBase);
+
+                               // sanity check. the first four bytes of the
+                               // CodeView
+                               // data should be "NB11"
+                               String s2 = accessFile.readLine();
+                               if (s2.startsWith("NB11")) { //$NON-NLS-1$
+                                       // Attribute att = peFile.getAttribute();
+                                       long start = debugBase;
+                                       long size = accessFile.length() - start;
+                                       
+                                       String name = CODEVIEW_SECTION_NAME;
+                                       IExecutableSection exeSection = new ExecutableSection(sectionMapper, name, 
+                                                       new SectionInfo(start, size));
+                                       executableSections.put(name, exeSection);
+                               }
+                       }
+                       fileOffset += DEBUGDIRSZ;
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IExecutableSymbolicsReader#getByteOrder()
+        */
+       public ByteOrder getByteOrder() {
+               return isLE ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.exe.IExecutableSymbolicsReader#getSymbolAtAddress()
+        */
+       @Override
+       public ISymbol getSymbolAtAddress(IAddress linkAddress) {
+               int insertion = Collections.binarySearch(symbols, linkAddress);
+               if (insertion >= 0) {
+                       return symbols.get(insertion++);
+               }
+       
+               if (insertion == -1) {
+                       return null;
+               }
+       
+               insertion = -insertion - 1;
+
+               if (insertion == symbols.size()) {
+                       return null;
+               }
+
+               return symbols.get(insertion - 1);
+       }
+       
+       public ISection getSectionByPEID(int peID)
+       {
+               return sectionsByPEID.get(peID);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/PEFileExecutableSymbolicsReaderFactory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/PEFileExecutableSymbolicsReaderFactory.java
new file mode 100644 (file)
index 0000000..0073026
--- /dev/null
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.io.IOException;
+
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReaderFactory;
+import org.eclipse.cdt.utils.coff.PE;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Factory for creating readers of symbolics in executables.
+ */
+public class PEFileExecutableSymbolicsReaderFactory implements IExecutableSymbolicsReaderFactory {
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IExecutableSymbolicsReaderFactory#getConfidence(org.eclipse.core.runtime.IPath)
+        */
+       public int getConfidence(IPath binaryFile) {
+               try {
+                       // If this constructor succeeds, it's PE
+                       @SuppressWarnings("unused")
+                       PE peFile = new PE(binaryFile.toOSString());
+                       return IExecutableSymbolicsReaderFactory.NORMAL_CONFIDENCE;
+               } catch (IOException e) {
+                       // this class elides actual I/O errors with format errors; ignore
+               }
+               return IExecutableSymbolicsReaderFactory.NO_CONFIDENCE;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IExecutableSymbolicsReaderFactory#createExecutableSymbolicsReader(org.eclipse.core.runtime.IPath)
+        */
+       public IExecutableSymbolicsReader createExecutableSymbolicsReader(
+                       IPath binaryFile) {
+               
+               try {
+                       // If this constructor succeeds, it's PE
+                       PE peFile = new PE(binaryFile.toOSString());
+                       return new PEFileExecutableSymbolicsReader(binaryFile, peFile);
+               } catch (IOException e) {
+                       // this class elides actual I/O errors with format errors; ignore
+               }
+               return null;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/SectionInfo.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/SectionInfo.java
new file mode 100644 (file)
index 0000000..2c59874
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+/**
+ * Information about the range of content for a section.  Used as a key in {@link SectionMapper}.
+ */
+public class SectionInfo {
+
+       public long fileOffset;
+       public long sectionSize;
+
+       public SectionInfo(long fileOffset, long sectionSize) {
+               this.fileOffset = fileOffset;
+               this.sectionSize = sectionSize;
+       }
+
+       /* (non-Javadoc)
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return "section from " + Long.toHexString(fileOffset) + " - " + Long.toHexString(fileOffset + sectionSize); //$NON-NLS-1$ //$NON-NLS-2$
+       }
+       
+       /* (non-Javadoc)
+        * @see java.lang.Object#hashCode()
+        */
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 1;
+               result = prime * result + (int) (fileOffset ^ (fileOffset >>> 32));
+               result = prime * result + (int) (sectionSize ^ (sectionSize >>> 32));
+               return result;
+       }
+
+       /* (non-Javadoc)
+        * @see java.lang.Object#equals(java.lang.Object)
+        */
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               SectionInfo other = (SectionInfo) obj;
+               if (fileOffset != other.fileOffset)
+                       return false;
+               if (sectionSize != other.sectionSize)
+                       return false;
+               return true;
+       }
+       
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/SectionMapper.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/SectionMapper.java
new file mode 100644 (file)
index 0000000..9791720
--- /dev/null
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.io.IOException;
+import java.nio.ByteOrder;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.FileStreamBuffer;
+import org.eclipse.cdt.debug.edc.internal.MemoryStreamBuffer;
+import org.eclipse.cdt.utils.ERandomAccessFile;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Handle mapping sections into memory and caching this content.
+ */
+public class SectionMapper implements ISectionMapper {
+       
+       private final IPath hostFile;
+       private final boolean isLE;
+       private ERandomAccessFile efile;
+       /** all sections loaded for any reason */
+       private Map<SectionInfo, IStreamBuffer> loadedSections; 
+       /** subset of sections loaded into memory maps */
+       private Map<SectionInfo, IStreamBuffer> mappedBuffers;
+       
+       public SectionMapper(IPath hostFile, boolean isLE) {
+               this.hostFile = hostFile;
+               this.isLE = isLE;
+               this.efile = null;
+               this.loadedSections = new HashMap<SectionInfo, IStreamBuffer>();
+               this.mappedBuffers = new HashMap<SectionInfo, IStreamBuffer>();
+       }
+       
+       public void dispose() {
+               for (Map.Entry<SectionInfo, IStreamBuffer> entry: loadedSections.entrySet()) {
+                       IStreamBuffer buffer = entry.getValue();
+                       if (buffer == null)
+                               continue;
+                       if (mappedBuffers.containsKey(entry.getKey()))
+                               FileStatistics.currentMemoryMappedBuffers -= buffer.capacity();
+                       else
+                               FileStatistics.currentHeapAllocatedBuffers -= buffer.capacity();
+               }
+               loadedSections.clear();
+               mappedBuffers.clear();
+               close();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.exe.ISectionMapper#getMappedFile()
+        */
+       public IPath getMappedFile() {
+               return hostFile;
+       }
+       
+       /**
+        * 
+        */
+       private void ensureOpen() throws IOException {
+               if (efile == null) {
+                       FileStatistics.log("Opening " + hostFile.toFile());
+                       FileStatistics.executablesOpened++;
+                       FileStatistics.executablesOpen++;
+                       efile = new ERandomAccessFile(hostFile.toFile(), "r");
+               }
+       }
+
+
+       private void close() {
+               if (!mappedBuffers.isEmpty())
+                       throw new IllegalStateException("cannot close file; mapped buffers open");
+               if (efile != null) {
+                       try {
+                               FileStatistics.log("Closing " + hostFile.toFile());
+                               FileStatistics.executablesOpen--;
+                               efile.close();
+                       } catch (IOException e) {
+                               // ignore
+                       }
+               }
+               efile = null;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.exe.IExecutableSectionMapper#getSectionBuffer(org.eclipse.cdt.debug.edc.internal.symbols.exe.SectionInfo)
+        */
+       public IStreamBuffer getSectionBuffer(SectionInfo section) throws IOException {
+               
+               ensureOpen();
+
+               IStreamBuffer buffer = loadedSections.get(section);
+               if (buffer == null) {
+                       buffer = loadSection(section);
+                       
+                       loadedSections.put(section, buffer);
+                       // TODO: flush data occasionally, before #dispose()
+               }
+               
+               return buffer;
+       }
+
+       private IStreamBuffer loadSection(SectionInfo section)
+                       throws IOException {
+               FileStatistics.log("Loading " + section + " from " + hostFile.toFile());
+               
+               IStreamBuffer buffer = null;
+               
+               // If the sym file is too large, it's useless reading it 
+               // into the heap and choking the memory.
+               // Just read it on-demand from disk.
+               try {
+                       if (section.sectionSize > 4 * 1024 * 1024) {
+                               buffer = loadSectionIntoFileStreamBuffer(section);
+                       } else {
+                               buffer = loadSectionIntoHeap(section);
+                       }
+               } catch (IOException e) {
+                       buffer = loadSectionIntoHeap(section);
+               }
+               
+               return buffer;
+       }
+
+       /**
+        * Load section contents into a streaming buffer.  This is a little slower but 
+        * does not allocate any more than a page of memory at a time.
+        * 
+        * @param section
+        * @param buffer
+        * @return new {@link IStreamBuffer}
+        */
+       private IStreamBuffer loadSectionIntoFileStreamBuffer(SectionInfo section) throws IOException {
+               IStreamBuffer buffer = null;
+               try {
+                       buffer = new FileStreamBuffer(efile, isLE ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN, 
+                                       section.fileOffset, section.sectionSize);
+                       mappedBuffers.put(section, buffer);
+                       FileStatistics.currentMemoryMappedBuffers += buffer.capacity();
+                       FileStatistics.totalMemoryMappedBuffers += buffer.capacity();
+               } catch (Throwable e2) {
+                       EDCDebugger.getMessageLogger().logError("Failed to make buffer for section " + section, e2);
+               }
+               return buffer;
+       }
+
+       private IStreamBuffer loadSectionIntoHeap(SectionInfo section)
+                       throws IOException {
+               IStreamBuffer buffer;
+               // try to load the section into memory because it will
+               // be faster
+               byte[] data = new byte[(int)section.sectionSize];
+               efile.seek(section.fileOffset);
+               efile.read(data);
+               buffer = new MemoryStreamBuffer(data, isLE ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
+               FileStatistics.currentHeapAllocatedBuffers += data.length;
+               FileStatistics.totalHeapAllocatedBuffers += data.length;
+               return buffer;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.exe.ISectionMapper#releaseBuffer(java.nio.ByteBuffer)
+        */
+       public void releaseSectionBuffer(SectionInfo section) {
+               IStreamBuffer buffer = loadedSections.remove(section);
+               if (buffer != null) {
+                       if (mappedBuffers.remove(section) != null) {
+                               FileStatistics.currentMemoryMappedBuffers -= buffer.capacity();
+                               if (mappedBuffers.isEmpty()) {
+                                       close();
+                               }
+                       } else {
+                               FileStatistics.currentHeapAllocatedBuffers -= buffer.capacity();
+                       }
+               }
+       }
+       
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglerEABI.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglerEABI.java
new file mode 100644 (file)
index 0000000..aedc1dc
--- /dev/null
@@ -0,0 +1,1824 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import java.util.WeakHashMap;
+
+import org.eclipse.cdt.debug.edc.symbols.IUnmangler;
+
+/**
+ * Unmangler for the ARM/Itanium/etc. EABI (http://www.codesourcery.com/public/cxx-abi/abi.html)
+ * <p>
+ * TODO: <expression> <closure-type-name>  <lambda-sig>
+ */
+public class UnmanglerEABI implements IUnmangler {
+
+       private static boolean DEBUG = false;
+       
+       enum SubstType {
+               PREFIX,
+               TEMPLATE_PREFIX,
+               TYPE,
+               QUAL_TYPE,
+               TEMPLATE_TEMPLATE_PARAM,
+               
+       }
+       public UnmanglerEABI() {
+               
+       }
+
+       static class UnmangleState {
+               private char[] symbol;
+               private int index;
+               StringBuilder buffer;
+               private Stack<Integer> pushes ; // lengths of buffer when pushed 
+               private List<String> substitutions;
+               private Map<Integer, SubstType> substitutionTypes;
+               private int lastTypeNameIndex;
+               
+               private List<String> templateArgs;
+               private int templateArgBase;
+               private Stack<Integer> templateArgStack;        // length of templateArgs when pushed
+               
+               private Stack<Integer> backtracks ; // grouped entries: index value, lengths of buffer, and substitutions length when pushed 
+
+               private final boolean nameOnly;
+
+               public UnmangleState(String symbol, boolean nameOnly) {
+                       this.symbol = symbol.toCharArray();
+                       this.nameOnly = nameOnly;
+                       index = 0;
+                       buffer = new StringBuilder();
+                       pushes = new Stack<Integer>();
+                       substitutions = new ArrayList<String>();
+                       substitutionTypes = new HashMap<Integer, UnmanglerEABI.SubstType>();
+                       templateArgs = new ArrayList<String>();
+                       templateArgStack = new Stack<Integer>();
+                       backtracks = new Stack<Integer>();
+                       lastTypeNameIndex = -1;
+               }
+               
+               /* (non-Javadoc)
+                * @see java.lang.Object#toString()
+                */
+               @Override
+               public String toString() {
+                       String remaining = getRemaining();
+                       if (remaining.length() == 0)
+                               remaining = "<<end>>";
+                       return "state: at [" + remaining + "], so far: " + current();
+               }
+               
+               /**
+                * Push when entering a new decoding context (BNF expression).
+                */
+               public void push() {
+                       pushes.push(buffer.length());
+               }
+               
+               /**
+                * Pop the current decoded string and restore context to
+                * the calling context.
+                * @return decoded string
+                */
+               public String pop() {
+                       int oldpos = pushes.isEmpty() ? 0 : pushes.pop();
+                       String str = buffer.substring(oldpos, buffer.length());
+                       buffer.setLength(oldpos);
+                       return str;
+               }
+               
+               /**
+                * Push template argument state
+                */
+               public void pushTemplateArgs() {
+                       templateArgStack.push(templateArgBase);
+                       templateArgStack.push(templateArgs.size());
+               }
+               
+               /**
+                * Pop template argument state
+                * @throws UnmanglingException 
+                */
+               public void popTemplateArgs() throws UnmanglingException {
+                       try {
+                               templateArgs.subList(templateArgStack.pop(), templateArgs.size()).clear();
+                               templateArgBase = templateArgStack.pop();
+                       } catch (Exception e) {
+                               throw new UnmanglingException("template stack empty", buffer.toString());
+                       }
+               }
+               /**
+                * Push all state, when entering a possible backtrack scenario.
+                * Use #safePop() if an operation succeeds, or #safeBacktrack()
+                * if it failed and you want to retry.
+                */
+               public void safePush() {
+                       backtracks.push(index);
+                       backtracks.push(lastTypeNameIndex);
+                       backtracks.push(buffer.length());
+                       backtracks.push(substitutions.size());
+                       backtracks.push(pushes.size());
+               }
+               
+               /**
+                * Call when a #safePush() branch has succeeded to discard backtrack state.
+                */
+               public void safePop() {
+                       backtracks.pop();
+                       backtracks.pop();
+                       backtracks.pop();
+                       backtracks.pop();
+                       backtracks.pop();
+               }
+
+               /**
+                * Call when a #safePush() branch has failed to reset backtrack state.
+                * (To perform another backtrack, call #safePush() again)
+                */
+               public void safeBacktrack() {
+                       int oldSize = backtracks.pop();
+                       pushes.subList(oldSize, pushes.size()).clear();
+                       oldSize = backtracks.pop();
+                       substitutions.subList(oldSize, substitutions.size()).clear();
+                       while (substitutionTypes.size() > oldSize)
+                               substitutionTypes.remove(substitutionTypes.size() - 1);
+                       buffer.setLength(backtracks.pop());
+                       lastTypeNameIndex = backtracks.pop();
+                       index = backtracks.pop();
+               }
+
+               /**
+                * Tell if there is any current string (length > 0)
+                * @return
+                */
+               public boolean hasCurrent() {
+                       int oldpos = pushes.isEmpty() ? 0 : pushes.peek();
+                       int end = buffer.length();
+                       return end > oldpos;
+               }
+
+               /**
+                * Get the current constructed string (since the last #push())
+                * @return
+                */
+               public String current() {
+                       int oldpos = pushes.isEmpty() ? 0 : pushes.peek();
+                       String str = buffer.substring(oldpos, buffer.length());
+                       return str;
+               }
+
+               /**
+                * Remember the current constructed string as a substitution.
+                * @param substType
+                */
+               public void remember(SubstType substType) {
+                       remember(current(), substType);
+               }
+
+               public boolean lastSubstitutionIsPrefix(SubstType substType) {
+                       if (substitutions.size() == 0)
+                               return false;
+                       String current = current();
+                       if (substitutions.get(substitutions.size() - 1).length() >= current.length())
+                               return false;
+                       return lastSubstitution() == substType;
+               }
+               /**
+                * Remember the given string as a substitution.
+                * @param name
+                * @param substType
+                */
+               public void remember(String name, SubstType substType) {
+                       if (name.length() == 0)
+                               return;
+                       int num = substitutions.size();
+                       if (num > 0 && substitutions.get(num - 1).equals(name))
+                               return;
+                       substitutions.add(name);
+                       substitutionTypes.put(num, substType);
+                       lastTypeNameIndex = num;
+                       if (DEBUG) System.out.println(num+" := " + name + " --> " + substType);
+               }
+               
+               /**
+                * Replace the last substitution.
+                * @param name
+                * @param substType
+                */
+               public void rememberInstead(String name, SubstType substType) {
+                       int num = substitutions.size() - 1;
+                       substitutions.set(num, name);
+                       substitutionTypes.put(num, substType);
+                       if (DEBUG) System.out.println(num+" ::= " + name + " -- > " + substType);
+               }
+               
+               /**
+                * Pop the current decoded string as in {@link #pop()}
+                * and remember the string as a substitution.
+                * @return String
+                */
+               public String popAndRemember(SubstType substType) {
+                       String name = pop();
+                       remember(name, substType);
+                       return name;
+               }
+               
+               public char peek() {
+                       return index < symbol.length ? symbol[index] : 0;
+               }
+               
+               public char peek(int offset) {
+                       return index + offset < symbol.length ? symbol[index + offset] : 0;
+               }
+               
+               public void consume(char ch) throws UnmanglingException {
+                       if (ch != get())
+                               throw unexpected();
+               }
+               public char get() {
+                       return index < symbol.length ? symbol[index++] : 0;
+               }
+               
+               public void unget() {
+                       if (index > 0) index--;
+               }
+               public void skip() {
+                       if (index < symbol.length)
+                               index++;
+               }
+               
+               public void skip2() {
+                       index = Math.min(index + 2, symbol.length);
+               }
+               
+               public boolean done() {
+                       return index >= symbol.length;
+               }
+
+               public UnmanglingException unexpected() {
+                       return new UnmanglingException("Unexpected text at " + getRemaining(), buffer.toString());                      
+               }
+               public UnmanglingException unexpected(String what) {
+                       return new UnmanglingException("Wanted " + what + " but got unexpected text at " + getRemaining(), buffer.toString());                  
+               }
+               public UnmanglingException notImplemented() {
+                       return new UnmanglingException("Unimplemented at " + getRemaining(),
+                                       buffer.toString());                     
+               }
+
+               /**
+                * @return
+                */
+               private String getRemaining() {
+                       if (index >= symbol.length)
+                               return "";
+                       return new String(symbol, index, symbol.length - index);
+               }
+
+               /**
+                * @throws UnmanglingException 
+                * 
+                */
+               public void throwIfDone() throws UnmanglingException {
+                       if (done())
+                               throw new UnmanglingException("Unexpected end of symbol",
+                                               buffer.toString());
+               }
+
+               public void updateSubstitution(SubstType substType) {
+                       int num = substitutions.size() - 1;
+                       substitutionTypes.put(num, substType);
+                       if (DEBUG) System.out.println(num + " ::= " + substType);
+               }
+
+               /**
+                * @return
+                */
+               public SubstType lastSubstitution() {
+                       return substitutionTypes.get(substitutions.size() - 1);
+               }
+
+               /**
+                * @param arg
+                */
+               public void rememberTemplateArg(String arg) {
+                       templateArgs.add(arg);
+               }
+
+               /**
+                * @param num
+                * @return
+                * @throws UnmanglingException 
+                */
+               public String getTemplateArg(int num) throws UnmanglingException {
+                       num -= templateArgBase;
+                       if (num < 0 || num >= templateArgs.size())
+                               throw unexpected("template argument in range 0-" + (templateArgs.size() - templateArgBase)+"; got " + num);
+                       return templateArgs.get(num);
+               }
+
+               public String lastSubstitutedName() {
+                       if (lastTypeNameIndex < 0)
+                               return "";
+                       return substitutions.get(lastTypeNameIndex);
+               }
+       }
+
+       private static WeakHashMap<String, String> unmangledMap = new WeakHashMap<String, String>();
+       private static WeakHashMap<String, String> withoutArgsMap = new WeakHashMap<String, String>();
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IUnmangler#undecorate(java.lang.String)
+        */
+       public String undecorate(String symbol) {
+               // symbols may have @@GLIBC... type suffixes
+               int atat = symbol.indexOf("@@");
+               if (atat > 0)
+                       symbol = symbol.substring(0, atat);
+               return symbol;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IUnmangler#isMangled(java.lang.String)
+        */
+       public boolean isMangled(String symbol) {
+               if (symbol == null)
+                       return false;
+               if (symbol.startsWith("_Z"))
+                       return true;
+               // this is used for enum constants
+               if (symbol.startsWith("__N"))
+                       return true;
+               return false;
+       }
+
+       public String unmangleWithoutArgs(String symbol) throws UnmanglingException {
+               return unmangle(symbol, true);
+       }
+
+       public String unmangle(String symbol) throws UnmanglingException {
+               return unmangle(symbol, false);
+       }
+
+       public String unmangleType(String symbol) throws UnmanglingException {
+               if (symbol == null)
+                       return null;
+               
+               if (unmangledMap.containsKey(symbol))
+                       return unmangledMap.get(symbol);
+
+               if (symbol.startsWith("_Z")) {
+                       UnmangleState state = new UnmangleState(symbol, false);
+                       state.skip2();
+                       String unmangled = "";
+                       if (state.peek() == 'S') {
+                               unmangled += unmangleSubstitution(state);
+                       }
+                       while (!state.done()) {
+                               if (state.peek() == 'I') {
+                                       // unscoped-template-name
+                                       state.remember(unmangled, SubstType.TEMPLATE_PREFIX);
+                                       String args = unmangleTemplateArgs(state, false);
+                                       state.buffer.append(args);
+                                       unmangled += args;
+                               } else {
+                                       if (unmangled.equals("::std"))
+                                               unmangled += "::";
+                                       unmangled += unmangleType(state);
+                               }
+                               state.remember(unmangled, SubstType.TYPE);
+                       }
+                       unmangledMap.put(symbol, unmangled);
+                       return unmangled;
+               }
+               return symbol;
+       }
+
+       public String unmangle(String symbol, boolean skipArgs) throws UnmanglingException {
+               if (symbol == null)
+                       return null;
+               
+               String unmangled;
+
+               if (skipArgs) {
+                       if (withoutArgsMap.containsKey(symbol))
+                               unmangled = withoutArgsMap.get(symbol);
+                       else {
+                               unmangled = doUnmangle(symbol, true);
+                               withoutArgsMap.put(symbol, unmangled);
+                       }
+               } else if (unmangledMap.containsKey(symbol)) {
+                       unmangled = unmangledMap.get(symbol);
+               } else {
+                       unmangled = doUnmangle(symbol, skipArgs);
+                       unmangledMap.put(symbol, unmangled);
+
+                       do {// for break below if conditionals succeed
+                               int paren = unmangled.indexOf('(');
+                               if (0 < paren) {
+                                       String unmangledWithoutArgs = unmangled.substring(0, paren-1);
+                                       if (unmangledWithoutArgs != null && unmangledWithoutArgs.length() != 0) {
+                                               withoutArgsMap.put(symbol, unmangledWithoutArgs);
+                                               break;
+                               }       }
+                               withoutArgsMap.put(symbol, unmangled);
+                       } while (false);// allows break above to skip default case
+               }
+               
+               return unmangled;
+       }
+
+       /**
+        * @param symbol
+        * @return
+        * @throws UnmanglingException
+        */
+       private String doUnmangle(String symbol, boolean nameOnly) throws UnmanglingException {
+               /*
+ Entities with C linkage and global namespace variables are not mangled. Mangled names have the general structure:
+
+
+    <mangled-name> ::= _Z <encoding>
+    <encoding> ::= <function name> <bare-function-type>
+              ::= <data name>
+              ::= <special-name>
+                */
+               if (symbol.startsWith("_Z")) {
+                       String suffix = "";
+                       int idx = symbol.indexOf('@');
+                       if (idx >= 0) {
+                               suffix = symbol.substring(idx);
+                               symbol = symbol.substring(0, idx);
+                       }
+
+                       UnmangleState state = new UnmangleState(symbol, nameOnly);
+                       state.skip2();
+                       
+                       String unmangled = unmangleEncoding(state);
+                       unmangled += suffix;
+                       return unmangled;
+               } else if (symbol.startsWith("__N")) {
+                       UnmangleState state = new UnmangleState(symbol, true);
+                       state.skip2();
+                       
+                       String unmangled = unmangleName(state);
+                       return unmangled;
+               } else {
+                       return symbol;
+               }
+       }
+
+       /*
+    <encoding> ::= <function name> <bare-function-type>
+              ::= <data name>
+              ::= <special-name>
+        */
+       private String unmangleEncoding(UnmangleState state) throws UnmanglingException {
+               state.push();
+               
+               String name;
+               
+               // ferret out <special-name>
+               char ch = state.peek();
+               if (ch == 'T' || ch == 'G') {
+                       name = unmangleSpecialName(state);
+               } else {
+                       name = unmangleName(state);
+               }
+               
+               if (!state.done() && !state.nameOnly) {
+                       boolean isTemplate = name.endsWith(">");        // HACK
+                       if (isTemplate) {
+                               state.buffer.append(unmangleType(state));
+                               state.buffer.append(' ');
+                       }
+                       state.buffer.append(name);
+                       state.buffer.append(unmangleBareFunctionType(state, false));
+               } else {
+                       state.buffer.append(name);
+               }
+               
+               return state.pop();
+       }
+
+       private void unmangleSpecialNameCallOffset(UnmangleState state, char ch)
+               throws UnmanglingException {
+
+               switch (ch) {
+               case 'h': {
+                       // h <nv-offset> _
+                       int offset = doUnmangleNumber(state);
+                       state.consume('_');
+                       state.buffer.append("<non-virtual base override at offset ");
+                       appendHexNumber(state.buffer, offset);
+                       break;
+               }       
+               case 'v': {
+                       // v <offset number> _ <virtual offset number> _
+                       int offset = doUnmangleNumber(state);
+                       state.consume('_');
+                       int voffset = doUnmangleNumber(state);
+                       state.consume('_');
+                       state.buffer.append("<virtual base override at offset ");
+                       appendHexNumber(state.buffer, offset);
+                       state.buffer.append(", vcall offset ");
+                       appendHexNumber(state.buffer, voffset);
+                       break;
+               }
+               default:
+                       throw state.unexpected("special name call-offset");
+               }
+       }
+       
+       /*
+ <special-name> ::= TV <type>  # virtual table
+                ::= TT <type>  # VTT structure (construction vtable index)
+                ::= TI <type>  # typeinfo structure
+                ::= TS <type>  # typeinfo name (null-terminated byte string)
+  <special-name> ::= GV <object name>  # Guard variable for one-time initialization
+                       # No <type>
+  <special-name> ::= T <call-offset> <base encoding>
+                     # base is the nominal target function of thunk
+  <call-offset> ::= h <nv-offset> _
+                               ::= v <v-offset> _
+  <nv-offset> ::= <offset number>
+                     # non-virtual base override
+  <v-offset>  ::= <offset number> _ <virtual offset number>
+                     # virtual base override, with vcall offset
+  <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
+                     # base is the nominal target function of thunk
+                     # first call-offset is 'this' adjustment
+                     # second call-offset is result adjustment
+
+        */
+       private String unmangleSpecialName(UnmangleState state) throws UnmanglingException {
+               state.push();
+               
+               char ch = state.get();
+               if (ch == 'T') {
+                       String type = null;
+                       ch = state.get();
+                       switch (ch) {
+                       case 'V':
+                               type = unmangleType(state);
+                               state.buffer.append("<virtual table for ");
+                               state.buffer.append(type);
+                               state.buffer.append('>');
+                               break;
+                       case 'T':
+                               type = unmangleType(state);
+                               state.buffer.append("<VTT structure for ");
+                               state.buffer.append(type);
+                               state.buffer.append('>');
+                               break;
+                       case 'I':
+                               type = unmangleType(state);
+                               state.buffer.append("<typeinfo structure for ");
+                               state.buffer.append(type);
+                               state.buffer.append('>');
+                               break;
+                       case 'S':
+                               type = unmangleType(state);
+                               state.buffer.append("<typeinfo name for ");
+                               state.buffer.append(type);
+                               state.buffer.append('>');
+                               break;
+                       case 'h':
+                       case 'v':
+                               unmangleSpecialNameCallOffset(state, ch);
+                               state.buffer.append(" for ");
+                               state.buffer.append(unmangleEncoding(state));
+                               state.buffer.append('>');
+                               break;
+                       case 'c': {
+                               // c <call-offset> <call-offset> <base encoding>
+                               state.buffer.append("<covariant : 'this' adjustment ");
+                               unmangleSpecialNameCallOffset(state, state.get());
+                               state.buffer.append("> result adjustment ");
+                               unmangleSpecialNameCallOffset(state, state.get());
+                               state.buffer.append("> for ");
+                               state.buffer.append(unmangleEncoding(state));
+                               state.buffer.append('>');
+                               break;
+                       }
+                       default:
+                               throw state.unexpected("special name");
+                       }
+               } else if (ch == 'G') {
+                       switch (state.get()) {
+                       case 'V':
+                               state.buffer.append("<one-time-init guard for ");
+                               state.buffer.append(unmangleName(state));
+                               state.buffer.append('>');
+                               break;
+                       default:
+                               throw state.unexpected("special name");
+                       }
+               }
+               
+               return state.pop();
+       }
+
+       private void appendHexNumber(StringBuilder builder, int offset) {
+               if (offset < 0) {
+                       builder.append("-0x");
+                       builder.append(Integer.toHexString(-offset));
+               } else {
+                       builder.append("0x");
+                       builder.append(Integer.toHexString(offset));
+               }
+       }
+
+       /**
+        * @param state
+        * @param name
+        * @return
+        * @throws UnmanglingException 
+        */
+       private String doUnmangleFunctionWithName(UnmangleState state, boolean expectReturn, String name) throws UnmanglingException {
+               state.push();
+
+               state.consume('F');
+               
+               if (expectReturn) {
+                       state.buffer.append(unmangleType(state));
+                       state.buffer.append(' ');
+               }
+               
+               if (name != null)
+                       state.buffer.append(name);
+               
+               state.buffer.append(unmangleBareFunctionType(state, false));
+               
+               state.consume('E');
+               
+               return state.pop();
+       }
+
+       /**
+        * @param state
+        * @param expectReturn true if a return type precedes argument list
+        * @throws UnmanglingException 
+        */
+       private String unmangleBareFunctionType(UnmangleState state, boolean expectReturn) throws UnmanglingException {
+               state.push();
+               if (expectReturn) {
+                       state.buffer.append(unmangleType(state));
+                       state.buffer.append(' ');
+               }
+               state.buffer.append('(');
+               if (state.peek() == 'v') {
+                       state.skip();
+               } else {
+                       boolean first = true;
+                       while (!state.done() && state.peek() != 'E') {
+                               if (first) {
+                                       first = false;
+                               } else {
+                                       state.buffer.append(',');
+                               }
+                               state.buffer.append(unmangleType(state));
+                       }
+               }
+               state.buffer.append(')');
+               return state.pop();
+       }
+
+       /*
+    <name> ::= <nested-name>   = N ...
+          ::= <unscoped-name>          = number or St ...
+          ::= <unscoped-template-name> <template-args>         = unscoped | S ... | I ...
+          ::= <local-name>     # See Scope Encoding below              =  Z ...
+
+        */
+       private String unmangleName(UnmangleState state) throws UnmanglingException {
+               state.push();
+               char ch = state.peek();
+               if (ch == 'N') {
+                       state.buffer.append(unmangleNestedName(state, true));
+               } else if (ch == 'Z') {
+                       state.buffer.append(unmangleLocalName(state));
+               } else if (ch == 0) {
+                       state.throwIfDone();
+               } else {
+                       // must be unscoped-name or unscoped-template-name
+                       
+                       if (ch == 'S' && state.peek(1) == 't') {
+                               state.skip2();
+                               state.buffer.append("::std::");
+                       }
+                       String name = unmangleUnqualifiedName(state);
+                       state.buffer.append(name);
+                       if (state.peek() == 'I') {
+                               // unscoped-template-name
+                               state.remember(name, SubstType.TEMPLATE_PREFIX);
+                               String args = unmangleTemplateArgs(state, false);
+                               state.buffer.append(args);
+                               state.remember(name + args, SubstType.TYPE);
+                       }
+               }
+               return state.pop();
+       }
+       
+       /*
+ <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+               := Z <function encoding> E s [<discriminator>]
+
+  <discriminator> := _ <non-negative number>      # when number < 10
+                  := __ <non-negative number> _   # when number >= 10
+
+        */
+       private String unmangleLocalName(UnmangleState state) throws UnmanglingException {
+               state.push();
+               state.consume('Z');
+               state.buffer.append(unmangleEncoding(state));
+               state.consume('E');
+               
+               boolean isStringLiteral = false;
+               if (state.peek() == 's') {
+                       isStringLiteral = true;
+                       state.skip();
+                       if (state.peek() == '_')
+                               state.buffer.append("::");
+               } else {
+                       addNameWithColons(state, unmangleName(state));
+               }
+               if (state.peek() == '_') {
+                       state.skip();
+                       int num;
+                       if (state.peek() == '_') {
+                               // >= 10
+                               num = doUnmangleNonNegativeNumber(state);
+                               state.consume('_');
+                       } else {
+                               char ch = state.get();
+                               if (ch >= '0' && ch <= '9') {
+                                       num = ch - '0';
+                               } else {
+                                       throw state.unexpected("number");
+                               }
+                       }
+                       if (isStringLiteral)
+                               state.buffer.append("string literal");
+                       state.buffer.append("#" + num);
+               }
+               return state.pop();
+       }
+
+       /*
+    <source-name> ::= <positive length number> <identifier>
+    <number> ::= [n] <non-negative decimal integer>
+    <identifier> ::= <unqualified source code identifier>
+        */
+       private String unmangleSourceName(UnmangleState state) throws UnmanglingException {
+               state.push();
+               char ch = state.peek();
+               if (ch >= '0' && ch <= '9') {
+                       int length = doUnmangleNumber(state);
+                       while (length-- > 0) {
+                               state.throwIfDone();
+                               state.buffer.append(state.get());
+                       }
+                       return state.pop();
+               } else {
+                       throw state.unexpected();
+               }
+       }
+       
+       /*
+        * [0-9]+
+        */
+       private int doUnmangleNonNegativeNumber(UnmangleState state) {
+               int number = 0;
+               char ch;
+               while ((ch = state.get()) != 0 && ch >= '0' && ch <= '9') {
+                       number = number * 10 + (ch - '0');
+               }
+               state.unget();
+               return number;
+       }
+
+       /*
+        * [n] <non-negative decimal number>
+        */
+       private int doUnmangleNumber(UnmangleState state) {
+               boolean neg = false;
+               if (state.peek() == 'n') {
+                       state.skip();
+                       neg = true;
+               }
+               int number = doUnmangleNonNegativeNumber(state);
+               return neg ? -number : number;
+       }
+
+       /*
+    <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+                 ::= N [<CV-qualifiers>] <template-prefix> <template-args> E    (args = I...)
+
+        */
+       private String unmangleNestedName(UnmangleState state, boolean allowCV)
+               throws UnmanglingException {
+
+               state.push();
+               
+               state.consume('N');
+
+               String cvquals = allowCV ? unmangleCVQualifiers(state) : null;
+               
+               state.buffer.append(unmanglePrefix(state, SubstType.PREFIX));
+               
+               state.consume('E');
+               
+               if (allowCV && (cvquals != null && cvquals.length() > 0)) {
+                       state.buffer.append(' ');
+                       state.buffer.append(cvquals);
+               }
+               return state.pop();
+       }
+
+       
+       /*
+  <template-args> ::= I <template-arg>+ E
+
+        */
+       private String unmangleTemplateArgs(UnmangleState state, boolean substArg) throws UnmanglingException {
+               state.push();
+               
+               int origTypeIndex = state.lastTypeNameIndex;
+               
+               String typeName = state.lastSubstitutedName();
+               
+               if (!substArg || state.peek() == 'I') {
+                       state.consume('I');
+                       substArg = false;
+               }
+               state.buffer.append('<');
+               boolean lastArgWasSubst = false;
+               if (state.peek() != 'E') {
+                       boolean first = true;
+                       do {
+                               if (first)
+                                       first = false;
+                               else
+                                       state.buffer.append(',');
+                               boolean unfinishedTemplateSubst = false;
+                               if (state.peek() == 'S') {
+                                       char ch2 = state.peek(1);
+                                       if (ch2 == 't') {
+                                               state.buffer.append("::std::");
+                                               state.skip2();
+                                               first = true;
+                                               continue;       // more of this arg to come
+                                       }
+                                       lastArgWasSubst = true;
+                                       if (ch2 == 'a' || ch2 == 'b') {
+                                               unfinishedTemplateSubst = true;
+                                       }
+                               }
+                               String arg = unmangleTemplateArg(state);
+                               if (unfinishedTemplateSubst)
+                                       arg += unmangleTemplateArgs(state, false);
+                               state.buffer.append(arg);
+                               if (lastArgWasSubst && state.done())
+                                       break;
+                               lastArgWasSubst = false;
+                       } while (state.peek() != 'E');
+               }
+
+               if (!substArg && !lastArgWasSubst)
+                       state.consume('E');
+               
+               if (state.buffer.lastIndexOf(">") == state.buffer.length() - 1)
+                       state.buffer.append(' ');
+               state.buffer.append('>');
+               
+               if (state.lastSubstitution() == SubstType.TEMPLATE_TEMPLATE_PARAM)
+                       state.rememberInstead(typeName + state.current(), SubstType.TEMPLATE_TEMPLATE_PARAM);
+               else if (state.lastTypeNameIndex > origTypeIndex)
+                       state.remember(typeName + state.current(), SubstType.TYPE);
+               state.lastTypeNameIndex = origTypeIndex;
+               
+               return state.pop();
+       }
+
+       /*
+  <template-arg> ::= <type>                                        # type or template
+                 ::= X <expression> E                              # expression
+                 ::= <expr-primary>                                # simple expressions ('L')
+                 ::= I <template-arg>* E                           # argument pack
+                 ::= sp <expression>                               # pack expansion of (C++0x)
+
+        */
+       private String unmangleTemplateArg(UnmangleState state) throws UnmanglingException {
+               state.push();
+               
+               String arg = null;
+               char ch = state.peek();
+               if (ch == 'X') {
+                       throw state.notImplemented();
+               } else if (ch == 'I') {
+                       arg = unmangleTemplateArgs(state, false);
+               } else if (ch == 's' && state.peek(1) == 'p') {
+                       throw state.notImplemented();
+               } else if (ch == 'L') {
+                       arg = unmangleExprPrimary(state);
+               } else {
+                       arg = unmangleType(state);
+               }
+               state.rememberTemplateArg(arg);
+               state.buffer.append(arg);
+               
+               return state.pop();
+       }
+
+
+       /**
+<expr-primary> ::= L <type> <value number> E                          # integer literal
+                 ::= L <type> <value float> E                           # floating literal
+                 ::= L <string type> E                                  # string literal
+                 ::= L <nullptr type> E                                 # nullptr literal (i.e., "LDnE")
+                ::= L <type> <real-part float> _ <imag-part float> E   # complex floating point literal (C 2000)
+                 ::= L <mangled-name> E                                 # external name
+
+        * @param state
+        * @return
+        */
+       private String unmangleExprPrimary(UnmangleState state) throws UnmanglingException {
+               state.push();
+               state.consume('L');
+               
+               try {
+                       state.safePush();
+                       
+                       String type = null;
+                       String suffix = null;
+                       switch (state.peek()) {
+                       case 'i':       // int
+                               suffix = "";
+                               break;
+                       case 'j':       // unsigned int
+                               suffix = "U";
+                               break;
+                       case 'l':       // long
+                               suffix = "L";
+                               break;
+                       case 'm':       // unsigned long
+                               suffix = "UL";
+                               break;
+                       case 'x':       // long long
+                               suffix = "LL";
+                               break;
+                       case 'y':       // unsigned long long
+                               suffix = "ULL";
+                               break;
+                       }
+                       if (suffix != null) {
+                               state.skip();
+                               state.buffer.append(doUnmangleNumber(state));
+                               state.buffer.append(suffix);
+                       } else {
+                               // show other types
+                               type = unmangleType(state);
+                               state.buffer.append('(');
+                               state.buffer.append(type);
+                               state.buffer.append(')');
+                               state.buffer.append(doUnmangleNumber(state));
+                       }
+                       state.safePop();
+               } catch (UnmanglingException e) {
+                       state.safeBacktrack();
+                       
+                       // must be mangled-name or something else
+                       state.buffer.append(unmangleName(state));
+               }
+               state.consume('E');
+               
+               return state.popAndRemember(SubstType.TEMPLATE_TEMPLATE_PARAM);
+               
+       }
+       /*
+  <template-param> ::= T_      # first template parameter
+                  ::= T <parameter-2 non-negative number> _
+                  
+        */
+       private String unmangleTemplateParam(UnmangleState state) throws UnmanglingException {
+               state.push();
+               
+               state.consume('T');
+               int num = doUnmangleBase10(state);
+               state.buffer.append(state.getTemplateArg(num));
+               
+               return state.popAndRemember(SubstType.TEMPLATE_TEMPLATE_PARAM);
+       }
+
+       /**
+        * Base-10, where _ = 0 and 1..x = 0..x-1
+        * @param state
+        * @return
+        * @throws UnmanglingException 
+        */
+       private int doUnmangleBase10(UnmangleState state) throws UnmanglingException {
+               char ch;
+               if (state.peek() == '_') {
+                       state.skip();
+                       return 0;
+               }
+               int num = 0;
+               while ((ch = state.get()) != '_') {
+                       state.throwIfDone();
+                       num = (num * 10) + (ch - '0');
+               }
+               return num + 1;
+       }
+
+       /*
+  <substitution> ::= S <seq-id> _
+                ::= S_
+
+   <substitution> ::= St # ::std::
+   <substitution> ::= Sa # ::std::allocator
+   <substitution> ::= Sb # ::std::basic_string
+   <substitution> ::= Ss # ::std::basic_string < char,
+                                                ::std::char_traits<char>,
+                                                ::std::allocator<char> >
+   <substitution> ::= Si # ::std::basic_istream<char,  std::char_traits<char> >
+   <substitution> ::= So # ::std::basic_ostream<char,  std::char_traits<char> >
+   <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+                
+        */
+       private String unmangleSubstitution(UnmangleState state) throws UnmanglingException {
+               state.push();
+               state.consume('S');
+               
+               char ch = state.peek();
+               if (ch == '_' || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z')) {
+                       int num = doUnmangleBase36(state);
+                       if (num < 0 || num >= state.substitutions.size()) 
+                               throw state.unexpected("substitution id in the range 0-"+ state.substitutions.size() + " but got " + num);
+                       String val = state.substitutions.get(num);
+                       
+                       SubstType type = state.substitutionTypes.get(num);
+                       switch (type) {
+                       case PREFIX:
+                               //...?
+                               state.buffer.append(val);
+                               break;
+                       case TEMPLATE_PREFIX:
+                               state.buffer.append(val);
+                               state.buffer.append(unmangleTemplateArgs(state, true));
+                               break;
+                       case TEMPLATE_TEMPLATE_PARAM:
+                               state.buffer.append(val);
+                               break;
+                       case QUAL_TYPE:
+                       case TYPE:
+                               // ...?
+                               state.buffer.append(val);
+                               break;
+                       }
+               } else {
+                       switch (ch) {
+                       case 't':
+                               state.buffer.append("::std"); break;
+                       case 'a':
+                               state.buffer.append("::std::allocator"); break;
+                       case 'b':
+                               state.buffer.append("::std::basic_string"); break;
+                       case 's':
+                               state.buffer.append("::std::basic_string<char,::std::char_traits<char>,::std::allocator<char> >"); break;
+                       case 'i':
+                               state.buffer.append("::std::basic_istream<char,::std::char_traits<char> >"); break;
+                       case 'o':
+                               state.buffer.append("::std::basic_ostream<char,::std::char_traits<char> >"); break;
+                       case 'd':
+                               state.buffer.append("::std::basic_iostream<char,::std::char_traits<char> >"); break;
+                       default:
+                               throw state.unexpected("std:: substitution");
+                       }
+                       state.skip();
+               }
+               
+               return state.pop();
+       }
+
+       /**
+        * As a special case, the first substitutable entity is encoded as "S_",
+        * i.e. with no number, so the numbered entities are the second one as
+        * "S0_", the third as "S1_", the twelfth as "SA_", the thirty-eighth as
+        * "S10_", etc.
+        * @throws UnmanglingException 
+        */
+       private int doUnmangleBase36(UnmangleState state) throws UnmanglingException {
+               int num = 0;
+               char ch = state.peek();
+               if (ch == '_') {
+                       state.skip();
+                       return 0;
+               }
+               while ((ch = state.get()) != '_') {
+                       state.throwIfDone();
+                       num = (num * 10);
+                       if (ch >= '0' && ch <= '9')
+                               num += (ch - '0');
+                       else if (ch >= 'A' && ch <= 'Z')
+                               num += (ch - 'A') + 10;
+                       else
+                               throw state.unexpected("BASE-36 number");
+               }
+               return num + 1;
+       }
+
+       /*
+    <prefix> ::= <prefix> <unqualified-name>  # ... 0-9
+                ::= <template-prefix> <template-args>   --> template=T... args=I...
+             ::= <template-param>      --> T... 
+                ::= # empty
+                ::= <substitution>             --> S...
+             ::= <prefix> <data-member-prefix>  --> name M
+             
+     left-recursion elimination:
+     <prefix> ::= <template-prefix> <template-args> <prefix'>
+               ::= <template-param> <prefix'>
+               ::= <substitution> <prefix'>
+               ::= # empty
+     <prefix'> ::= <unqualified-name> <prefix'>
+                       ::= <data-member-prefix> M <prefix'>
+                       ::= #empty
+        */
+       private String unmanglePrefix(UnmangleState state, SubstType substType) throws UnmanglingException {
+               state.push();
+               
+               boolean any = false;
+               boolean lastSubst = false; 
+               
+               while (true) {
+                       char ch = state.peek();
+                       
+                       if (ch == 'E') {
+                               break;
+                       }
+                               
+                       String part = null;
+                       
+                       if (ch == 'T') {
+                               part = unmangleTemplateParam(state);
+                               state.remember(substType);
+                       }
+                       else if (ch == 'S') {
+                               part = unmangleSubstitution(state);
+                               lastSubst = true;
+                       } 
+                       else if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') 
+                                       || (ch == 'C' || ch == 'D' || ch == 'L')) {
+                               part = unmangleUnqualifiedName(state);
+                       }
+                       else if (ch == 'I') {
+                               if (!any)
+                                       throw state.unexpected();
+
+                               if (state.hasCurrent()) {
+                                       state.updateSubstitution(SubstType.TEMPLATE_PREFIX);
+                                       part = state.current();
+                               }
+                               String args = unmangleTemplateArgs(state, false);
+                               state.buffer.append(args);
+                               continue;
+                       }
+                       else {
+                               throw state.unexpected();
+                       }
+                       
+                       lastSubst = false;
+                       any = true;
+                       
+                       if (lastSubst)
+                               any = true;
+                       if (state.hasCurrent()) {
+                               addNameWithColons(state, part);
+                       } else {
+                               state.buffer.append(part);
+                       }
+                       
+                       if (ch != 'S' && state.peek() != 'E') {
+                               state.remember(substType);
+                       }
+               }
+               
+               
+               return state.pop();
+       }
+
+       /**
+        * @param state
+        * @param name
+        */
+       private void addNameWithColons(UnmangleState state, String name) {
+               if (state.hasCurrent() && !name.startsWith("::"))
+                       state.buffer.append("::");
+               state.buffer.append(name);
+       }
+
+       /*
+       <template-prefix> ::= <prefix> <template unqualified-name>  ... 0-9
+                         ::= <template-param>  # T*
+                         ::= <substitution>    # S*
+       --> followed by <template-args> (I)
+       
+       left-recursion elimination:
+         <template-prefix> ::= <template-param> <template-prefix'> # T*
+                         ::= <substitution> <template-prefix'> # S*
+         <template-prefix'> ::= <template unqualified-name> <template-prefix'> ... 0-9
+                                       ::= #empty
+       --> followed by <template-args> (I)
+        */
+       String unmangleTemplatePrefix(UnmangleState state) throws UnmanglingException {
+               state.push();
+               
+               char ch = state.peek();
+               if (ch == 'S') {
+                       state.buffer.append(unmangleSubstitution(state));
+                       state.buffer.append(unmangleTemplatePrefixPrime(state));
+                       return state.pop();
+               }
+               
+               if (ch == 'T') {
+                       state.buffer.append(unmangleTemplateParam(state));
+                       state.buffer.append(unmangleTemplatePrefixPrime(state));
+               }
+               
+               return state.popAndRemember(SubstType.TEMPLATE_PREFIX);
+       }
+
+       private String unmangleTemplatePrefixPrime(UnmangleState state) throws UnmanglingException {
+               state.push();
+               while (true) {
+                       try {
+                               state.buffer.append(unmangleUnqualifiedName(state));
+                               if (state.peek() == 'I') {
+                                       // unscoped-template-name
+                                       state.buffer.append(unmangleTemplateArgs(state, false));
+                               }
+                       } catch (UnmanglingException e) {
+                               break;
+                       }
+               }
+               
+               return state.pop();
+       }
+
+       /*
+<type> ::= <builtin-type>  = rVKPROCGU ...
+        ::= <function-type>   = 
+        ::= <class-enum-type>
+        ::= <array-type>
+        ::= <pointer-to-member-type>  = M...
+        ::= <template-param>
+        ::= <template-template-param> <template-args>
+        ::= <substitution> # See Compression below
+
+  <type> ::= <CV-qualifiers> <type>
+        ::= P <type>   # pointer-to
+        ::= R <type>   # reference-to
+        ::= O <type>   # rvalue reference-to (C++0x)
+        ::= C <type>   # complex pair (C 2000)
+        ::= G <type>   # imaginary (C 2000)
+        ::= U <source-name> <type>     # vendor extended type qualifier
+
+  <CV-qualifiers> ::= [r] [V] [K]      # restrict (C99), volatile, const
+        */
+       private String unmangleType(UnmangleState state) throws UnmanglingException {
+               state.push();
+               char ch = state.get(); 
+               switch (ch) {
+               //
+               // qualified types
+               //
+               case 'r':
+               case 'V':
+               case 'K':
+                       state.unget();
+                       String cvquals = unmangleCVQualifiers(state);
+                       state.buffer.append(unmangleType(state));
+                       if (cvquals.length() > 0) {
+                               state.buffer.append(' ');
+                               state.buffer.append(cvquals);
+                       }
+                       if (state.lastSubstitutionIsPrefix(SubstType.QUAL_TYPE))
+                               state.remember(SubstType.QUAL_TYPE);
+                       return state.popAndRemember(SubstType.QUAL_TYPE);
+               case 'P':
+                       state.buffer.append(unmangleType(state));
+                       if (state.lastSubstitutionIsPrefix(SubstType.QUAL_TYPE))
+                               state.remember(SubstType.QUAL_TYPE);
+                       ptrOrRefize(state.buffer, "*");
+                       return state.popAndRemember(SubstType.QUAL_TYPE);
+               case 'R':
+                       state.buffer.append(unmangleType(state));
+                       if (state.lastSubstitutionIsPrefix(SubstType.QUAL_TYPE))
+                               state.remember(SubstType.QUAL_TYPE);
+                       ptrOrRefize(state.buffer, "&");
+                       return state.popAndRemember(SubstType.QUAL_TYPE);
+               case 'O': // rvalue reference-to
+               case 'C': // complex pair
+               case 'G': // imaginary
+                       throw state.notImplemented(); 
+               case 'U': // vendor extension
+               {
+                       // TODO: assuming the extension precedes the type,
+                       // e.g. int __declspec(dllimport) foo();
+                       state.buffer.append(unmangleSourceName(state));
+                       state.buffer.append(' '); 
+                       state.buffer.append(unmangleType(state));
+                       return state.popAndRemember(SubstType.TYPE);
+               }
+               
+               //
+               // built-in types
+               //
+               case 'v':
+                       state.buffer.append("void"); break;
+               case 'w':
+                       state.buffer.append("wchar_t"); break;
+               case 'b':
+                       state.buffer.append("bool"); break;
+               case 'c':
+                       state.buffer.append("char"); break;
+               case 'a':
+                       state.buffer.append("signed char"); break;
+               case 'h':
+                       state.buffer.append("unsigned char"); break;
+               case 's':
+                       state.buffer.append("short"); break;
+               case 't':
+                       state.buffer.append("unsigned short"); break;
+               case 'i':
+                       state.buffer.append("int"); break;
+               case 'j':
+                       state.buffer.append("unsigned int"); break;
+               case 'l':
+                       state.buffer.append("long"); break;
+               case 'm':
+                       state.buffer.append("unsigned long"); break;
+               case 'x':
+                       state.buffer.append("long long"); break;
+               case 'y':
+                       state.buffer.append("unsigned long long"); break;
+               case 'n':
+                       state.buffer.append("__int128"); break;
+               case 'o':
+                       state.buffer.append("unsigned __int128"); break;
+               case 'f':
+                       state.buffer.append("float"); break;
+               case 'd':
+                       state.buffer.append("double"); break;
+               case 'e':
+                       state.buffer.append("long double"); break;
+               case 'g':
+                       state.buffer.append("__float128"); break;
+               case 'z':
+                       state.buffer.append("..."); break;
+               case 'D': {
+                       ch = state.get();
+                       switch (ch) {
+                       case 'd':
+                               state.buffer.append("::std::decimal::decimal64"); break;
+                       case 'e':
+                               state.buffer.append("::std::decimal::decimal128"); break;
+                       case 'f':
+                               state.buffer.append("::std::decimal::decimal32"); break;
+                       case 'h':
+                               state.buffer.append("::std::decimal::binary16"); break; // TODO: a guess; what's the actual C++ name for the half-float?
+                       case 'i':
+                               state.buffer.append("char32_t"); break;
+                       case 's':
+                               state.buffer.append("char16_t"); break;
+                       default:
+                               // Dp, Dt, DT
+                               state.unget(); throw state.notImplemented();
+                       }
+               }
+               case 'u':
+                       state.buffer.append(unmangleName(state)); 
+                       return state.popAndRemember(SubstType.TYPE);
+                       
+               //
+               // <class-enum-type> ::= <unqualified-name> | <nested-name>
+               //
+               case 'N':
+                       state.unget();
+                       state.buffer.append(unmangleNestedName(state, false));
+                       state.remember(SubstType.TYPE);
+                       break;
+                       
+               case 'F':
+                       // <function-type> ::= F [Y] <bare-function-type> E
+                       if (state.peek() == 'Y') {
+                               state.skip();
+                               state.buffer.append("extern \"C\" ");
+                       }
+                       state.buffer.append(unmangleBareFunctionType(state, true));
+                       state.consume('E');
+                       state.remember(SubstType.TYPE);
+                       break;
+                       
+               case 'M': {
+                       state.unget();
+                       String name = unmanglePtm(state);
+                       state.buffer.append(name); 
+                       state.remember(name, SubstType.TYPE);
+                       break;
+               }
+                       
+               case 'S':
+                       state.unget();
+                       state.buffer.append(unmangleSubstitution(state)); 
+                       break;
+                       
+               case 'T':
+                       // either <template-param> or <template-template-param> <template-args>
+                       state.unget();
+                       state.buffer.append(unmangleTemplateParam(state));
+                       if (state.peek() == 'I') {
+                               state.buffer.append(unmangleTemplateArgs(state, false));
+                       }
+                       break;
+                       
+               case 'A':
+                       state.unget();
+                       state.buffer.append(unmangleArrayType(state));
+                       break;
+                       
+               default:
+                       state.unget();
+                       String unqual = unmangleUnqualifiedName(state);
+                       state.buffer.append(unqual);
+                       if (state.peek() == 'I') {
+                               // unscoped-template-name
+                               state.remember(unqual, SubstType.TEMPLATE_PREFIX);
+                               state.buffer.append(unmangleTemplateArgs(state, false));
+                       }
+                       state.remember(SubstType.TYPE);
+                       break;
+               }
+               return state.pop();
+       }
+
+       
+       /**
+        * Insert a "*" or "&" into a string.  If this is a function type,
+        * insert in front of the argument list, not after.
+        * @param buffer
+        * @param string
+        */
+       private void ptrOrRefize(StringBuilder buffer, String string) {
+               char last = buffer.length() > 0 ? buffer.charAt(buffer.length() - 1) : 0;
+               if (last == ')' || last == ']') {
+                       char match = last == ')' ? '(' : '[';
+                       int stack = 0;
+                       int idx = buffer.length() - 1;
+                       while (idx > 0) {
+                               char ch = buffer.charAt(idx);
+                               if (ch == last)
+                                       stack++;
+                               else if (ch == match) {
+                                       stack--;
+                                       if (stack == 0) 
+                                               break;
+                               }
+                               idx--;
+                       }
+                       buffer.insert(idx, '(' + string + ')');
+               } else {
+                       buffer.append(string);
+               }
+       }
+
+       /*
+  <array-type> ::= A <positive dimension number> _ <element type>
+              ::= A [<dimension expression>] _ <element type>
+
+        */
+       private String unmangleArrayType(UnmangleState state) throws UnmanglingException {
+               state.push();
+               state.consume('A');
+               
+               String count; 
+               
+               char ch = state.peek();
+               if (ch >= '0' && ch <= '9') {
+                       int num = doUnmangleNonNegativeNumber(state);
+                       count = "" + num;
+               } else {
+                       throw state.notImplemented();
+               }
+               state.consume('_');
+               
+               state.buffer.append(unmangleType(state));
+               
+               state.buffer.append('[');
+               state.buffer.append(count);
+               state.buffer.append(']');
+               
+               return state.pop();
+       }
+
+       /*
+   <pointer-to-member-type> ::= M <class type> <member type>
+        */
+       private String unmanglePtm(UnmangleState state) throws UnmanglingException {
+               state.push();
+               state.consume('M');
+               String klass = unmangleType(state);
+               String ptrquals = unmangleCVQualifiers(state);
+               try {
+                       state.safePush();
+                       state.buffer.append(doUnmangleFunctionWithName(state, true, '(' + klass + "::*)"));
+                       state.safePop();
+               } catch (UnmanglingException e) {
+                       // may be pointer to member (field)
+                       state.safeBacktrack();
+                       state.buffer.append(unmangleType(state));
+                       state.buffer.append(' ');
+                       state.buffer.append(klass);
+                       state.buffer.append("::*");
+               }
+               if (ptrquals.length() > 0) {
+                       state.buffer.append(' ');
+                       state.buffer.append(ptrquals);
+               }
+               return state.pop();
+       }
+
+       /**
+        * Unmangle any sequence of CV quals 
+        * @param state state
+        * @return String
+        */
+       private String unmangleCVQualifiers(UnmangleState state) {
+               state.push();
+               while (true) {
+                       boolean matched = true;
+                       switch (state.peek()) {
+                       case 'r':
+                               state.skip();
+                               if (state.hasCurrent()) state.buffer.append(' ');
+                               state.buffer.append("restrict"); 
+                               break;
+                       case 'V':
+                               state.skip();
+                               if (state.hasCurrent()) state.buffer.append(' ');
+                               state.buffer.append("volatile"); 
+                               break;
+                       case 'K':
+                               state.skip();
+                               if (state.hasCurrent()) state.buffer.append(' ');
+                               state.buffer.append("const"); 
+                               break;
+                       default:
+                               matched = false;
+                               break;
+                       }
+                       if (!matched)
+                               break;
+               }
+               return state.pop();
+       }
+       
+       static class Operator {
+               String name;
+               /** for unary or binary ops; other questionable ones are 0 */
+               int numops;
+               
+               public Operator(String name, int numops) {
+                       this.name = name;
+                       this.numops = numops;
+               }
+       }
+       
+       static Map<String, Operator> operators = new HashMap<String, Operator>();
+       
+       private static void registerOperator(String code, String name, int opcnt) {
+               if (operators.containsKey(code))
+                       throw new IllegalStateException();
+               operators.put(code, new Operator(name, opcnt));         
+       }
+
+       static {
+               registerOperator("nw", "new", 0);
+               registerOperator("na", "new[]", 0);
+               registerOperator("dl", "delete", 0);
+               registerOperator("da", "delete[]", 0);
+               registerOperator("ps", "+", 1);
+               registerOperator("ng", "-", 1);
+               registerOperator("ad", "&", 1);
+               registerOperator("de", "*", 1);
+               registerOperator("co", "~", 1);
+               registerOperator("pl", "+", 2);
+               registerOperator("mi", "-", 2);
+               registerOperator("ml", "*", 2);
+               registerOperator("dv", "/", 2);
+               registerOperator("rm", "%", 2);
+               registerOperator("an", "&", 2);
+               registerOperator("or", "|", 2);
+               registerOperator("eo", "^", 2);
+               registerOperator("aS", "=", 2);
+               registerOperator("pL", "+=", 2);
+               registerOperator("mI", "-=", 2);
+               registerOperator("mL", "*=", 2);
+               registerOperator("dV", "/=", 2);
+               registerOperator("rM", "%=", 2);
+               registerOperator("aN", "&=", 2);
+               registerOperator("oR", "|=", 2);
+               registerOperator("eO", "^=", 2);
+               registerOperator("ls", "<<", 2);
+               registerOperator("rs", ">>", 2);
+               registerOperator("lS", "<<=", 2);
+               registerOperator("rS", ">>=", 2);
+               registerOperator("eq", "==", 2);
+               registerOperator("ne", "!=", 2);
+               registerOperator("lt", "<", 2);
+               registerOperator("gt", ">", 2);
+               registerOperator("le", "<=", 2);
+               registerOperator("ge", ">=", 2);
+               registerOperator("nt", "!", 1);
+               registerOperator("aa", "&&", 2);
+               registerOperator("oo", "||", 2);
+               registerOperator("pp", "++", 1);
+               registerOperator("mm", "--", 1);
+               registerOperator("cm", ",", 2);
+               registerOperator("pm", "->*", 2);
+               registerOperator("pt", "->", 2);
+               registerOperator("cl", "()", 1);
+               registerOperator("ix", "[]", 2);
+               registerOperator("qu", "?", 3);
+               registerOperator("st", "sizeof ", 0);   // type
+               registerOperator("sz", "sizeof", 1);    // expression
+               registerOperator("at", "alignof ", 0);  // type
+               registerOperator("az", "alignof", 1);   // expression
+               registerOperator("cv", "()", 1);
+       }
+       
+       /*
+    <unqualified-name> ::= <operator-name>                     = lowercase
+                       ::= <ctor-dtor-name>                    = C1-3 D0-2   ...
+                       ::= <source-name>                       = <number> ...
+                       ::= <unnamed-type-name>         = Ut ...
+
+        */
+       private String unmangleUnqualifiedName(UnmangleState state) throws UnmanglingException {
+               char ch = state.peek();
+               if (ch >= '0' && ch <= '9') {
+                       return unmangleSourceName(state);
+               }
+               else if (ch >= 'a' && ch <= 'z') {
+                       return unmangleOperatorName(state);
+               }
+               else if (ch == 'U') {
+                       return unmangleUnnamedTypeName(state);
+               }
+               else if (ch == 'C') {
+                       state.push();
+                       String last = simpleName(state.lastSubstitutedName());
+                       state.get();
+                       switch (state.get()) {
+                       case '1':
+                       case '2':
+                       case '3':
+                               state.buffer.append(last);
+                               return state.pop();
+                       default:
+                               state.unget();
+                               throw state.unexpected("constructor name");
+                       }
+               }
+               else if (ch == 'D') {
+                       state.push();
+                       String last = simpleName(state.lastSubstitutedName());
+                       state.get();    
+                       state.buffer.append('~');
+                       state.buffer.append(last);
+                       switch (state.get()) {
+                       case '0':
+                               return state.pop();
+                       case '1':
+                               return state.pop();
+                       case '2':
+                               return state.pop();
+                       default:
+                               state.unget();
+                               throw state.unexpected("destructor name");
+                       }
+               }
+               throw state.unexpected();
+       }
+
+       /**
+        * @param name
+        * @return
+        */
+       private String simpleName(String name) {
+               int idx = name.lastIndexOf("::");
+               if (idx >= 0)
+                       return name.substring(idx + 2);
+               return name;
+       }
+
+       /*
+  <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ 
+  <unnamed-type-name> ::= <closure-type-name>
+
+  <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ 
+
+        */
+       private String unmangleUnnamedTypeName(UnmangleState state) throws UnmanglingException {
+               state.push();
+               state.consume('U');
+               switch (state.get()) {
+               case 't':
+                       state.buffer.append("<unnamed #");
+                       if (state.peek() != '_') {
+                               state.buffer.append("" + (doUnmangleNonNegativeNumber(state) + 2));
+                       } else {
+                               state.buffer.append("1");
+                       }
+                       state.buffer.append('>');
+                       state.consume('_');
+                       break;
+               case 'l':
+                       throw state.notImplemented();
+               default:
+                       throw state.unexpected();
+               }
+               return state.pop();
+       }
+
+       /*
+        */
+       private String unmangleOperatorName(UnmangleState state) throws UnmanglingException {
+               state.push();
+               char ch = state.get();
+               String op = "" + ch;
+               if (ch == 'v') {
+                       // vendor type <digit> <source-name>
+                       ch = state.get();
+                       if (ch >= '0' && ch <= '9') {
+                               int opcount = ch - '0';
+                               op = unmangleSourceName(state);
+                               boolean first = true;
+                               
+                               // pretend it's a function, to differentiate
+                               state.buffer.append('(');
+                               while (opcount-- > 0) {
+                                       if (first)
+                                               first = false;
+                                       else
+                                               state.buffer.append(',');
+                               }
+                               state.buffer.append(')');
+                       } else {
+                               throw state.unexpected();
+                       }
+                       return state.pop();
+               }
+               
+               ch = state.get();
+               if (!Character.isLetter(ch)) {
+                       throw state.unexpected();
+               }
+               
+               op += ch;
+               
+               Operator oper = operators.get(op);
+               if (oper == null) {
+                       throw state.unexpected();
+               }
+               
+               state.buffer.append("operator ");
+               
+               // special cases
+               if (op.equals("cv")) {
+                       state.buffer.append(unmangleType(state));
+                       // fall through
+               }
+               
+               state.buffer.append(oper.name);
+               return state.pop();
+       
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglerWin32.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglerWin32.java
new file mode 100644 (file)
index 0000000..a33948a
--- /dev/null
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import org.eclipse.cdt.debug.edc.symbols.IUnmangler;
+
+/**
+ * Stub unmangler for Win32 symbols.  Big fat TODO
+ */
+public class UnmanglerWin32 implements IUnmangler {
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IUnmangler#undecorate(java.lang.String)
+        */
+       public String undecorate(String symbol) {
+               // remove standard underscore
+               if (symbol.startsWith("_")) {
+                       symbol = symbol.substring(1);
+               }
+               // and DLL import prefix
+               if (symbol.startsWith("_imp_")) {
+                       symbol = symbol.substring(5);
+               }
+               // and a stdcall/fastcall suffix
+               int at = symbol.lastIndexOf('@');
+               boolean isStdcall = false;
+               if (at > 0) {
+                       try {
+                               Integer.parseInt(symbol.substring(at+1));
+                               isStdcall = true;
+                       } catch (NumberFormatException e) {
+                       }
+               }
+               if (isStdcall) {
+                       symbol = symbol.substring(0, at);
+                       
+                       // and a fastcall prefix
+                       if (symbol.startsWith("@")) 
+                               symbol = symbol.substring(1);
+               }
+               return symbol;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IUnmangler#isMangled(java.lang.String)
+        */
+       public boolean isMangled(String symbol) {
+               return symbol != null && symbol.startsWith("?");
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IUnmangler#unmangleNameOnly(java.lang.String)
+        */
+       public String unmangleWithoutArgs(String symbol) throws UnmanglingException {
+               // big fat TODO
+               return symbol;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IUnmangler#unmangle(java.lang.String)
+        */
+       public String unmangle(String symbol) throws UnmanglingException {
+               // big fat TODO
+               return symbol;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.IUnmangler#unmangle(java.lang.String)
+        */
+       public String unmangleType(String symbol) throws UnmanglingException {
+               // big fat TODO
+               return symbol;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglerWin32EABI.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglerWin32EABI.java
new file mode 100644 (file)
index 0000000..c33f6f7
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+
+/**
+ * Unmangler for EABI symbols in a Win32 executable.
+ */
+public class UnmanglerWin32EABI extends UnmanglerWin32 {
+
+       private UnmanglerEABI eabiUnmangler = new UnmanglerEABI();
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.symbols.files.UnmanglerWin32#unmangle(java.lang.String)
+        */
+       @Override
+       public String unmangle(String symbol) throws UnmanglingException {
+               return eabiUnmangler.unmangle(symbol);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglingException.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/UnmanglingException.java
new file mode 100644 (file)
index 0000000..88a0a85
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.internal.symbols.files;
+
+import org.eclipse.cdt.debug.edc.symbols.IUnmangler;
+
+/**
+ * This exception is thrown by {@link IUnmangler#unmangle(String)}
+ * when decoding partially or fully fails.  A portion of the
+ * unmangled content may be retrieved.
+ */
+public class UnmanglingException extends Exception {
+
+       private static final long serialVersionUID = 3469819721317573378L;
+       private final String partialUnmangling;
+
+       public UnmanglingException(String message, String partialUnmangling) {
+               super(message);
+               this.partialUnmangling = partialUnmangling;
+       }
+       
+       /* (non-Javadoc)
+        * @see java.lang.Throwable#toString()
+        */
+       @Override
+       public String toString() {
+               return super.toString() + ": got " + partialUnmangling;
+       }
+       
+       public String getPartialUnmangling() {
+               return partialUnmangling;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/AbstractFinalLaunchSequence.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/AbstractFinalLaunchSequence.java
new file mode 100644 (file)
index 0000000..dc5f3a7
--- /dev/null
@@ -0,0 +1,943 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.launch;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.debug.edc.ITCFAgentLauncher;
+import org.eclipse.cdt.debug.edc.ITCFConnectionListener;
+import org.eclipse.cdt.debug.edc.ITCFServiceManager;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.TCFServiceManager;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Breakpoints;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Memory;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Processes;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl;
+import org.eclipse.cdt.debug.edc.services.IDSFServiceUsingTCF;
+import org.eclipse.cdt.debug.edc.services.Registers;
+import org.eclipse.cdt.debug.edc.tcf.extension.ProtocolConstants;
+import org.eclipse.cdt.debug.edc.tcf.extension.services.ISimpleRegisters;
+import org.eclipse.cdt.debug.edc.tcf.extension.services.SimpleRegistersProxy;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IPeer;
+import org.eclipse.tm.tcf.protocol.IService;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IMemory;
+import org.eclipse.tm.tcf.services.IProcesses;
+import org.eclipse.tm.tcf.services.IProcesses.DoneCommand;
+import org.eclipse.tm.tcf.services.IProcesses.DoneGetChildren;
+import org.eclipse.tm.tcf.services.IProcesses.DoneGetContext;
+import org.eclipse.tm.tcf.services.IProcesses.ProcessContext;
+import org.eclipse.tm.tcf.services.IRegisters;
+import org.eclipse.tm.tcf.services.IRunControl;
+import org.eclipse.tm.tcf.util.TCFTask;
+
+public abstract class AbstractFinalLaunchSequence extends Sequence {
+
+       private EDCLaunch launch;
+
+       protected DsfServicesTracker tracker;
+       protected List<Step> steps = new ArrayList<Step>();
+
+       /**
+        * The single TCF peer associated with this session. Do not reference this
+        * field explicitly except to set it. Use {@link #getTCFPeer()}
+        */
+       private IPeer tcfPeer;
+       
+       /**
+        * Attributes that the debugger requires the TCF peer to match. Derivatives
+        * populate this when we call {@link #specifyRequiredPeer()}
+        */
+       protected final Map<String, String> peerAttributes = new HashMap<String, String>();
+
+       /**********************************************
+        * Common steps
+        **********************************************/
+
+       // Common first step for the sequence
+       //
+       protected final Step trackerStep = new Step() {
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       tracker = new DsfServicesTracker(EDCDebugger.getDefault().getBundle().getBundleContext(), launch
+                                       .getSession().getId());
+                       requestMonitor.done();
+               }
+
+               @Override
+               public void rollBack(RequestMonitor requestMonitor) {
+                       if (tracker != null)
+                               tracker.dispose();
+                       tracker = null;
+                       requestMonitor.done();
+               }
+       };
+
+       // Common last step for the sequence
+       //
+       protected final Step cleanupStep = new Step() {
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       tracker.dispose();
+                       tracker = null;
+                       requestMonitor.done();
+               }
+       };
+
+       /**
+        * EDC currently only supports the scenario where a single TCF peer provides
+        * all the services needed by a debug session (ILaunch). It must provide the
+        * run-control service at a minimum (although other services are probably
+        * required, too). This step should be executed immediately after
+        * trackerStep.
+        */
+       protected Step initFindPeerStep = new Step() {
+               
+               @Override
+               public String getTaskName() {
+                       return "Find or launch TCF peer";
+               }
+
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       findPeer(requestMonitor);
+                       requestMonitor.done();
+               }
+       };
+
+       /**
+        * @since 2.0
+        */
+       protected Step rememberTCFChannelStep = new StepWithProgress() {
+
+               @Override
+               public String getTaskName() {
+                       return "Remember TCF Channel";
+               }
+
+               @Override
+               public void execute(RequestMonitor rm, IProgressMonitor pm) {
+                       try {
+                               IPeer peer = getTCFPeer();
+                               assert peer != null : "initFindPeerStep must be run prior to this one";
+       
+                               ITCFServiceManager tcfServiceManager = EDCDebugger.getDefault().getServiceManager();
+                               IChannel channel = tcfServiceManager.getChannelForPeer(peer);
+                               if (channel == null)
+                                       assert channel != null : "No open channel found to the peer";
+                               else
+                                       launch.usingTCFChannel(channel);
+                       }
+                       finally {
+                               rm.done();
+                       }
+               }
+
+       };
+
+       /**
+        * This step registers a listener that detects when the connection goes down.
+        * It invokes #handleConnectionClosed(), which by default terminates the 
+        * launch.
+        * @since 2.0
+        */
+       protected Step initDetectConnectionErrorStep = new Step() {
+               
+               class TCFConnectionListener implements ITCFConnectionListener {
+
+                       private IChannel myPeerChannel;
+                       
+                       public void peerChannelOpened(IPeer peer, IChannel channel) {
+                               if (peer == getTCFPeer()) {
+                                       myPeerChannel = channel;
+                               }
+                       }
+
+                       public void peerChannelClosed(IPeer peer, IChannel channel,
+                                       Throwable error) {
+                               if (peer == getTCFPeer() && channel == myPeerChannel) {
+                                       try {
+                                               handleConnectionClosed(channel, error);
+                                       } finally {
+                                               EDCDebugger.getDefault().getServiceManager().removeConnectionListener(this);
+                                       }
+                               }
+                       }
+               }
+               
+               final TCFConnectionListener peerListener = new TCFConnectionListener();
+               
+               @Override
+               public String getTaskName() {
+                       return "Init connection error listener";
+               }
+
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       
+                       // ensure we detect connection issues
+                       IPeer thePeer = getTCFPeer();
+                       if (thePeer != null) {
+                               EDCDebugger.getDefault().getServiceManager().addConnectionListener(peerListener);
+                               IChannel channel = EDCDebugger.getDefault().getServiceManager().getChannelForPeer(thePeer);
+                               if (channel != null && channel.getState() == IChannel.STATE_OPEN) {
+                                       peerListener.peerChannelOpened(thePeer, channel);
+                               }
+                       }
+                       
+                       requestMonitor.done();
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.concurrent.Sequence.Step#rollBack(org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+                */
+               @Override
+               public void rollBack(RequestMonitor rm) {
+                       EDCDebugger.getDefault().getServiceManager().removeConnectionListener(peerListener);
+                       super.rollBack(rm);
+               }
+       };
+
+       protected Step initRunControlStep = new Step() {
+
+               @Override
+               public String getTaskName() {
+                       return "Init RunControl service";
+               }
+
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       assert getTCFPeer() != null : "initFindPeerStep must be run prior to this one";
+                       RunControl runcontrol = tracker.getService(RunControl.class);
+                       findTCFServiceForDSFService(runcontrol, IRunControl.NAME, requestMonitor);
+                       requestMonitor.done();
+               }
+       };
+
+       /*
+        * Initialize Registers service.
+        */
+       protected Step initRegistersServiceStep = new Step() {
+
+               @Override
+               public String getTaskName() {
+                       return "Init Registers service";
+               }
+
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       IPeer peer = getTCFPeer();
+                       assert peer != null : "initFindPeerStep must be run prior to this one";
+
+                       final Registers registers = tracker.getService(Registers.class);
+                       
+                       ITCFServiceManager tcfServiceManager = EDCDebugger.getDefault().getServiceManager();
+                       final IChannel channel = tcfServiceManager.getChannelForPeer(peer);
+
+                       Protocol.invokeLater(new Runnable() {
+                               public void run() {
+                                       // First check if IRegisters service is provided.
+                                       // If not, look for ISimpleRegisters service.
+                                       //
+                                       IService regSvc = null;
+                                       try {
+                                               regSvc = getTCFService(IRegisters.NAME);
+                                       } catch (CoreException e) {
+                                               // ignore, look for SimpleRegisters service. 
+                                               // Report error when SimpleRegisters service is discarded...02/16/10
+                                       }
+
+                                       if (regSvc != null) { // registers service ready
+                                               registers.tcfServiceReady(regSvc);
+                                       }
+                                       else {  // look for ISimpleRegisters service.
+                                               try {
+                                                       regSvc = getTCFService(ISimpleRegisters.NAME);
+                                               } catch (CoreException e) {
+                                               }
+                                               if (regSvc == null) {
+                                                       requestMonitor.setStatus(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "Fail to find Registers service in agent."));
+                                               }
+                                               else {
+                                                       ISimpleRegisters simpleRegProxy = channel.getRemoteService(ISimpleRegisters.class);
+                                                       if (simpleRegProxy == null) {
+                                                               simpleRegProxy = new SimpleRegistersProxy(channel);
+                                                               channel.setServiceProxy(ISimpleRegisters.class, simpleRegProxy);
+                                                       }
+                                                       registers.tcfServiceReady(simpleRegProxy);
+                                               }
+                                       }
+                                       
+                                       requestMonitor.done();
+                               }
+                       });
+               }
+       };
+
+       /*
+        * Initialize the memory service
+        */
+       protected Step initMemoryServiceStep = new Step() {
+
+               @Override
+               public String getTaskName() {
+                       return "Init Memory service";
+               }
+
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       assert getTCFPeer() != null : "initFindPeerStep must be run prior to this one";
+                       Memory memory = tracker.getService(Memory.class);
+                       findTCFServiceForDSFService(memory, IMemory.NAME, requestMonitor);
+                       requestMonitor.done();
+               }
+       };
+
+       /**
+        * init breakpoints service.
+        */
+       protected Step initBreakpointsServiceStep = new Step() {
+
+               @Override
+               public String getTaskName() {
+                       return "Init Breakpoints service";
+               }
+
+               @Override
+               public void execute(RequestMonitor requestMonitor) {
+                       assert getTCFPeer() != null : "initFindPeerStep must be run prior to this one";
+                       Breakpoints breakpoints = tracker.getService(Breakpoints.class);
+                       findTCFServiceForDSFService(breakpoints,
+                                       org.eclipse.tm.tcf.services.IBreakpoints.NAME,
+                                       requestMonitor);
+
+                       requestMonitor.done();
+               }
+
+       };
+
+       /*
+        * Initialize the processes service
+        */
+       protected Step initProcessesServiceStep = new Step() {
+
+               @Override
+               public String getTaskName() {
+                       return "Init Processes service";
+               }
+
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       assert getTCFPeer() != null : "initFindPeerStep must be run prior to this one";
+                       Processes p = tracker.getService(Processes.class);
+                       findTCFServiceForDSFService(p, IProcesses.NAME, requestMonitor);
+                       requestMonitor.done();
+               }
+       };
+
+       /*
+        * Launch the process
+        */
+       protected Step launchStep = new Step() {
+
+               @Override
+               public String getTaskName() {
+                       return "Launch target";
+               }
+
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       assert getTCFPeer() != null : "initFindPeerStep must be run prior to this one";
+                       IService service;
+                       try {
+                               service = getTCFService(IProcesses.NAME);
+                       } catch (CoreException e1) {
+                               requestMonitor.setStatus(e1.getStatus());
+                               requestMonitor.done();
+                               return;
+                       }
+
+                       // Note that requestMonitor is passed down, so don't call
+                       // requestMonitor.done() here !
+                       launchProcess(launch, (IProcesses) service, requestMonitor);
+               }
+       };
+
+       /*
+        * Attach to a process
+        */
+       protected Step attachStep = new Step() {
+
+               @Override
+               public String getTaskName() {
+                       return "Attach";
+               }
+
+               @Override
+               public void execute(final RequestMonitor requestMonitor) {
+                       assert getTCFPeer() != null : "initFindPeerStep must be run prior to this one";
+                       IService service;
+                       try {
+                               service = getTCFService(IProcesses.NAME);
+                       } catch (CoreException e1) {
+                               requestMonitor.setStatus(e1.getStatus());
+                               requestMonitor.done();
+                               return;
+                       }
+
+                       // Note that requestMonitor is passed down, so don't call
+                       // requestMonitor.done() here !
+                       attachProcess(launch, (IProcesses) service, requestMonitor);
+               }
+       };
+
+       /**
+        * Get a particular service from the TCF peer associated with this launch
+        * 
+        * @param tcfServiceName
+        *            the name of the service
+        * @return the service or null if not available
+        * @throws CoreException
+        */
+       protected IService getTCFService(String tcfServiceName) throws CoreException {
+               TCFServiceManager tcfServiceManager = (TCFServiceManager) EDCDebugger.getDefault().getServiceManager();
+               return tcfServiceManager.getPeerService(getTCFPeer(), tcfServiceName);
+       }
+
+       /**
+        * Looks for a peer that matches the criteria set by the subclass, and puts
+        * it in {@link #tcfPeer} if successful. If more than one peer fits the
+        * bill, the subclass is given the chance to choose via
+        * {@link #selectPeer(IPeer[])}
+        * 
+        * @param requestMonitor
+        */
+       protected void findPeer(RequestMonitor requestMonitor) {
+               try {
+                       // We already found it. No-op
+                       if (getTCFPeer() != null) {
+                               return;
+                       }
+                       
+                       // See if subclass wants an explicit peer.
+                       if ((tcfPeer = selectExplicitPeer()) != null) {
+                               return;
+                       }
+                       
+                       // See if any already running (and discovered) peers fit the bill
+                       TCFServiceManager tcfServiceManager = (TCFServiceManager) EDCDebugger.getDefault().getServiceManager();
+                       boolean useLocalAgentOnly = useLocalAgentOnly();
+                       IPeer[] runningPeers = tcfServiceManager.getRunningPeers(IRunControl.NAME, peerAttributes, useLocalAgentOnly);
+                       if (runningPeers.length > 0) {
+                               int index = selectPeer(runningPeers);
+                               if (index >= 0 && index < runningPeers.length) {
+                                       tcfPeer = runningPeers[index];
+                                       return;
+                               }
+                       }
+
+                       // Invoke any registered agent-launchers which could make the
+                       // desired peer available.
+                       List<IPeer> launchedPeers = new ArrayList<IPeer>();
+                       ITCFAgentLauncher[] agentLaunchers = tcfServiceManager.findSuitableAgentLaunchers(IRunControl.NAME, peerAttributes, useLocalAgentOnly);
+                       for (ITCFAgentLauncher agentLauncher : agentLaunchers) {
+                               IPeer peer = tcfServiceManager.launchAgent(agentLauncher, peerAttributes);      // this could take a little while...
+                               if (peer != null) {
+                                       launchedPeers.add(peer);
+                               }
+                       }
+                       if (launchedPeers.size() > 0) {
+                               int index = selectPeer(launchedPeers.toArray(new IPeer[launchedPeers.size()]));
+                               if (index >= 0 && index < launchedPeers.size()) {
+                                       tcfPeer = launchedPeers.get(index);
+                                       return;
+                               }
+                       }
+                       
+                       requestMonitor.setStatus(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "Could not find a suitable TCF peer", null));
+               } catch (CoreException e) {
+                       requestMonitor.setStatus(e.getStatus());                                
+               }
+       }
+
+       /**
+        * Subclass may override this to select a peer that is not
+        * otherwise discovered by the Locator service.
+        * <p>
+        * If this returns non-<code>null</code>, this peer will be
+        * used instead of querying the locator service and using 
+        * {@link #selectPeer(IPeer[])}.  
+        * <p>
+        * By default, this returns <code>null</code>.
+        * @return an IPeer or <code>null</code>
+        * @throws CoreException if unable to select the desired explicit peer
+        * @since 2.0
+        */
+       protected IPeer selectExplicitPeer() throws CoreException {
+               return null;
+       }
+
+       /**
+        * Subclass should override this to select a peer from the array of peers
+        * which match the required minimum set of attributes specified by
+        * {@link #specifyRequiredPeer()}.  The default behavior is to use the first candidate.
+        * 
+        * <p>
+        * This methods represents a way for a specific launcher to do runtime peer
+        * selection. Choosing the right peer might require opening a channel to it
+        * to determine more detailed capabilities than what's available via its
+        * attributes. Or perhaps some additional decision making is required, not
+        * requiring a channel--e.g., more closely examining one of the peer
+        * attributes. Either way, {@link #specifyRequiredPeer()} provides the
+        * <i>minimum</i> set of attributes a peer should have to be considered for
+        * the launch. This method is used to provide further and final pruning of
+        * any candidates.
+        * 
+        * @param peers
+        *            the candidates
+        * @return the index of the peer to use; if the returned value is outside
+        *         the range of candidates, then none of the peers are used.
+        * @since 2.0
+        */
+       public int selectPeer(IPeer[] peers) {
+               assert peers.length > 0;
+               return 0;
+       }
+
+       /**
+        * Find the given TCF service and link it to the given DSF service. The TCF
+        * service will be used to carry out the DSF one.
+        * 
+        * <p>
+        * Note caller must call the "rm.done".
+        * 
+        * @param dsfService
+        * @param tcfServiceName
+        *            TCF service required
+        * @param tcfPeerAttrs
+        *            TCF peer attributes required to match.
+        * @param rm
+        */
+       protected void findTCFServiceForDSFService(IDSFServiceUsingTCF dsfService, String tcfServiceName,
+                       RequestMonitor rm) {
+
+               try {
+                       IService service = getTCFService(tcfServiceName);
+                       if (service == null)
+                               throw EDCDebugger.newCoreException("Required service \"" + tcfServiceName + "\" is not available.");
+                       
+                       dsfService.tcfServiceReady(service);
+               } catch (CoreException e1) {
+                       if (e1.getStatus().matches(IStatus.CANCEL))
+                               rm.cancel();
+                       rm.setStatus(e1.getStatus());
+               }
+       }
+
+       /**
+        * @since 2.0
+        */
+       public AbstractFinalLaunchSequence(DsfExecutor executor, EDCLaunch launch, IProgressMonitor pm) {
+               this(executor, launch, pm, "Configuring Debugger", "Aborting configuring debugger");
+       }
+
+       /**
+        * 
+        * @param executor
+        * @param launch
+        * @param pm
+        * @param sequenceName
+        *            name to display in the progress monitor when the sequence is
+        *            running.
+        * @param abortName
+        *            name to display in the progress monitor when the sequence is
+        *            aborting due to error.
+        * @param useLocalAgentOnly
+        *            whether to ignore peers from remote hosts
+        * @since 2.0
+        */
+       public AbstractFinalLaunchSequence(DsfExecutor executor, EDCLaunch launch, IProgressMonitor pm,
+                       String sequenceName, String abortName) {
+               super(executor, pm, sequenceName, abortName);
+               this.launch = launch;
+               specifyRequiredPeer();
+       }
+
+       @Override
+       public Step[] getSteps() {
+               return steps.toArray(new Step[steps.size()]);
+       }
+
+       /**
+        * This method is invoked by the the step
+        * {@link AbstractFinalLaunchSequence#launchStep} to launch the thing to be
+        * debugged. The base implementation knows how to carry out the launch via a
+        * TCF IProcesses service. When dealing with an agent that doesn't provide
+        * that service (typically the case for embedded bareboard debugging), the
+        * subclass must override this method to inject its custom launch logic.
+        * 
+        * @param launch
+        *            the launch object
+        * @param ps
+        *            the TCF processes service; operation will fail if null
+        * @param requestMonitor
+        *            monitor to invoke when processing is done
+        */
+       protected void launchProcess(final ILaunch launch, final IProcesses ps, final RequestMonitor requestMonitor) {
+               try {
+                       ILaunchConfiguration cfg = launch.getLaunchConfiguration();
+
+                       // Get absolute program path.
+                       ICProject cproject = LaunchUtils.getCProject(cfg);
+                       // This works even if cproject is null.
+                       IPath program = LaunchUtils.verifyProgramPath(cfg, cproject); 
+                       final String file = program.toOSString();
+
+                       final String workingDirectory = LaunchUtils.getWorkingDirectoryPath(cfg);
+                       final String[] args = LaunchUtils.getProgramArgumentsArray(cfg);
+                       final Map<String, String> env = LaunchUtils.getEnvironmentVariables(cfg);
+                       final boolean append = cfg.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
+                       final boolean attach = false;
+
+                       final IProcesses.DoneGetEnvironment done_env = new IProcesses.DoneGetEnvironment() {
+                               public void doneGetEnvironment(IToken token, Exception error, Map<String, String> def) {
+                                       if (error != null) {
+                                               requestMonitor.setStatus(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), error
+                                                               .getLocalizedMessage(), error));
+                                               requestMonitor.done();
+                                               return;
+                                       }
+                                       final Map<String, String> vars = new HashMap<String, String>();
+                                       if (append)
+                                               vars.putAll(def);
+                                       if (env != null)
+                                               vars.putAll(env);
+                                       Protocol.invokeAndWait(new Runnable() {
+                                               public void run() {
+                                                       ps.start(workingDirectory, file, args, vars, attach, new IProcesses.DoneStart() {
+                                                               public void doneStart(IToken token, Exception error, ProcessContext process) {
+                                                                       if (error != null) {
+                                                                               requestMonitor.setStatus(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(),
+                                                                                               error.getLocalizedMessage(), error));
+                                                                               requestMonitor.done();
+                                                                               return;
+                                                                       }
+               
+                                                                       requestMonitor.done();
+                                                               }
+                                                       });
+                                       }
+                                       });
+                               }
+                       };
+
+                       if (append) {
+                               Protocol.invokeLater(new Runnable() {
+                                       public void run() {
+                                               ps.getEnvironment(done_env);
+                                       }
+                               });
+                       } else {
+                               done_env.doneGetEnvironment(null, null, null);
+                       }
+               } catch (Exception x) {
+                       requestMonitor.setStatus(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), x
+                                       .getLocalizedMessage(), x));
+                       requestMonitor.done();
+               }
+       }
+
+       public void attachProcess(EDCLaunch launch, IProcesses service, RequestMonitor requestMonitor) {
+
+               try {
+                       int pid = launch.getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_ATTACH_PROCESS_ID, -1);
+
+                       String preTargetedID = Integer.toString(pid);
+                       
+                       // 1) get process list from agent (getChildren)
+                       String[] processes = getProcessList(service);
+                       int numProcesses = processes.length;
+                       // 2) get contexts for each ID
+                       ChooseProcessItem[] items = null;
+                       ProcessContext[] contexts = null;
+
+                       items = new ChooseProcessItem[numProcesses];
+                       contexts = new ProcessContext[numProcesses];
+
+                       for (int i = 0; i < numProcesses; i++) {
+                               contexts[i] = getProcessContext(processes[i], service);
+                               String procID = contexts[i].getProperties().get(ProtocolConstants.PROP_OS_ID).toString();
+                               if (procID == null)
+                                       procID = "unknown";
+                               ChooseProcessItem item = new ChooseProcessItem(procID, contexts[i].getName());
+                               items[i] = item;
+                       }
+
+                       int selectedIndex = 0;
+                       if (pid == -1)
+                       {
+                               // 3) bring up dialog to choose which process
+                               ChooseProcessItem selected = chooseProcess(items, "");
+                               for (selectedIndex = 0; selectedIndex < numProcesses; selectedIndex++) {
+                                       if (selected.processID.equals(items[selectedIndex].processID))
+                                               break;
+                               }
+                       }
+                       else
+                       {
+                               for (int i = 0; i < contexts.length; i++) {
+                                       String procID = (String) contexts[i].getProperties().get(ProtocolConstants.PROP_OS_ID);
+                                       if (procID.equals(preTargetedID))
+                                       {
+                                               selectedIndex = i;
+                                               break;
+                                       }
+                               }
+
+                       }
+
+                       // 4) attach
+                       doAttachTask(contexts[selectedIndex]);
+
+               } catch (CoreException e) {
+                       if (e.getStatus().matches(IStatus.CANCEL))
+                               requestMonitor.cancel();
+                       else {
+                               requestMonitor.setStatus(e.getStatus());
+                       }
+               }
+
+               requestMonitor.done();
+       }
+
+       /**
+        * Call TCF to carry out the attach.
+        * 
+        * @param context
+        * @throws CoreException
+        */
+       protected void doAttachTask(final ProcessContext context) throws CoreException {
+               final TCFTask<Object> task = new TCFTask<Object>() {
+                       public void run() {
+                               context.attach(new DoneCommand() {
+                                       public void doneCommand(IToken token, Exception error) {
+                                               if (error == null)
+                                                       done(this);
+                                               else
+                                                       error(error);
+                                       }
+                               });
+                       }
+               };
+               try {
+                       task.getE();
+               } catch (Error e) {
+                       String msg = "failed to attach to process: " + context.getID() + ", caused by: "
+                                       + e.getCause().getMessage();
+                       if (!task.isCancelled()) {
+                               EDCDebugger.getMessageLogger().logError(msg, e);
+                               throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), msg, e));
+                       } else {
+                               throw new CoreException(Status.CANCEL_STATUS);
+                       }
+               }
+       }
+
+       protected ProcessContext getProcessContext(final String processID, final IProcesses service) throws CoreException {
+               final TCFTask<IProcesses.ProcessContext> task = new TCFTask<IProcesses.ProcessContext>() {
+
+                       public void run() {
+                               service.getContext(processID, new DoneGetContext() {
+
+                                       public void doneGetContext(IToken token, Exception error, ProcessContext context) {
+                                               if (error == null)
+                                                       done(context);
+                                               else
+                                                       error(error);
+                                       }
+                               });
+                       }
+
+               };
+               try {
+                       return task.getE();
+               } catch (Error e) {
+                       String msg = "failed to create context for process: " + processID + ", caused by: "
+                                       + e.getCause().getMessage();
+                       if (!task.isCancelled()) {
+                               EDCDebugger.getMessageLogger().logError(msg, e);
+                               throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), msg, e));
+                       } else {
+                               throw new CoreException(Status.CANCEL_STATUS);
+                       }
+               }
+       }
+
+       /**
+        * @throws CoreException 
+        * @since 2.0
+        */
+       protected ProcessContext getProcessContextByName(String contextName,
+                       IProcesses ps) throws CoreException {
+               final String[] contextIDs = getProcessList(ps);
+               for (String contextID : contextIDs) {
+                       ProcessContext context = getProcessContext(contextID, ps);
+                       if (context.getName().equals(contextName))
+                               return context;
+               }
+               return null;
+       }
+
+       /**
+        * Get list of running processes from the target.
+        * 
+        * @param service
+        *            TCF processes service.
+        * @return array of IDs which are internal IDs created by debugger for the
+        *         processes, not process ID in the target OS.
+        * @throws CoreException
+        */
+       protected String[] getProcessList(final IProcesses service) throws CoreException {
+               TCFTask<String[]> task = new TCFTask<String[]>() {
+
+                       public void run() {
+                               service.getChildren(null, false, new DoneGetChildren() {
+
+                                       public void doneGetChildren(IToken token, Exception error, String[] contextIds) {
+                                               if (error == null)
+                                                       done(contextIds);
+                                               else
+                                                       error(error);
+                                       }
+                               });
+                       }
+               };
+
+               String[] ids;
+               try {
+                       ids = task.getE();
+               } catch (Error e) {
+                       String msg = "failed to get process list from target,  caused by: " + e.getCause().getMessage();
+                       if (!task.isCancelled()) {
+                               EDCDebugger.getMessageLogger().logError(msg, e);
+                               throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), msg, e));
+                       } else {
+                               throw new CoreException(Status.CANCEL_STATUS);
+                       }
+               }
+
+               if (ids.length == 0) {
+                       String msg = "Failed to get running processes from target";
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), msg, null));
+               }
+               return ids;
+       }
+
+       /**
+        * TODO: This requires UI dialog. We need to either 1. make this abstract so
+        * that each EDC-based debugger can do its own implementation (pending
+        * unification of attach code for TRK & Windows), or 2. provide a common
+        * dialog as IStatusHandler extension.
+        * 
+        * @param processes
+        * @param defaultSelection
+        * @return
+        * @throws CoreException
+        */
+       protected ChooseProcessItem chooseProcess(final ChooseProcessItem[] processes, String defaultSelection)
+                       throws CoreException {
+               // temp stub.
+               return null;
+       }
+
+       /**
+        * Specify attributes the debugger requires from the underlying TCF peer.
+        * Only peers with those attributes will be considered for this debug
+        * session. This method is called by the abstract class during construction
+        * of the object. The implementation should add the required attributes to
+        * {@link #peerAttributes}
+        */
+       abstract protected void specifyRequiredPeer();
+
+       /**
+        * Return the single TCF peer associated with this debug session (ILaunch).
+        * EDC currently only supports the scenario where a single TCF peer provides
+        * all the services needed by a session. The peer is that from
+        * {@link #selectExplicitPeer()} or chosen from the Locator service 
+        * using attributes from {@link #specifyRequiredPeer()} and filtered
+        * by {@link #selectPeer(IPeer[])}.
+        * <p>
+        * 
+        * @return the peer. Will return null if called before the
+        *         {@link #initFindPeerStep} step has executed.
+        * @since 2.0 a subclass can no longer override this method if it wants to explicitly provide the
+        * peer: override {@link #selectExplicitPeer()} instead.
+        */
+       protected final IPeer getTCFPeer() {
+               return tcfPeer;
+       }
+
+       /**
+        * Tell whether to match local peers or possibly remote peers.
+        * <p>
+        * This routine is called during the {@link #findPeer(RequestMonitor)}
+        * step to indicate whether this sequence will consider TCF peers detected on other 
+        * machines.  This check occurs only when no explicit peer is returned by {@link #selectExplicitPeer()}.
+        * @return <code>true</code> to filter remote agents (whose {@link IPeer#ATTR_IP_HOST} does not lie on
+        * a local network interface) or <code>false</code> to accept any peer matching {@link #peerAttributes}. 
+        * @since 2.0
+        */
+       abstract protected boolean useLocalAgentOnly();
+       
+       /**
+        * Default handler for connection errors that terminates the launch.
+        * This runs on the dispatch thread.
+        * @param channel the channel associated with the peer
+        * @param error error, possibly <code>null</code>
+        * @since 2.0
+        */
+       protected void handleConnectionClosed(IChannel channel, Throwable error) {
+               if (launch != null && !launch.isTerminated()) {
+                       if (error != null) {
+                               EDCDebugger.getMessageLogger().logError("Connection lost; terminating debug session", error);
+                       }
+                       launch.shutdownSession(new RequestMonitor(ImmediateExecutor.getInstance(), null));
+               }
+       }
+       
+       /**
+        * @since 2.0
+        */
+       public EDCLaunch getLaunch() {
+               return launch;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/AgentSettings.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/AgentSettings.java
new file mode 100644 (file)
index 0000000..079ac63
--- /dev/null
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.launch;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.cdt.debug.edc.tcf.extension.services.ISettings;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.util.TCFTask;
+
+/**
+ * @noimplement
+ * @noextend
+ */
+public class AgentSettings {
+
+       private final ISettings settingsService;
+
+       /**
+        * @since 2.0
+        */
+       public AgentSettings(ISettings settingsService) {
+               this.settingsService = settingsService;
+       }
+
+       public ISettings getSettingsService() {
+               return settingsService;
+       }
+
+       /**
+        * @since 2.0
+        */
+       public String[] getSettingIds() throws IOException {
+               TCFTask<String[]> task = new TCFTask<String[]>() {
+
+                       public void run() {
+
+                               settingsService.getIds(new ISettings.DoneGetSettingIds() {
+
+                                       public void doneGetSettingIds(IToken token, Exception error, String[] ids) {
+                                               if (error != null) {
+                                                       error(error);
+                                               } else {
+                                                       if (ids.length > 0)
+                                                               System.out.println(Arrays.deepToString(ids));
+                                                       done(ids);
+                                               }
+                                       }
+                               });
+                       }
+                       
+               };
+               return task.getIO();
+       }
+
+       /**
+        * @since 2.0
+        */
+       public void setSettings(final String context, final String[] ids, final Object[] values) throws IOException {
+               
+               TCFTask<Object> task = new TCFTask<Object>() {
+
+                       public void run() {
+
+                               settingsService.setValues(context, ids, values, 
+                               new ISettings.DoneSetSettingValues() {
+
+                                       public void doneSetSettingValues(IToken token, Exception error) {
+                                               if (error != null)
+                                                       error(error);
+                                               else
+                                                       done(null);
+                                       }
+                               });
+                       }
+                       
+               };
+               task.getIO();
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/ChooseProcessItem.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/ChooseProcessItem.java
new file mode 100644 (file)
index 0000000..1b65d68
--- /dev/null
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.launch;
+
+/**
+ * Class to hold process information (ID, name) for the ChooseProcessDialog
+ */
+public class ChooseProcessItem {
+       public String processID;
+       public String processName;
+
+       public ChooseProcessItem(String id, String name) {
+               this.processID = id;
+               this.processName = name;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/DebugServicesFactory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/DebugServicesFactory.java
new file mode 100644 (file)
index 0000000..a09fddf
--- /dev/null
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.launch;
+
+import org.eclipse.cdt.debug.edc.internal.launch.CSourceLookup;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Breakpoints;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Noop;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Expressions;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.INoop;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Memory;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Processes;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Signals;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Snapshots;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Symbols;
+import org.eclipse.cdt.debug.edc.services.Disassembly;
+import org.eclipse.cdt.debug.edc.services.ISnapshots;
+import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
+import org.eclipse.cdt.dsf.debug.service.AbstractDsfDebugServicesFactory;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
+import org.eclipse.cdt.dsf.debug.service.IDisassembly;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IModules;
+import org.eclipse.cdt.dsf.debug.service.IProcesses;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.ISignals;
+import org.eclipse.cdt.dsf.debug.service.ISourceLookup;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.ISymbols;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.debug.core.ILaunch;
+
+public abstract class DebugServicesFactory extends AbstractDsfDebugServicesFactory {
+
+       public DebugServicesFactory() {
+
+       }
+
+       @Override
+       @SuppressWarnings("unchecked")
+       public <V> V createService(Class<V> clazz, DsfSession session, Object... optionalArguments) {
+               if (ITargetEnvironment.class.isAssignableFrom(clazz)) {
+                       for (Object arg : optionalArguments)
+                               if (arg instanceof ILaunch)
+                                       return (V) createTargetEnvironmentService(session, ((ILaunch) arg));
+               }
+               if (Snapshots.class.isAssignableFrom(clazz)) {
+                       return (V)createSnapshotsService(session);
+               }
+               
+               // Used for testing
+               if (INoop.class.isAssignableFrom(clazz)) {
+                       return (V) new Noop(session);
+               }
+
+               return super.createService(clazz, session, optionalArguments);
+       }
+
+       /**
+        * EDC requires adopters to provide an {@link ITargetEnvironment} service.
+        * 
+        * @param session
+        *            the DSF session the service will be used in
+        * @param launch
+        *            the launch object which spawned the DSF session. It's likely
+        *            the launch's configuration will be needed to service some of
+        *            the ITargetEnvironment methods.
+        * @return the DSF service
+        */
+       abstract protected ITargetEnvironment createTargetEnvironmentService(DsfSession session, ILaunch launch);
+
+       /**
+        * EDC requires adopters to provide an {@link IStack} service.
+        * 
+        * @param session
+        *            the DSF session the service will be used in
+        * @return the DSF service
+        */
+       abstract protected IStack createStackService(DsfSession session);
+
+       /**
+        * EDC requires adopters to provide an {@link IRegisters} service.
+        * 
+        * @param session
+        *            the DSF session the service will be used in
+        * @return the DSF service
+        */
+       abstract protected IRegisters createRegistersService(DsfSession session);
+
+       @Override
+       protected ISourceLookup createSourceLookupService(DsfSession session) {
+               return new CSourceLookup(session);
+       }
+
+       @Override
+       protected IRunControl createRunControlService(DsfSession session) {
+               return new RunControl(session);
+       }
+
+       @Override
+       protected IMemory createMemoryService(DsfSession session) {
+               return new Memory(session);
+       }
+
+       @Override
+       protected IBreakpoints createBreakpointService(DsfSession session) {
+               return new Breakpoints(session);
+       }
+
+       @Override
+       protected IDisassembly createDisassemblyService(DsfSession session) {
+               return new Disassembly(session, new String[0]);
+       }
+
+       @Override
+       protected IExpressions createExpressionService(DsfSession session) {
+               return new Expressions(session);
+       }
+
+       @Override
+       protected IModules createModulesService(DsfSession session) {
+               return new Modules(session);
+       }
+
+       @Override
+       protected IProcesses createProcessesService(DsfSession session) {
+               return new Processes(session);
+       }
+
+       @Override
+       protected ISignals createSignalsService(DsfSession session) {
+               return new Signals(session);
+       }
+
+       @Override
+       protected ISymbols createSymbolsService(DsfSession session) {
+               return new Symbols(session);
+       }
+
+       protected ISnapshots createSnapshotsService(DsfSession session) {
+               return new Snapshots(session);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/EDCLaunch.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/EDCLaunch.java
new file mode 100644 (file)
index 0000000..dba5e24
--- /dev/null
@@ -0,0 +1,775 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.launch;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.debug.core.sourcelookup.AbsolutePathSourceContainer;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.ExecutablesSourceContainer;
+import org.eclipse.cdt.debug.edc.internal.PathUtils;
+import org.eclipse.cdt.debug.edc.internal.launch.ShutdownSequence;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Processes;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExitedEvent;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.RootExecutionDMC;
+import org.eclipse.cdt.debug.edc.internal.snapshot.Album;
+import org.eclipse.cdt.debug.edc.internal.snapshot.SnapshotUtils;
+import org.eclipse.cdt.debug.edc.snapshot.IAlbum;
+import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.debug.model.DsfLaunch;
+import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlockRetrieval;
+import org.eclipse.cdt.dsf.debug.service.IDsfDebugServicesFactory;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
+import org.eclipse.cdt.dsf.debug.sourcelookup.DsfSourceLookupDirector;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IMemoryBlockRetrieval;
+import org.eclipse.debug.core.model.ISourceLocator;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.containers.DirectorySourceContainer;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IPeer;
+import org.eclipse.tm.tcf.protocol.Protocol;
+
+/**
+ * The only object in the model that implements the traditional interfaces.
+ */
+@ThreadSafe
+abstract public class EDCLaunch extends DsfLaunch {
+       private DefaultDsfExecutor executor;
+       private final DsfSession session;
+       private DsfServicesTracker tracker;
+       private boolean initialized;
+       private boolean shutDown;
+       private boolean isLaunching;
+       private boolean isTerminating;
+
+       private DsfMemoryBlockRetrieval memRetrieval;
+       private IDsfDebugServicesFactory serviceFactory;
+       private final String debugModelID;
+       private String description;
+       private Album album;
+       private boolean snapshotSupportInitialized;
+       private boolean isFirstLaunch = true;
+       private ILaunchConfiguration activeLaunchConfiguration;
+       private List<ILaunchConfiguration> affiliatedLaunchConfigurations = Collections.synchronizedList(new ArrayList<ILaunchConfiguration>());
+       private boolean isTerminatedThanDisconnected = false;
+       private boolean shuttingDown;
+
+       private static final Map<EDCLaunch, List<IChannel>> launchChannels = Collections
+                       .synchronizedMap(new HashMap<EDCLaunch, List<IChannel>>());
+
+       private static final Map<String, EDCLaunch> launchSessions = Collections
+                       .synchronizedMap(new HashMap<String, EDCLaunch>());
+
+       /**
+        * Every EDC (DSF) session has a thread pool in which to delegate blocking
+        * code to. See AbstractEDCService.asyncExec()
+        */
+       private static final Map<String, ExecutorService> threadPools = Collections
+               .synchronizedMap(new HashMap<String, ExecutorService>());
+
+       public EDCLaunch(ILaunchConfiguration launchConfiguration, String mode, ISourceLocator locator, String ownerID) {
+               super(launchConfiguration, mode, locator);
+
+               debugModelID = ownerID;
+
+               // Create the dispatch queue to be used by debugger control and services
+               // that belong to this launch
+               final DefaultDsfExecutor dsfExecutor = new DefaultDsfExecutor("DSF executor - " + ownerID); //$NON-NLS-1$
+               dsfExecutor.prestartCoreThread();
+               executor = dsfExecutor;
+               session = DsfSession.startSession(executor, ownerID);
+               launchSessions.put(session.getId(), this);
+               
+               threadPools.put(session.getId(), newThreadPool());
+       }
+
+       /**
+        * Obtains a new thread pool
+        */
+       private ThreadPoolExecutor newThreadPool() {
+               // Thread pools can be a tricky thing. The behaviors available for
+               // ThreadPoolExecutor are particularly so. Grab a handful of
+               // aspirin and read the class javadoc if you're up for it. Basically,
+               // what we're going to do here is create a thread pool that hopes to
+               // meet demand with three threads. It will use a queue to allow itself
+               // to be backlogged by a maximum of 10,000 requests. If the requests
+               // keep pouring in and the backlog limit is blown, the pool will
+               // dispatch up to three additional threads (for a total of six) to try
+               // to handle the load. If it still can't keep up after that, then it
+               // throws up its hands and starts rejecting requests. We need to protect
+               // ourselves from exhausting cpu/system resources (a million threads) or
+               // memory (millions of backlogged requests). A coding or runtime mishap
+               // could lead to either if we don't set limits on the thread pool. But
+               // what are reasonable limits? The best we can do is set some values we
+               // think will work, use checks to make us or the user aware when they
+               // don't, and give the user a backdoor mechanism to tweak the values
+               // until we can provide better default values.
+               //
+               // Also, keep in mind that the thread pool will try to trim down the
+               // number of threads if and when it has had to resort to creating
+               // additional ones to handle a heavy load. If a thread is idle for more
+               // than ten seconds, it will be shut down.
+
+               int coreThreadCount = getBackdoorValue("org.eclipse.cdt.edc.poolthread.coreThreadCount", 3);
+               int maxThreadCount = getBackdoorValue("org.eclipse.cdt.edc.poolthread.maxThreadCount", coreThreadCount + 3);
+               long idleLimit = getBackdoorValue("org.eclipse.cdt.edc.poolthread.idleLimit", 10);
+               int queueLimit = getBackdoorValue("org.eclipse.cdt.edc.poolthread.queueLimit", 10000);
+               
+           return new ThreadPoolExecutor(coreThreadCount, maxThreadCount,
+                   idleLimit, TimeUnit.SECONDS,
+                   new ArrayBlockingQueue<Runnable>(queueLimit));
+       }
+
+       /**
+        * Provide a backdoor mechanism for tweaking the thread pool parameters on
+        * the field. Hopefully this will never be needed, but better safe than
+        * sorry.
+        */
+       private static int getBackdoorValue(String prop, int defaultVal) {
+               String value = System.getProperty(prop);
+               if (value != null) {
+                       try {
+                               return Integer.parseInt(value);
+                       }
+                       catch (NumberFormatException exc){}
+               }
+               return defaultVal;
+       }
+       
+
+       public static EDCLaunch getLaunchForSession(String sessionID) {
+               return launchSessions.get(sessionID);
+       }
+
+       /**
+        * See {@link #threadPools}
+        * @since 2.0
+        */
+       public static ExecutorService getThreadPool(String sessionID) {
+               return threadPools.get(sessionID);
+       }
+
+       public DsfExecutor getDsfExecutor() {
+               return executor;
+       }
+
+       public IDsfDebugServicesFactory getServiceFactory() {
+               return serviceFactory;
+       }
+
+       public void initialize() {
+               Runnable initRunnable = new DsfRunnable() {
+                       public void run() {
+                               tracker = new DsfServicesTracker(EDCDebugger.getDefault().getBundle().getBundleContext(), session
+                                               .getId());
+                               session.addServiceEventListener(EDCLaunch.this, null);
+                               memRetrieval = null;
+                               initialized = true;
+                               fireChanged();
+                       }
+               };
+
+               // Invoke the execution code and block waiting for the result.
+               try {
+                       executor.submit(initRunnable).get();
+               } catch (Exception e) {
+                       EDCDebugger.getMessageLogger().log(
+                                       new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+                                                       "Error initializing launch", e)); //$NON-NLS-1$
+               }
+       }
+
+       public void initializeMemoryRetrieval() throws CoreException {
+               // Create a memory retrieval and register it with the session
+               try {
+                       executor.submit(new Callable<Object>() {
+                               public Object call() throws CoreException {
+                                       memRetrieval = new DsfMemoryBlockRetrieval(getDebugModelID(), getLaunchConfiguration(), session);
+                                       session.registerModelAdapter(IMemoryBlockRetrieval.class, memRetrieval);
+                                       return null;
+                               }
+                       }).get();
+               } catch (InterruptedException e) {
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, 0,
+                                       "Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$
+               } catch (ExecutionException e) {
+                       throw (CoreException) e.getCause();
+               } catch (RejectedExecutionException e) {
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, 0,
+                                       "Debugger shut down before launch was completed.", e)); //$NON-NLS-1$
+               }
+       }
+
+       public DsfSession getSession() {
+               return session;
+       }
+
+       public DsfMemoryBlockRetrieval getMemoryBlockRetrieval() {
+               return memRetrieval;
+       }
+
+       public void setServiceFactory(IDsfDebugServicesFactory factory) {
+               serviceFactory = factory;
+       }
+
+       // Event handler when a thread or a threadGroup exits
+       @DsfServiceEventHandler
+       public void eventDispatched(IExitedDMEvent e) {
+               // Only shutdown the session if the RootDMC is exited, namely all processDMCs 
+               // are terminated or disconnected.
+               if (! (e instanceof ExitedEvent))
+                       return;
+               
+               // Synchronize here in case a launch delegate is trying to do more
+               // launching at the same time.
+               synchronized (this)
+               {
+                       if (e.getDMContext() instanceof RootExecutionDMC && !isLaunching()) {
+                               // Don't terminate the launch if a delegate has already started
+                               // using it for new activity.
+                               // The ExitedEvent tells us whether the last context in the launch
+                               // is terminated or disconnected.
+                               setTerminating(true);
+                               isTerminatedThanDisconnected = ((ExitedEvent)e).isTerminatedThanDisconnected();
+                               shutdownSession(new RequestMonitor(ImmediateExecutor.getInstance(), null));
+                       }
+               }
+       }
+
+       // /////////////////////////////////////////////////////////////////////////
+       // IServiceEventListener
+       @DsfServiceEventHandler
+       public void eventDispatched(ICommandControlShutdownDMEvent event) {
+               shutdownSession(new RequestMonitor(ImmediateExecutor.getInstance(), null));
+       }
+
+       // /////////////////////////////////////////////////////////////////////////
+       // ITerminate
+       @Override
+       public boolean canTerminate() {
+               return initialized && !shutDown;
+       }
+
+       @Override
+       public boolean isTerminated() {
+               // This return value is irrelevant to whether the session
+               // is terminated or disconnected.
+               return shutDown;
+       }
+
+       @Override
+       public void terminate() throws DebugException {
+               // Step one, tell the run control service to terminate everything
+               DsfExecutor dsfExecutor = getDsfExecutor();
+               if (dsfExecutor != null) {
+                       setTerminating(true);
+                       getDsfExecutor().execute(new Runnable() {
+                               public void run() {
+                                       RunControl runControlService = tracker
+                                                       .getService(RunControl.class);
+                                       if (runControlService != null)
+                                               runControlService.terminateAllContexts(null);
+                               }
+                       });
+               }
+       }
+
+       // ITerminate
+       // /////////////////////////////////////////////////////////////////////////
+
+       // /////////////////////////////////////////////////////////////////////////
+       // IDisconnect
+       @Override
+       public boolean canDisconnect() {
+               return !(snapshotSupportInitialized && isSnapshotLaunch()) && canTerminate();
+       }
+
+       @Override
+       public boolean isDisconnected() {
+               // Indicates whether the launch (session) is terminated 
+               // by "disconnect" command.
+               return isTerminated() && ! isTerminatedThanDisconnected;
+       }
+
+       @Override
+       public void disconnect() throws DebugException {
+               DsfExecutor dsfExecutor = getDsfExecutor();
+               if (dsfExecutor != null) {
+               getDsfExecutor().execute(new Runnable() {
+                   public void run() {
+                       Processes procService = tracker.getService(Processes.class);
+                       if (procService != null)
+                               procService.detachDebuggerFromSession(null);
+                   }
+               });
+               }
+       }
+
+       // IDisconnect
+       // /////////////////////////////////////////////////////////////////////////
+
+       /**
+        * Shuts down the services, the session and the executor associated with
+        * this launch.
+        * <p>
+        * Note: The argument request monitor to this method should NOT use the
+        * executor that belongs to this launch. By the time the shutdown is
+        * complete, this executor will not be dispatching anymore and the request
+        * monitor will never be invoked. Instead callers should use the
+        * {@link ImmediateExecutor}.
+        * </p>
+        * 
+        * @param rm
+        *            The request monitor invoked when the shutdown is complete.
+        */
+       @ConfinedToDsfExecutor("getSession().getExecutor()")
+       public void shutdownSession(final RequestMonitor rm) {          
+               if (shutDown || shuttingDown || executor == null) {
+                       rm.done();
+                       return;
+               }
+
+               shuttingDown = true;
+
+               // Shut down the thread pool, otherwise its core threads might hang
+               // around indefinitely.
+               ExecutorService pool = threadPools.get(session.getId());
+               if (pool != null) {
+                       pool.shutdown();
+                       try {
+                               // We need to wait for the threads actively handling a task
+                               // to complete. If we proceed with the session shutdown before
+                               // that, the active threads are likely to encounter problem as
+                               // they try to operate within a defunct session. Don't wait
+                               // indefinitely, though. Note that this does not block the 
+                               // UI from showing the session as terminated. For the most part,
+                               // things on the surface should look like the debug session
+                               // ended. Obviously, cleanup will be pending.
+                               pool.awaitTermination(15, TimeUnit.SECONDS);
+                       } catch (InterruptedException exc) {
+                               EDCDebugger.getMessageLogger().logException(exc);
+                       }
+               }
+
+               Sequence shutdownSeq = new ShutdownSequence(getDsfExecutor(), session.getId(), new RequestMonitor(session
+                               .getExecutor(), rm) {
+                       @Override
+                       public void handleCompleted() {
+                               session.removeServiceEventListener(EDCLaunch.this);
+                               if (!isSuccess()) {
+                                       EDCDebugger.getMessageLogger().log(
+                                                       new MultiStatus(EDCDebugger.PLUGIN_ID, -1, new IStatus[] { getStatus() },
+                                                                       "Session shutdown failed", null)); //$NON-NLS-1$
+                               }
+                               // Last order of business, shutdown the dispatch queue.
+                               if (tracker != null)
+                                       tracker.dispose();
+                               tracker = null;
+                               DsfSession.endSession(session);
+
+                               // DsfMemoryBlockRetrieval.saveMemoryBlocks();
+                               if (memRetrieval != null) {
+                                       memRetrieval.saveMemoryBlocks();
+                               }
+
+                               // endSession takes a full dispatch to distribute the
+                               // session-ended event, finish step only after the dispatch.
+                               executor.shutdown();
+                               executor = null;
+                               fireTerminate();
+
+                               try {
+                                       closeUnusedChannels();
+                               } catch (Throwable e) {
+                                       EDCDebugger.getMessageLogger().logError(null, e);
+                               }
+
+                               shutDown = true;
+
+                               rm.setStatus(getStatus());
+                               rm.done();
+                       }
+               });
+               executor.execute(shutdownSeq);
+
+               try {
+                       ILaunchConfiguration activeLaunchConfig = getLaunchConfiguration();
+
+                       if (activeLaunchConfig.getAttribute(IEDCLaunchConfigurationConstants.ATTR_IS_ONE_USE, false))
+                               activeLaunchConfig.delete();
+
+                       if (isSnapshotLaunch()) {
+                               // delete launch configuration
+                               ILaunchConfiguration lc = SnapshotUtils.findExistingLaunchForAlbum(album);
+                               if (lc != null){
+                                       lc.delete();
+                               }
+                       }
+               } catch (Throwable e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+       }
+
+       protected void closeUnusedChannels() {
+               synchronized (launchChannels) {
+                       List<IChannel> channelList = launchChannels.get(this);
+                       launchChannels.remove(this);
+                       if (channelList == null)
+                               return;
+
+                       Collection<List<IChannel>> remainingChannels = launchChannels.values();
+                       for (List<IChannel> list : remainingChannels) {
+                               channelList.removeAll(list);
+                       }
+                       for (final IChannel channel : channelList) {
+                               Protocol.invokeAndWait(new Runnable() {
+                                       public void run() {
+                                               channel.close();
+                                       }
+                               });
+                       }
+               }
+       }
+
+       @SuppressWarnings("rawtypes")
+       @Override
+       public Object getAdapter(Class adapter) {
+               // Must force adapters to be loaded.
+               Platform.getAdapterManager().loadAdapter(this, adapter.getName());
+               return super.getAdapter(adapter);
+       }
+
+       public String getDebugModelID() {
+               return debugModelID;
+       }
+
+       public void usingTCFChannel(IChannel channel) {
+               synchronized (launchChannels) {
+                       List<IChannel> channelList = launchChannels.get(this);
+                       if (channelList == null) {
+                               channelList = new ArrayList<IChannel>();
+                       }
+                       if (!channelList.contains(channel))
+                               channelList.add(channel);
+                       launchChannels.put(this, channelList);
+               }
+       }
+
+       public IAlbum getAlbum() {
+               return album;
+       }
+
+       public void setAlbum(IAlbum album) {
+               this.album = (Album) album;
+       }
+
+       public boolean isSnapshotLaunch() {
+               // this is not set in run mode
+               if (ILaunchManager.DEBUG_MODE.equals(getLaunchMode()))
+                       assert snapshotSupportInitialized;
+               return album != null;
+       }
+
+       public ISourceLocator getExecutableLocator() {
+               CSourceLookupDirector director = new CSourceLookupDirector();
+               director.initializeParticipants();
+               try {
+                       if (isSnapshotLaunch()) {
+                               getAlbum().configureSourceLookupDirector(director);
+                       } else {
+                               String exePath = getLaunchConfiguration().getAttribute(
+                                               ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, "");
+                               director.setSourceContainers(createExecutableLocatorSourceContainers(exePath));
+                       }
+               } catch (CoreException e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+               return director;
+       }
+
+       /**
+        * @since 2.0
+        */
+       protected ISourceContainer[] createExecutableLocatorSourceContainers(String exePath) {
+               List<ISourceContainer> containers = new ArrayList<ISourceContainer>();
+               containers.add(new AbsolutePathSourceContainer());
+               if (exePath.length() > 0)
+               {
+                       IPath exeDirectory = new Path(exePath).removeLastSegments(1);
+                       containers.add(new DirectorySourceContainer(exeDirectory, false));
+               }
+               containers.add(new ExecutablesSourceContainer());
+               return containers.toArray(new ISourceContainer[containers.size()]);
+       }
+
+       public void initializeSnapshotSupport() {
+               try {
+                       String albumFile = getLaunchConfiguration().getAttribute(IEDCLaunchConfigurationConstants.ATTR_ALBUM_FILE,
+                                       "");
+                       IPath albumPath = PathUtils.createPath(albumFile);
+                       if (albumPath.toFile().exists()) {
+                               album = Album.getAlbumByLocation(albumPath);
+                               if (album == null) {
+                                       album = new Album();
+                                       album.setLocation(albumPath);
+                                       album.loadAlbum(false);
+                               }
+                               album.setSessionID(session.getId());
+
+                               IAlbum album = Album.getAlbumBySession(session.getId());
+                               DsfSourceLookupDirector director = (DsfSourceLookupDirector) getSourceLocator();
+                               album.configureSourceLookupDirector(director);
+                       } else {
+
+                       }
+               } catch (Exception e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+               
+               snapshotSupportInitialized = true;
+       }
+
+       /**
+        * @since 2.0
+        */
+       public ILaunchConfiguration[] getAffiliatedLaunchConfigurations() {
+               return affiliatedLaunchConfigurations.toArray(new ILaunchConfiguration[affiliatedLaunchConfigurations.size()]);
+       }
+
+       /**
+        * @since 2.0
+        */
+       public void addAffiliatedLaunchConfiguration(
+                       ILaunchConfiguration configuration) {
+               affiliatedLaunchConfigurations.add(configuration);
+       }
+
+       /**
+        * @since 2.0
+        */
+       public void setActiveLaunchConfiguration(ILaunchConfiguration activeLaunchConfiguration) {
+               this.activeLaunchConfiguration = activeLaunchConfiguration;
+       }
+
+       /**
+        * @since 2.0
+        */
+       public void setFirstLaunch(boolean isFirstLaunch) {
+               this.isFirstLaunch = isFirstLaunch;
+       }
+
+       /**
+        * @since 2.0
+        */
+       public boolean isFirstLaunch() {
+               return isFirstLaunch;
+       }
+
+       /**
+        * @since 2.0
+        */
+       public ISourceLocator createSourceLocator()
+                       throws CoreException {
+               DsfSourceLookupDirector locator = new DsfSourceLookupDirector(session);
+               String memento = getLaunchConfiguration().getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String) null);
+               if (memento == null) {
+                       locator.initializeDefaults(getLaunchConfiguration());
+               } else {
+                       locator.initializeFromMemento(memento, getLaunchConfiguration());
+               }
+               return locator;
+       }
+
+       /**
+        * @since 2.0
+        */
+       public static EDCLaunch[] findLaunchesUsingPeer(final IPeer ipeer) {
+               final List<EDCLaunch> results = new ArrayList<EDCLaunch>();
+               ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
+               final List<ILaunch> launchList = Arrays.asList(manager.getLaunches());
+
+               Protocol.invokeAndWait(new Runnable() {
+                       public void run() {
+                               for (ILaunch iLaunch : launchList) {
+                                       if (iLaunch instanceof EDCLaunch) {
+                                               EDCLaunch edcLaunch = (EDCLaunch) iLaunch;
+                                               List<IChannel> channels = launchChannels.get(edcLaunch);
+                                               if (channels != null)
+                                               {
+                                                       for (IChannel iChannel : channels) {
+                                                               if (iChannel.getRemotePeer().equals(ipeer)) {
+                                                                       results.add(edcLaunch);
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               });
+               
+               return results.toArray(new EDCLaunch[results.size()]);
+       }
+
+       /**
+        * @since 2.0
+        */
+       @Override
+       public ILaunchConfiguration getLaunchConfiguration() {
+               if (activeLaunchConfiguration == null)
+                       activeLaunchConfiguration = super.getLaunchConfiguration();
+               return activeLaunchConfiguration;
+       }
+
+       /**
+        * @since 2.0
+        */
+       public String getCompilationPath(String filename) {
+               // TODO Use the source lookup service
+               IPath path = Path.EMPTY;
+               if (Path.EMPTY.isValidPath(filename)) {
+                       filename = PathUtils.convertPathToNative(filename);
+                       ISourceLocator sl = getSourceLocator();
+                       if (sl instanceof CSourceLookupDirector) {
+                               path = ((CSourceLookupDirector) sl).getCompilationPath(filename);
+                       }
+                       if (path == null) {
+                               path = PathUtils.findExistingPathIfCaseSensitive(new Path(filename));
+                       }
+               }
+               return path.toOSString();
+       }
+
+       /**
+        * @since 2.0
+        */
+       public String getStartupStopAtPoint() {
+               String ret = null;
+               try {
+                       if (getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN,
+                                       false)) {
+                               ret = getLaunchConfiguration().getAttribute(
+                                               ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL,
+                                               ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT);
+                       }
+               } catch (CoreException e) {
+                       // ignore
+               }
+
+               return ret;
+       }
+
+       /**
+        * Set a short description for this launch.
+        * The default is the name of the initial launch
+        * configuration but usually somewhere in the
+        * initial launch sequence a description of the
+        * debug target can be gathered, either from the
+        * TCF peer attributes or from the connection
+        * settings.
+        * @since 2.0
+        */
+       public void setDescription(String description) {
+               this.description = description;
+       }
+
+       /**
+        * Returns a short description of the launch.
+        * Used as the label for the launch in the
+        * Debug view. 
+        * @since 2.0
+        */
+       public String getDescription() {
+               if (description == null)
+                       return getLaunchConfiguration().getName();
+               return description;
+       }
+
+       /**
+        * Once a launch has been selected for use by a launch delegate
+        * the launching flag is set so clients can know the launch is
+        * in use. Once the launch process completes this launching flag
+        * will be reset.
+        * @since 2.0
+        */
+       public void setLaunching(boolean isLaunching) {
+               this.isLaunching = isLaunching;
+       }
+
+       /**
+        * Returns true if this launch being used by a delegate
+        * for new launch activity.
+        * @since 2.0
+        */
+       public boolean isLaunching() {
+               return isLaunching;
+       }
+
+       /**
+        * When the termination process begins this is called to flag
+        * the launch so clients can know it is shutting down.
+        * @since 2.0
+        */
+       public void setTerminating(boolean isTerminating) {
+               this.isTerminating = isTerminating;
+       }
+
+       /**
+        * Returns true if this launch is in the process of terminating.
+        * Termination is asynchronous and clients can call this to see
+        * if termination is in progress.
+        * @since 2.0
+        */
+       public boolean isTerminating() {
+               return isTerminating;
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/EDCLaunchDelegate.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/EDCLaunchDelegate.java
new file mode 100644 (file)
index 0000000..4b09e17
--- /dev/null
@@ -0,0 +1,361 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.launch;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.launch.ServicesLaunchSequence;
+import org.eclipse.cdt.debug.edc.internal.snapshot.SnapshotLaunchSequence;
+import org.eclipse.cdt.debug.edc.internal.snapshot.SnapshotUtils;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.debug.service.IDsfDebugServicesFactory;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.launch.AbstractCLaunchDelegate2;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
+
+abstract public class EDCLaunchDelegate extends AbstractCLaunchDelegate2 {
+
+       class UncancelableMonitor extends SubProgressMonitor {
+
+               private boolean canceled;
+
+               public UncancelableMonitor(IProgressMonitor monitor, int ticks,
+                               int style) {
+                       super(monitor, ticks, style);
+                       this.canceled = false;
+               }
+
+               @Override
+               public void setCanceled(boolean b) {
+                       canceled = b;
+               }
+
+               @Override
+               public boolean isCanceled() {
+                       return canceled;
+               }
+               
+       }
+       
+       public EDCLaunchDelegate() {
+               super(false);
+       }
+
+       public EDCLaunchDelegate(boolean requireCProject) {
+               super(requireCProject);
+       }
+
+       public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
+                       throws CoreException {
+               
+               org.eclipse.cdt.launch.LaunchUtils.enableActivity("org.eclipse.cdt.debug.edc.ui.edcActivity", true); //$NON-NLS-1$
+               
+               if (monitor == null) {
+                       monitor = new NullProgressMonitor();
+               }
+               
+               monitor.beginTask("Launching...", 10);
+               if (monitor.isCanceled()) {
+                       return;
+               }
+
+               try {
+                       final EDCLaunch edcLaunch = (EDCLaunch) launch;
+                       boolean forDebug = mode.equals(ILaunchManager.DEBUG_MODE);
+
+                       monitor.worked(1);
+                       
+                       if (edcLaunch.isFirstLaunch())
+                       {
+                               // First launch for this session, we need to create all of the services
+                               edcLaunch.setServiceFactory(newServiceFactory());
+
+                               if (forDebug) {
+                                       edcLaunch.initializeSnapshotSupport();
+                               }
+                               // Create and invoke the launch sequence to create the debug control and
+                               // services
+                               IProgressMonitor subMon1 = new SubProgressMonitor(monitor, 4, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+                               final ServicesLaunchSequence servicesLaunchSequence = new ServicesLaunchSequence(edcLaunch.getSession(), edcLaunch,
+                                               subMon1);
+
+                               edcLaunch.getSession().getExecutor().execute(servicesLaunchSequence);
+                               try {
+                                       getOrCancelSequence(servicesLaunchSequence, subMon1);
+                               } catch (InterruptedException e1) {
+                                       throw new DebugException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+                                                       "Interrupted Exception in dispatch thread.\n" + e1.getLocalizedMessage(), e1)); //$NON-NLS-1$
+                               } catch (CancellationException e) {
+                                       throw new CoreException(Status.CANCEL_STATUS);
+                               } catch (ExecutionException e1) {
+                                       throw new DebugException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, DebugException.REQUEST_FAILED,
+                                                       "Error in services launch sequence.", e1.getCause())); //$NON-NLS-1$
+                               }
+
+                               if (monitor.isCanceled())
+                                       return;
+
+                               // The initializeControl method should be called after the
+                               // ICommandControlService
+                               // be initialized in the ServicesLaunchSequence above. This is because
+                               // it is that
+                               // service that will trigger the launch cleanup (if we need it during
+                               // this launch)
+                               // through an ICommandControlShutdownDMEvent
+                               if (forDebug) {
+                                       edcLaunch.initializeMemoryRetrieval();
+                               }
+
+                               monitor.worked(1);
+                               
+                       }
+
+
+                       // Create and invoke the final launch sequence to setup the debugger
+                       IProgressMonitor subMon2 = new UncancelableMonitor(monitor, 4, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+                       final Sequence finalLaunchSequence = getFinalLaunchSequence(edcLaunch.getSession().getExecutor(), edcLaunch, subMon2);
+
+                       edcLaunch.getSession().getExecutor().execute(finalLaunchSequence);
+                       boolean succeed = false;
+                       try {
+                               getOrCancelSequence(finalLaunchSequence, subMon2);
+                               succeed = true;
+                       } catch (InterruptedException e1) {
+                               IStatus exceptionStatus = new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+                                               "Interrupted Exception in dispatch thread.\n" + e1.getLocalizedMessage(), e1);
+                               if (edcLaunch.isFirstLaunch())
+                                       throw new DebugException(exceptionStatus); //$NON-NLS-1$
+                               else
+                                       EDCDebugger.getMessageLogger().log(exceptionStatus);
+                       } catch (CancellationException e) {
+                               if (edcLaunch.isFirstLaunch())
+                                       throw new CoreException(Status.CANCEL_STATUS);
+                       } catch (ExecutionException e1) {
+                               Throwable cause = e1.getCause();
+                               if (cause instanceof CoreException) {
+                                       IStatus s = ((CoreException) cause).getStatus();
+                                       if (s.getSeverity() == IStatus.CANCEL && edcLaunch.isFirstLaunch())
+                                               throw (CoreException) cause;
+                               }
+                               IStatus errorStatus = EDCDebugger.getMessageLogger().createStatus(IStatus.ERROR, null, e1.getCause());
+                               if (edcLaunch.isFirstLaunch())
+                                       throw new DebugException(errorStatus);
+                               else
+                                       EDCDebugger.getMessageLogger().log(errorStatus);
+                       } finally {
+                               if (!succeed && edcLaunch.isFirstLaunch()) {
+                                       Query<Object> launchShutdownQuery = new Query<Object>() {
+                                               @Override
+                                               protected void execute(DataRequestMonitor<Object> rm) {
+                                                       edcLaunch.shutdownSession(rm);
+                                               }
+                                       };
+
+                                       edcLaunch.getSession().getExecutor().execute(launchShutdownQuery);
+
+                                       // Wait for the shutdown to finish. The Query.get() method is a
+                                       // synchronous call which blocks until the query completes.
+                                       try {
+                                               // not cancellable
+                                               launchShutdownQuery.get();
+                                       } catch (InterruptedException e) {
+                                               throw new DebugException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID,
+                                                               DebugException.INTERNAL_ERROR,
+                                                               "InterruptedException while shutting down debugger launch " + launch, e)); //$NON-NLS-1$ 
+                                       } catch (ExecutionException e) {
+                                               throw new DebugException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID,
+                                                               DebugException.REQUEST_FAILED, "Error in shutting down debugger launch " + launch, e)); //$NON-NLS-1$
+                                       }
+                               }
+                               
+                               if (!forDebug) {
+                                       // just running, so go ahead and shutdown the session
+                                       edcLaunch.shutdownSession(new RequestMonitor(ImmediateExecutor.getInstance(), null));
+                               }
+                               
+                               edcLaunch.setLaunching(false);
+                       }
+               } finally {
+                       monitor.done();
+               }
+       }
+
+       /**
+        * Wait for a sequence to finish, periodically checking whether
+        * it has been cancelled. 
+        * @param sequence
+        * @param monitor
+        * @return the value of the sequence
+        * @throws ExecutionException 
+        * @throws InterruptedException
+        * @throws CancellationException  
+        */
+       private Object getOrCancelSequence(Sequence sequence,
+                       IProgressMonitor monitor) throws InterruptedException, ExecutionException {
+               while (!monitor.isCanceled()) {
+                       try {
+                               return sequence.get(1, TimeUnit.SECONDS);
+                       } catch (TimeoutException e) {
+                               // fine, keep looping
+                       }
+               }
+               // cancelled
+               sequence.cancel(true);  /* flag is ignored */
+               throw new CancellationException();
+       }
+
+       @Override
+       public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {
+               // Need to configure the source locator before creating the launch
+               // because once the launch is created and added to launch manager,
+               // the adapters will be created for the whole session, including
+               // the source lookup adapter.
+
+               EDCLaunch launch = findExistingLaunch(configuration, mode);
+               if (launch == null)
+               {
+                       launch = createLaunch(configuration, mode);
+                       launch.initialize();
+                       launch.setSourceLocator(launch.createSourceLocator());
+               }
+               else
+               {
+                       launch.addAffiliatedLaunchConfiguration(configuration);
+                       launch.setFirstLaunch(false);
+               }
+
+               launch.setActiveLaunchConfiguration(configuration);
+
+               return launch;
+       }
+
+       /**
+        * @since 2.0
+        */
+       abstract public EDCLaunch createLaunch(ILaunchConfiguration configuration,
+                       String mode);
+
+       private EDCLaunch findExistingLaunch(ILaunchConfiguration configuration,
+                       String mode) {
+               if (!SnapshotUtils.isSnapshotLaunchConfig(configuration)) // Snapshot launches never join existing ones.
+               { 
+               ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
+               List<ILaunch> launchList = Arrays.asList(manager.getLaunches());
+               
+               for (ILaunch iLaunch : launchList) {            
+                       if (!iLaunch.isTerminated() && iLaunch instanceof EDCLaunch)
+                       {
+                               EDCLaunch edcLaunch = (EDCLaunch) iLaunch;
+                               // The launch may be in the process of terminating. Test for that but
+                               // first synchronize around the launch so it can't begin termination
+                               // while we are checking here.
+
+                               if (DsfSession.isSessionActive(edcLaunch.getSession().getId())
+                                               && isSameTarget(edcLaunch, configuration, mode))
+                               {
+                                       if (edcLaunch.isTerminating())
+                                               this.waitForLaunchToTerminate(edcLaunch);
+                                       synchronized (edcLaunch)
+                                       {
+                                               if (!edcLaunch.isTerminating())
+                                               {
+                                                       edcLaunch.setLaunching(true);
+                                                       return edcLaunch;
+                                               }
+                                       }
+                               }
+                       }
+                       }
+               }
+               return null;
+       }
+
+       private void waitForLaunchToTerminate(final EDCLaunch edcLaunch) {
+
+               Job waitForTerminate = new Job("Waiting for " + edcLaunch.getDescription() + " to terminate") {
+
+                       @Override
+                       protected IStatus run(IProgressMonitor monitor) {
+                               monitor.beginTask("Waiting for termination",
+                                               IProgressMonitor.UNKNOWN);
+                               try {
+                                       while (!edcLaunch.isTerminated()) {
+                                               Thread.sleep(500);
+                                               if (monitor.isCanceled())
+                                                       return Status.CANCEL_STATUS;
+                                               monitor.worked(1);
+                                       }
+                               } catch (InterruptedException e) {
+                                       EDCDebugger.getMessageLogger().logError(null, e);
+                               }
+                               finally {
+                                       monitor.done();
+                               }
+
+                               return Status.OK_STATUS;
+                       }
+               };
+
+               waitForTerminate.schedule();
+               try {
+                       waitForTerminate.join();
+               } catch (InterruptedException e) {
+                       EDCDebugger.getMessageLogger().logError(null, e);
+               }
+       }
+
+       abstract public String getDebugModelID();
+
+       abstract protected Sequence getLiveLaunchSequence(DsfExecutor executor, EDCLaunch launch, IProgressMonitor pm);
+
+       protected Sequence getSnapshotLaunchSequence(DsfExecutor executor, EDCLaunch launch, IProgressMonitor pm) {
+               return new SnapshotLaunchSequence(executor, launch, pm);
+       };
+
+       protected Sequence getFinalLaunchSequence(DsfExecutor executor, EDCLaunch launch, IProgressMonitor pm) {
+               if (launch.isSnapshotLaunch())
+                       return getSnapshotLaunchSequence(executor, launch, pm);
+               else
+                       return getLiveLaunchSequence(executor, launch, pm);
+       };
+
+       abstract protected IDsfDebugServicesFactory newServiceFactory();
+       
+
+       /**
+        * @param existingLaunch 
+        * @since 2.0
+        */
+       abstract protected boolean isSameTarget(EDCLaunch existingLaunch, ILaunchConfiguration configuration, String mode);
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/ICacheManager.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/ICacheManager.java
new file mode 100644 (file)
index 0000000..8e88715
--- /dev/null
@@ -0,0 +1,103 @@
+package org.eclipse.cdt.debug.edc.launch;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.acpm.AvailableFormatsRequestCache;
+import org.eclipse.cdt.debug.edc.acpm.FormatedExpressionValueRequestCache;
+import org.eclipse.cdt.debug.edc.acpm.MemoryRangeCache;
+import org.eclipse.cdt.debug.edc.acpm.RegistersByNameRequestCache;
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+
+/**
+ * Interface for an ACPM cache manager used within EDC. The cache manager is
+ * responsible for dishing out cache objects and managing their lifetimes.
+ * <p>
+ * In theory, every method of every available DSF service could be given an ACPM
+ * front end, making this a massive interface. In practice, though, ACPM is used
+ * selectively for situations where coding using asynchronous APIS becomes
+ * unwieldy. This interface will attempt to provide access to the service
+ * methods likely to be used in those situations. This interface will grow in
+ * time and as such is marked @noimplement and @noextend so the expansion can be
+ * done without breaking backward compatibility.
+ * 
+ * TODO: extensibility; allow EDC adopters to integrate custom services
+ * 
+ * @since 2.0
+ * @noimplement
+ * @noextend
+ */
+@ConfinedToDsfExecutor("")     // any executor
+public interface ICacheManager {
+
+       /** See {@link IFormattedValues#getFormattedExpressionValue(FormattedValueDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)} */
+       public FormatedExpressionValueRequestCache getFormattedExpressionValue(IFormattedValues service, FormattedValueDMContext dmc);
+       
+       /** See {@link IFormattedValues#getAvailableFormats(IFormattedDataDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)} */
+       public AvailableFormatsRequestCache getAvailableFormats(IFormattedValues service, IFormattedDataDMContext dmc);
+       
+       /** Returns the collection of all available registers for the given context, indexed by name */
+       public RegistersByNameRequestCache getRegistersByName(IDMContext dmc);
+
+       /**
+        * Returns a range cache that can be used to get any range of memory
+        * relative to [address].
+        * {@link IMemory#getMemory(IMemoryDMContext, IAddress, long, int, int, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)}
+        */
+    public MemoryRangeCache getMemory(IMemoryDMContext dmc, IAddress address, int wordSize);
+
+       /**
+        * ACPM transactions that use this cache manager interface are required to
+        * start the transaction by calling this method, and then calling
+        * {@link #endTransaction(boolean)} at the end of the attempt (successful or
+        * not). The manager relies on this for tracking cache objects used in the
+        * current transaction (only one can run at any one time since ACPM
+        * transactions run on the DSF thread). That information is used in managing
+        * the lifetime of cache objects.
+        * 
+        * <pre>
+        * class MyTransaction<Boolean> {
+        *     protected Boolean process() throws InvalidCacheException, CoreException {
+        *         boolean invalidCache = false;
+        *         ICacheManager cacheMgr = ...
+        *         cacheMgr.beginTransaction();
+        *         try {
+        *             Boolean result = false;
+        *             // ... transaction logic
+        *             return result
+        *          }
+        *          catch (InvalidCacheException exc) {
+        *              invalidCache = true;
+        *              throw exc;
+        *          }
+        *          finally {
+        *              cacheMgr.endTransaction(invalidCache);
+        *          }
+        *      }
+        * }
+        * </pre>
+        * 
+        */
+       public void beginTransaction();
+
+       /**
+        * See {@link #beginTransaction()}
+        * 
+        * @param failedInvalidCache
+        *            indicates whether the transaction failed due to an invalid
+        *            cache exception. One that fails in that way will run again
+        *            once the required invalid cache objects become valid; it's an
+        *            "ongoing" transaction. It's imperative for the cache manager
+        *            to not discard cache objects involved in ongoing transactions.
+        */
+       public void endTransaction(boolean failedInvalidCache);
+
+       /**
+        * Tells the cache manager to discard all cache objects.
+        */
+       public void purgeAll();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/IEDCLaunchConfigurationConstants.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/IEDCLaunchConfigurationConstants.java
new file mode 100644 (file)
index 0000000..0c70cfe
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.launch;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @since 2.0
+ */
+public interface IEDCLaunchConfigurationConstants {
+
+       public static final String ATTR_ALBUM_FILE = "org.eclipse.cdt.debug.edc.internal.launch.snapshotAlbum"; //$NON-NLS-1$
+
+       public static final String ATTR_USE_REMOTE_PEERS = "org.eclipse.cdt.debug.edc.useRemotePeers"; //$NON-NLS-1$
+
+       /**
+        * @since 2.0
+        */
+       public static final String ATTR_ATTACH_CONTEXT_NAME = "org.eclipse.cdt.debug.edc.attachContextName"; //$NON-NLS-1$
+
+       /**
+        * @since 2.0
+        */
+       public static final String ATTR_IS_ONE_USE = "org.eclipse.cdt.debug.edc.isOneUse"; //$NON-NLS-1$
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/LaunchMessages.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/LaunchMessages.java
new file mode 100644 (file)
index 0000000..3665034
--- /dev/null
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.launch;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class LaunchMessages {
+
+       private static final String BUNDLE_NAME = "org.eclipse.cdt.debug.edc.launch.LaunchMessages";//$NON-NLS-1$
+
+       private static ResourceBundle RESOURCE_BUNDLE = null;
+
+       static {
+               try {
+                       RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+               } catch (MissingResourceException x) {
+               }
+       }
+
+       private LaunchMessages() {
+       }
+
+       public static String getFormattedString(String key, String arg) {
+               return MessageFormat.format(getString(key), new Object[] { arg });
+       }
+
+       public static String getFormattedString(String key, String[] args) {
+               return MessageFormat.format(getString(key), (Object[]) args);
+       }
+
+       public static String getString(String key) {
+               if (RESOURCE_BUNDLE == null)
+                       return '!' + key + '!';
+               return RESOURCE_BUNDLE.getString(key);
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/LaunchMessages.properties b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/LaunchMessages.properties
new file mode 100644 (file)
index 0000000..efb43b5
--- /dev/null
@@ -0,0 +1,22 @@
+###############################################################################
+# Copyright (c) 2008, 2009  QNX Software Systems and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#       QNX Software Systems - Initial API and implementation
+#       Monta Vista - Joanne Woo - Bug 87556
+#       Nokia - Ken Ryall - Bug 118894
+#       Nokia - Ling Wang - tailored for EDC
+###############################################################################
+
+LaunchUtils.C_Project_not_specified=C Project not specified
+LaunchUtils.Not_a_C_CPP_project=Project is not a C/C++ project
+LaunchUtils.Program_file_not_specified=Program file not specified
+LaunchUtils.Program_file_does_not_exist=Program file does not exist
+LaunchUtils.PROGRAM_PATH_not_found={0} not found
+LaunchUtils.Project_NAME_does_not_exist=Project {0} does not exist
+LaunchUtils.Project_NAME_is_closed=Project {0} is closed
+
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/LaunchUtils.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/launch/LaunchUtils.java
new file mode 100644 (file)
index 0000000..d3a12e4
--- /dev/null
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.launch;
+
+import java.io.FileNotFoundException;
+import java.util.Map;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.variables.IStringVariableManager;
+import org.eclipse.core.variables.VariablesPlugin;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
+
+public class LaunchUtils {
+
+       /**
+        * Verify the following things about the project: - is a valid project name
+        * given - does the project exist - is the project open - is the project a
+        * C/C++ project
+        */
+       public static ICProject verifyCProject(ILaunchConfiguration configuration) throws CoreException {
+               String name = getProjectName(configuration);
+               if (name == null) {
+                       abort(LaunchMessages.getString("LaunchUtils.C_Project_not_specified"), null, //$NON-NLS-1$
+                                       ICDTLaunchConfigurationConstants.ERR_UNSPECIFIED_PROJECT);
+                       return null;
+               }
+               ICProject cproject = getCProject(configuration);
+               if (cproject == null && name.length() > 0) {
+                       IProject proj = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
+                       if (!proj.exists()) {
+                               abort(LaunchMessages.getFormattedString("LaunchUtils.Project_NAME_does_not_exist", name), null, //$NON-NLS-1$
+                                               ICDTLaunchConfigurationConstants.ERR_NOT_A_C_PROJECT);
+                       } else if (!proj.isOpen()) {
+                               abort(LaunchMessages.getFormattedString("LaunchUtils.Project_NAME_is_closed", name), null, //$NON-NLS-1$
+                                               ICDTLaunchConfigurationConstants.ERR_NOT_A_C_PROJECT);
+                       }
+                       abort(LaunchMessages.getString("LaunchUtils.Not_a_C_CPP_project"), null, //$NON-NLS-1$
+                                       ICDTLaunchConfigurationConstants.ERR_NOT_A_C_PROJECT);
+               }
+               return cproject;
+       }
+
+       /**
+        * Verify that program name of the configuration can be found as a file.
+        * 
+        * @return Absolute path of the program location
+        */
+       public static IPath verifyProgramPath(ILaunchConfiguration configuration, ICProject cproject) throws CoreException {
+               // Note this assumes CDT launch configuration main tab is used.
+               String programName = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME,
+                               (String) null);
+               if (programName == null) {
+                       abort(LaunchMessages.getString("LaunchUtils.Program_file_not_specified"), null, //$NON-NLS-1$
+                                       ICDTLaunchConfigurationConstants.ERR_NOT_A_C_PROJECT);
+               }
+
+               IPath programPath = new Path(programName);
+               if (programPath.isEmpty()) {
+                       abort(LaunchMessages.getString("LaunchUtils.Program_file_does_not_exist"), null, //$NON-NLS-1$
+                                       ICDTLaunchConfigurationConstants.ERR_NOT_A_C_PROJECT);
+               }
+
+               if (!programPath.isAbsolute() && cproject != null) {
+                       // Find the specified program within the specified project
+                       IFile wsProgramPath = cproject.getProject().getFile(programPath);
+                       programPath = wsProgramPath.getLocation();
+               }
+
+               if (!programPath.toFile().exists()) {
+                       abort(LaunchMessages.getString("LaunchUtils.Program_file_does_not_exist"), //$NON-NLS-1$
+                                       new FileNotFoundException(LaunchMessages.getFormattedString("LaunchUtils.PROGRAM_PATH_not_found", //$NON-NLS-1$ 
+                                                       programPath.toOSString())), ICDTLaunchConfigurationConstants.ERR_PROGRAM_NOT_EXIST);
+               }
+
+               return programPath;
+       }
+
+       /**
+        * Throws a core exception with an error status object built from the given
+        * message, lower level exception, and error code.
+        * 
+        * @param message
+        *            the status message
+        * @param exception
+        *            lower level exception associated with the error, or
+        *            <code>null</code> if none
+        * @param code
+        *            error code
+        */
+       private static void abort(String message, Throwable exception, int code) throws CoreException {
+               MultiStatus status = new MultiStatus(EDCDebugger.getUniqueIdentifier(), code, message, exception);
+               status.add(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), code,
+                               exception == null ? "" : exception.getLocalizedMessage(), //$NON-NLS-1$
+                               exception));
+               throw new CoreException(status);
+       }
+
+       /**
+        * Returns an ICProject based on the project name provided in the
+        * configuration. First look for a project by name, and then confirm it is a
+        * C/C++ project.
+        */
+       public static ICProject getCProject(ILaunchConfiguration configuration) throws CoreException {
+               String projectName = getProjectName(configuration);
+               if (projectName != null) {
+                       projectName = projectName.trim();
+                       if (projectName.length() > 0) {
+                               IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+                               ICProject cProject = CCorePlugin.getDefault().getCoreModel().create(project);
+                               if (cProject != null && cProject.exists()) {
+                                       return cProject;
+                               }
+                       }
+               }
+               return null;
+       }
+
+       private static String getProjectName(ILaunchConfiguration configuration) throws CoreException {
+               return configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String) null);
+       }
+       
+       /**
+        * Convenience method.
+        */
+       public static IStringVariableManager getStringVariableManager() {
+               return VariablesPlugin.getDefault().getStringVariableManager();
+       }
+       
+       public static String getWorkingDirectoryPath(ILaunchConfiguration config) throws CoreException {
+               String location = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, "");
+               if (location != null) {
+                       String expandedLocation = LaunchUtils.getStringVariableManager().performStringSubstitution(location);
+                       if (expandedLocation.length() > 0) {
+                               return expandedLocation;
+                       }
+               }
+               return "";
+       }
+
+       /**
+        * @since 2.0
+        */
+       public static String[] getProgramArgumentsArray(ILaunchConfiguration config) throws CoreException {
+               return org.eclipse.cdt.launch.LaunchUtils.getProgramArgumentsArray(config);
+       }
+       
+       /**
+        * @since 2.0
+        */
+       @SuppressWarnings("unchecked")
+       public static Map<String, String> getEnvironmentVariables(ILaunchConfiguration config) throws CoreException {
+               return config.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, (Map<?,?>) null);
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/AbstractEDCService.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/AbstractEDCService.java
new file mode 100644 (file)
index 0000000..66486ac
--- /dev/null
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.snapshot.Album;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.BundleContext;
+
+/**
+ * This is abstract DSF service with some APIs specific to EDC.
+ */
+public abstract class AbstractEDCService extends AbstractDsfService implements IEDCService {
+
+       private final String[] classNames;
+       private ITargetEnvironment targetEnvironmentService = null;
+       private final boolean snapshot;
+    private EDCServicesTracker fEDCTracker;
+
+       public AbstractEDCService(DsfSession session, String[] classNames) {
+               super(session);
+               this.classNames = classNames;
+               this.snapshot = Album.isSnapshotSession(session.getId());
+       }
+
+       public boolean isSnapshot() {
+               return snapshot;
+       }
+
+       /**
+        * @since 2.0
+        */
+       public EDCServicesTracker getEDCServicesTracker() {
+               return fEDCTracker;
+       }
+
+    /**
+        * @since 2.0
+        */
+    public <V> V getService(Class<V> serviceClass) {
+       if (IEDCService.class.isAssignableFrom(serviceClass))
+               return fEDCTracker.getService(serviceClass);
+        return getServicesTracker().getService(serviceClass);
+    }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.service.AbstractDsfService#initialize(org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+        */
+       @Override
+       public void initialize(final RequestMonitor requestMonitor) {
+               fEDCTracker = new EDCServicesTracker(getBundleContext(), getSession().getId());
+               super.initialize(new RequestMonitor(getExecutor(), requestMonitor) {
+                       @Override
+                       public void handleSuccess() {
+                               doInitialize(requestMonitor);
+                       }
+               });
+       }
+
+       @Override
+       public void shutdown(RequestMonitor rm) {
+               fEDCTracker.dispose();
+               fEDCTracker = null;
+               super.shutdown(rm);
+       }
+
+       protected void doInitialize(RequestMonitor requestMonitor) {
+               register(classNames, new Hashtable<String, String>());
+
+               if (targetEnvironmentService == null)
+                       targetEnvironmentService = getServicesTracker().getService(ITargetEnvironment.class);
+
+               requestMonitor.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.service.AbstractDsfService#getBundleContext()
+        */
+       @Override
+       protected BundleContext getBundleContext() {
+               return EDCDebugger.getBundleContext();
+       }
+
+       public ITargetEnvironment getTargetEnvironmentService() {
+               return targetEnvironmentService;
+       }
+
+       /**
+        * Add implicit service class names
+        * 
+        * @param classNames
+        *            the class names our derivative gave us. Must not be null, but
+        *            can be empty.
+        * @param implicitClassNames
+        *            the implicit class names that should be specified. Must not be
+        *            null, but can be empty.
+        * @return a new collection of class names that is [classNames] plus any
+        *         missing implicit ones. The implicit ones will appear first in the
+        *         list
+        */
+       /*package*/ static String[] massageClassNames(String[] classNames, String[] implicitClassNames) {
+               List<String> newClassNames = new ArrayList<String>(Arrays.asList(implicitClassNames));
+               for (String className : classNames) {
+                       if (!newClassNames.contains(className)) {
+                               newClassNames.add(className);
+                       }
+               }
+               return newClassNames.toArray(new String[newClassNames.size()]);
+       }
+
+       /**
+        * EDC services can use this method to execute blocking <i>thread-safe</i>
+        * code without blocking the DSF thread. The runnable is exercised on a
+        * separate thread obtained from a thread pool. This mechanism was
+        * introduced to allow an EDC service's logic to avoid bogging down the DSF
+        * thread in cases where it cannot reasonably avoid making a blocking call.
+        * One example is when a TCF service has to be invoked synchronously (the
+        * calling thread waits for the request monitor to complete). Such things
+        * should not be done on the DSF thread since that thread is meant to be
+        * readily available to handle a queue of requests, much like a UI thread
+        * is.
+        * 
+        * In the event of an uncaught exception in the given code, the request
+        * monitor is automatically completed and given an error status.
+        * 
+        * @throws RejectedExecutionException
+        *             if the thread pool has been overwhelmed and given code cannot
+        *             be scheduled to run
+        * 
+        * @since 2.0
+        */
+       protected void asyncExec(Runnable runnable, RequestMonitor rm) {
+               try {
+                       ExecutorService executor = EDCLaunch.getThreadPool(getSession().getId());
+                       if (executor.isShutdown())
+                       {
+                               rm.setStatus(new Status(Status.ERROR, EDCDebugger.PLUGIN_ID, "Session has been shutdown.", null));
+                               rm.done();
+                       }
+                       else
+                               executor.execute(new SafeRunner(runnable, rm));
+               }
+               catch (RejectedExecutionException exc) {
+                       // See EDCLaunch.newThreadPool()
+                       String msg = Messages.AbstractEDCService_0;
+                       EDCDebugger.getMessageLogger().log(IStatus.WARNING, msg, exc); 
+                       rm.setStatus(new Status(Status.ERROR, EDCDebugger.PLUGIN_ID, msg, exc));
+                       rm.done();
+                       throw exc;
+               }
+       }
+
+       /**
+        * A safe runner used by {@link AbstractEDCService#asyncExec(Runnable)} to
+        * ensure an uncaught exception does not leave the request monitor hanging.
+        */
+       private class SafeRunner implements Runnable {
+               private Runnable fCode;
+               private RequestMonitor fRm;
+
+               SafeRunner(Runnable code, RequestMonitor rm) {
+                       fCode = code;
+                       fRm = rm;
+                       Assert.isNotNull(code);
+               }
+
+               public void run() {
+                       try {
+                               fCode.run();
+                       } catch (Exception e) {
+                               handleException(fCode, e);
+                       } catch (LinkageError e) {
+                               handleException(fCode, e);
+                       } catch (AssertionError e) {
+                               handleException(fCode, e);
+                       }
+               }
+
+               private void handleException(Runnable code, Throwable e) {
+                       IStatus status;
+                       if (!(e instanceof OperationCanceledException)) {
+                               // try to obtain the correct plug-in id for the bundle providing the safe runnable 
+                               if (e instanceof CoreException) {
+                                       status = new MultiStatus(EDCDebugger.PLUGIN_ID, -1, Messages.AbstractEDCService_1, e);
+                                       ((MultiStatus)status).merge(((CoreException) e).getStatus());
+                               } else {
+                                       status = new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, -1, Messages.AbstractEDCService_2, e);
+                               }
+                               EDCDebugger.getMessageLogger().log(status);
+                       }
+                       else {
+                               status = new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, -1, Messages.AbstractEDCService_3, e);
+                       }
+                       if (fRm != null) {
+                               fRm.setStatus(status);
+                               fRm.done();
+                       }
+               }
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/AbstractTargetEnvironment.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/AbstractTargetEnvironment.java
new file mode 100644 (file)
index 0000000..850b66e
--- /dev/null
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.services;
+
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+
+/**
+ * Common base for ITargetEnvironment services.
+ * 
+ */
+public abstract class AbstractTargetEnvironment extends AbstractEDCService implements ITargetEnvironment {
+       private ILaunch launch;
+
+       /**
+        * @param session
+        * @param classNames
+        *            the type names the service will be registered under. See
+        *            AbstractDsfService#register for details. We tack on
+        *            ITargetEnvironment if not provided.
+        * 
+        * @param launch
+        *            must be non-null
+        */
+       public AbstractTargetEnvironment(DsfSession session, String[] classNames, ILaunch launch) {
+               super(session,
+                               massageClassNames(classNames, new String[] {ITargetEnvironment.class.getName()}));
+               assert launch != null;
+               this.launch = launch;
+       }
+
+       public ILaunchConfiguration getLaunchConfiguration() {
+               return launch.getLaunchConfiguration();
+       }
+
+       public ILaunch getLaunch() {
+               return launch;
+       }
+
+       /*
+        * This implementation works for most CDT debug sessions.<br> If your
+        * debugger is using different preference UI, please override this method.
+        */
+       public String getStartupStopAtPoint() {
+               String ret = null;
+               try {
+                       if (getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN,
+                                       false)) {
+                               ret = getLaunchConfiguration().getAttribute(
+                                               ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL,
+                                               ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT);
+                       }
+               } catch (CoreException e) {
+                       // ignore
+               }
+
+               return ret;
+       }
+
+       /**
+        * @since 2.0
+        */
+       public boolean needStartupBreakpointInExecutable(String exeName) {
+               // By default EDC will try to install startup breakpoint in
+               // any loaded module until it succeeds.
+               return true;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/DMContext.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/DMContext.java
new file mode 100644 (file)
index 0000000..b611e7d
--- /dev/null
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+public abstract class DMContext extends AbstractDMContext implements IEDCDMContext {
+
+       protected Map<String, Object> properties = Collections.synchronizedMap(new HashMap<String, Object>());
+       private String id;
+
+       public DMContext(IDsfService service, IDMContext[] parents, String name, String id) {
+               super(service, parents);
+               properties.put(PROP_NAME, name);
+               properties.put(PROP_ID, id);
+               this.id = id;
+       }
+
+       public DMContext(String sessionId, IDMContext[] parents, String id) {
+               super(sessionId, parents);
+               properties.put(PROP_NAME, id);
+               properties.put(PROP_ID, id);
+               this.id = id;
+       }
+
+       public DMContext(IDsfService service, IDMContext[] parents, String id, Map<String, Object> props) {
+               super(service, parents);
+               if (props != null) {
+                       properties.putAll(props);
+                       this.id = id;
+                       properties.put(PROP_ID, id);
+               }
+       }
+
+       public DMContext(String sessionId, IDMContext[] parents, Map<String, Object> props) {
+               super(sessionId, parents);
+               if (props != null) {
+                       properties.putAll(props);
+                       id = (String) properties.get(PROP_ID);
+               }
+       }
+
+       public DMContext(IDsfService service, IDMContext[] parents, Map<String, Object> props) {
+               super(service, parents);
+               if (props != null) {
+                       properties.putAll(props);
+                       id = (String) properties.get(PROP_ID);
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCDMContext#getProperty(java.lang.String)
+        */
+       public Object getProperty(String key) {
+               synchronized (properties) {
+                       return properties.get(key);
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCDMContext#getProperties()
+        */
+       public Map<String, Object> getProperties() {
+               Map<String, Object> result = new HashMap<String, Object>();
+               synchronized (properties) {
+                       result.putAll(properties);
+               }
+               return result;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCDMContext#getName()
+        */
+       public String getName() {
+               return (String) getProperty(PROP_NAME);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCDMContext#setName(java.lang.String)
+        */
+       public void setName(String name) {
+               synchronized (properties) {
+                       properties.put(PROP_NAME, name);
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCDMContext#setProperty(java.lang.String, java.lang.Object)
+        */
+       public void setProperty(String name, Object object) {
+               synchronized (properties) {
+                       properties.put(name, object);
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.internal.services.dsf.IEDCDMContext#getID()
+        */
+       public String getID() {
+               return id;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof DMContext)
+                       return super.baseEquals(obj) && this.getID().equals(((IEDCDMContext) obj).getID());
+               return false;
+       }
+
+       @Override
+       public int hashCode() {
+               return super.baseHashCode() ^ getID().hashCode();
+       }
+
+       @Override
+       public String toString() {
+               StringBuilder builder = new StringBuilder();
+               builder.append("DMContext [");
+               if (id != null) {
+                       builder.append("id=");
+                       builder.append(id);
+                       builder.append(", ");
+               }
+               if (properties != null) {
+                       builder.append("properties=");
+                       builder.append(properties);
+               }
+               builder.append("]");
+               return builder.toString();
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Disassembly.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Disassembly.java
new file mode 100644 (file)
index 0000000..af0a435
--- /dev/null
@@ -0,0 +1,569 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.disassembler.CodeBufferUnderflowException;
+import org.eclipse.cdt.debug.edc.disassembler.DisassembledInstruction;
+import org.eclipse.cdt.debug.edc.disassembler.EDCInstruction;
+import org.eclipse.cdt.debug.edc.disassembler.EDCInstructionFunctionInfo;
+import org.eclipse.cdt.debug.edc.disassembler.EDCMixedInstruction;
+import org.eclipse.cdt.debug.edc.disassembler.IDisassembledInstruction;
+import org.eclipse.cdt.debug.edc.disassembler.IDisassembler;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.EDCServicesMessages;
+import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.debug.service.IDisassembly;
+import org.eclipse.cdt.dsf.debug.service.IInstruction;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+import org.eclipse.cdt.dsf.debug.service.IMixedInstruction;
+import org.eclipse.cdt.dsf.debug.service.IModules;
+import org.eclipse.cdt.dsf.debug.service.IModules.AddressRange;
+import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.model.MemoryByte;
+import org.eclipse.tm.tcf.services.IMemory.MemoryError;
+
+
+public class Disassembly extends AbstractEDCService implements IDisassembly {
+
+       /**
+        * @param classNames
+        *            the type names the service will be registered under. See
+        *            AbstractDsfService#register for details. We tack on base DSF's
+        *            IDisassembly and this class to the list if not provided.
+        * @since 2.0
+        */
+       public Disassembly(DsfSession session, String[] classNames) {
+               super(session,
+                               massageClassNames(classNames, 
+                                               new String[] { IDisassembly.class.getName(), Disassembly.class.getName() }));
+       }
+
+       /**
+        * @return IStatus.ERROR containing NLS string indicating disassembler not yet available
+        * @since 2.0
+        */
+       public static IStatus statusNoDisassembler() {
+               return new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
+                                                 EDCServicesMessages.Disassembly_NoDisassemblerYet, null);
+       }
+
+       /**
+        * @param memoryAt 1st location of unreadable memory
+        * @param memoryLength length of unreadable memory
+        * @return IStatus.ERROR containing formatted message with location & length
+        */
+       private static IStatus statusCannotReadMemory(String memoryAt, Integer memoryLength) {
+               return new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
+                                                 cantReadMemory(memoryAt, memoryLength.toString()), null);
+       }
+
+       /**
+        * string for use in both status for error return and in
+        * pseudo-instruction used in error recovery mode for disassembly view
+        * @param memoryAt 1st location of unreadable memory
+        * @param memoryLength length of unreadable memory (incoming null will "unknown" for length)
+        * @return formatted message with location & length
+        */
+       private static String cantReadMemory(String memoryAt, String memoryLength) {
+               memoryLength = (memoryLength == null) ? "unknown" : memoryLength;
+               return MessageFormat.format(EDCServicesMessages.Disassembly_CannotReadMemoryAt,
+                                                                       memoryAt, memoryLength);
+       }
+
+       /**
+        * check each byte of incoming MemoryByte[] array to see if readable;
+        * fills the RequestMonitor status in case of unreadable bytes.
+        * @param memBytes data to translate
+        * @param start address of first byte of memBytes
+        * @param rm with which to set status in case of error
+        * @return code buffer translated from incoming memByte array, null if any are unreadable
+        * @since 2.0
+        */
+       public static ByteBuffer translateMemoryBytes(MemoryByte[] memBytes,
+                       IAddress start, RequestMonitor rm) {
+               byte[] bytes = new byte[memBytes.length];
+               for (int i = 0; i < memBytes.length; i++) {
+                       // check each byte
+                       if (!memBytes[i].isReadable()) {
+                               rm.setStatus(statusCannotReadMemory(start.add(i).toHexAddressString(), 
+                                                                                                       memBytes.length-i));
+                               rm.done();
+                               return null;
+                       }
+                       bytes[i] = memBytes[i].getValue();
+               }
+               return ByteBuffer.wrap(bytes);
+       }
+
+       /**
+        * return a buffer of instruction code whose readability matches the
+        * first byte of the data for as long as all such bytes are the same
+        * @param memBytes data to translate
+        * @return a code buffer either full of readable bytes
+        *              or empty representing the unreadable region
+        */
+       private ByteBuffer translateMemoryBytes(List<MemoryByte> memBytes) {
+               byte[] bytes = new byte[memBytes.size()];
+               boolean firstIsReadable = memBytes.get(0).isReadable();
+               int count = 0;
+               for (MemoryByte memByte : memBytes) {
+                       // check each byte
+                       if (memByte.isReadable() != firstIsReadable)
+                               break;
+                       bytes[count++] = firstIsReadable ? memByte.getValue() : 0;
+               }
+
+               return ByteBuffer.wrap(bytes, 0, count);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IDisassembly#getInstructions(org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext, java.math.BigInteger, java.math.BigInteger, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getInstructions(final IDisassemblyDMContext context, BigInteger startAddress, BigInteger endAddress,
+                       final DataRequestMonitor<IInstruction[]> drm) {
+
+               // FIXME: ignoring null startAddress and null endAddress semantics
+
+               ITargetEnvironment env = getTargetEnvironmentService();
+               final IDisassembler disassembler = (env != null) ? env.getDisassembler() : null;
+               if (disassembler == null) {
+                       drm.setStatus(statusNoDisassembler());
+                       drm.done();
+                       return;
+               }
+
+               DsfServicesTracker services = getServicesTracker();
+               if (services == null) // could be null if async invoked as or after debug session ends
+                       return;
+
+               IMemory memoryService = services.getService(IMemory.class);
+               if (memoryService == null) // could be null if async invoked as or after debug session ends
+                       return;
+
+               final int size = endAddress.intValue() - startAddress.intValue() + 16;
+
+               final IMemoryDMContext mem_dmc = DMContexts.getAncestorOfType(context, IMemoryDMContext.class);
+               final IAddress start = new Addr64(startAddress);
+
+               memoryService.getMemory(mem_dmc, start, 0, 1, size,
+                                                               new DataRequestMonitor<MemoryByte[]>(getExecutor(), drm) {
+                       /**
+                        * overridden to create a non-error status plus pseudoInstruction data-set
+                        * in the DRM requested by DisassemblyBackendDsf, where a DRM.status of
+                        * ERROR is turned into an "invalid" block in its document map.  Such
+                        * blocks are repeatedly re-requested ... causing scrolling oddities & performance issues.
+                        * @see failedMemoryDsfPseudoInstructions
+                        */
+                       @Override
+                       protected void handleError() {
+                               IStatus s = getStatus();
+                       Throwable e = s.getException();
+                       if (e instanceof MemoryError && s.getMessage().contains("Fail to read memory")) {
+                                       drm.setData(failedMemoryDsfPseudoInstructions(start, size, s.getMessage()));
+                                       drm.done();
+                               } else {
+                                       super.handleError();
+                       }
+                       
+                   }
+
+                   @Override
+                       protected void handleSuccess() {
+                               List<MemoryByte> memBytes = Arrays.asList(getData());
+                               Map<String, Object> options = new HashMap<String, Object>();
+                               try {
+                                       ArrayList<IInstruction> instrs
+                                         = fillDisassemblyViewInstructions(memBytes, start, context,
+                                                                                                               disassembler, options);
+                                       drm.setData(instrs.toArray(new IInstruction[instrs.size()]));
+                               } catch (CoreException e) {
+                                       drm.setStatus(e.getStatus());
+                               }
+                               drm.done();
+                       }
+               });
+
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IDisassembly#getInstructions(org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext, java.lang.String, int, int, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getInstructions(final IDisassemblyDMContext context, String filename, int linenum, final int lines,
+                       final DataRequestMonitor<IInstruction[]> drm) {
+
+               // FIXME: ignoring "lines" semantics
+
+               IModules modulesService = getServicesTracker().getService(IModules.class);
+
+               ISymbolDMContext sym_dmc = DMContexts.getAncestorOfType(context, ISymbolDMContext.class);
+
+               filename = EDCLaunch.getLaunchForSession(getSession().getId()).getCompilationPath(filename);
+
+               modulesService.calcAddressInfo(sym_dmc, filename, linenum, 0,
+                                                                          new DataRequestMonitor<AddressRange[]>(getExecutor(), drm) {
+                       @Override
+                       protected void handleSuccess() {
+                               AddressRange[] addr_ranges = getData();
+
+                               IAddress start = addr_ranges[0].getStartAddress();
+                               IAddress end = start.add(lines * 4); // kind of arbitrary end
+                                                                                                               // address hint.
+
+                               getInstructions(context, start.getValue(), end.getValue(), drm);
+                       }
+               });
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IDisassembly#getMixedInstructions(org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext, java.math.BigInteger, java.math.BigInteger, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getMixedInstructions(final IDisassemblyDMContext context, BigInteger startAddress, BigInteger endAddress,
+                       final DataRequestMonitor<IMixedInstruction[]> drm) {
+
+               // FIXME: ignoring null startAddress and null endAddress semantics
+
+               DsfServicesTracker services = getServicesTracker();
+               if (services == null) // could be null if async invoked as or after debug session ends
+                       return;
+
+               IEDCSymbols symbolsService = services.getService(IEDCSymbols.class);
+               if (symbolsService == null) // could be null if async invoked as or after debug session ends
+                       return;
+
+               IEDCModules modulesService = services.getService(IEDCModules.class);
+               if (modulesService == null) // could be null if async invoked as or after debug session ends
+                       return;
+
+               final ISymbolDMContext sym_dmc = DMContexts.getAncestorOfType(context, ISymbolDMContext.class);
+
+               // These are absolute runtime addresses.
+               final IAddress end = new Addr64(endAddress);
+               final IAddress start
+                 = getStartAddressForLineEntryContainingAddress(symbolsService, modulesService, sym_dmc,
+                                                                                                                new Addr64(startAddress), end);
+
+               ILineEntry startEntry = symbolsService.getLineEntryForAddress(sym_dmc, start);
+
+               if (startEntry == null) {
+                       // startAddress has no source
+                       getInstructions(context, startAddress, endAddress,
+                                                       new DataRequestMonitor<IInstruction[]>(getExecutor(), drm) {
+                               @Override
+                               protected void handleSuccess() {
+                                       IMixedInstruction[] ret = new IMixedInstruction[1];
+                                       ret[0] = new EDCMixedInstruction("unknown", 0, getData()); //$NON-NLS-1$
+                                       drm.setData(ret);
+                                       drm.done();
+                               }
+                       });
+               } else { // there is source for start address.
+
+                       final IEDCModuleDMContext module = modulesService.getModuleByAddress(sym_dmc, start);
+                       final List<ILineEntry> codeLines = symbolsService.getLineEntriesForAddressRange(sym_dmc, start, end);
+
+                       getInstructions(context, startAddress, endAddress,
+                                                       new DataRequestMonitor<IInstruction[]>(getExecutor(), drm) {
+                               @Override
+                               protected void handleSuccess() {
+                                       List<IMixedInstruction> mixedInstructions = new ArrayList<IMixedInstruction>();
+
+                                       mixSource(mixedInstructions, null, module, codeLines, getData());
+
+                                       drm.setData(mixedInstructions.toArray(new IMixedInstruction[mixedInstructions.size()]));
+                                       drm.done();
+                               }
+                       });
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IDisassembly#getMixedInstructions(org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext, java.lang.String, int, int, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getMixedInstructions(final IDisassemblyDMContext context, String filename, final int linenum,
+                       final int lines, final DataRequestMonitor<IMixedInstruction[]> drm) {
+
+               // FIXME: ignoring "lines" semantics
+
+               final ITargetEnvironment env = getTargetEnvironmentService();
+               final IDisassembler disassembler = (env != null) ? env.getDisassembler() : null;
+               if (disassembler == null) {
+                       drm.setStatus(statusNoDisassembler());
+                       drm.done();
+                       return;
+               }
+
+               IModules modulesService = getServicesTracker().getService(IModules.class);
+
+               ISymbolDMContext sym_dmc = DMContexts.getAncestorOfType(context, ISymbolDMContext.class);
+
+               filename = EDCLaunch.getLaunchForSession(getSession().getId()).getCompilationPath(filename);
+
+               modulesService.calcAddressInfo(sym_dmc, filename, linenum, 0,
+                                                                          new DataRequestMonitor<AddressRange[]>(getExecutor(), drm) {
+                       @Override
+                       protected void handleSuccess() {
+                               AddressRange[] addr_ranges = getData();
+
+                               IAddress start = addr_ranges[0].getStartAddress();
+                               IAddress end = start.add(lines * 4); // kind of arbitrary end  address hint.
+                               getMixedInstructions(context, start.getValue(), end.getValue(), drm);
+                       }
+               });
+       }
+
+       private static EDCInstruction pseudoInstruction(IAddress address, int size, String pseudoMnemonic) {
+               DisassembledInstruction pseudoInstruction = new DisassembledInstruction();
+               pseudoInstruction.setAddress(address);
+               pseudoInstruction.setSize(size);
+               pseudoInstruction.setMnemonics(pseudoMnemonic);
+               return new EDCInstruction(pseudoInstruction);
+       }
+
+       /**
+        * used in failedMemoryDsfPseudoInstructions() below as chunk boundary for
+        * each of the pseudoInstructions in a larger chunk of retrieved memory.
+        */
+       private static final int asmFence = 0x20;
+
+       /**
+        * this utility function creates pseudo-mnemonics indicating failed memory
+        * read. it was refactored from memoryService.getMemory().handleError() so
+        * that it could be utilized by subclass override getInstructions() methods
+        * making the same memoryService.getMemory() call.
+        * <p>
+        * <i>background:</i>
+        * <p>
+        * as of 2010.oct.01, EDC memoryService no longer caches blocks of memory that
+        * cannot be read (a correct change, given that this was blocking the caching
+        * of good memory on the boundaries of such blocks, causing other problems).
+        * <p>
+        * when this change was made, Disassembly#fillDisassemblyViewInstructions()
+        * stopped getting reached through memoryService.getMemory().handleSuccess() .
+        * therefore, actual bad blocks of memory were not getting filled with pseudo
+        * mnemonics indicating bad memory .  in other words, when "Fail to read memory"
+        * errors from TCF caused invocation of memoryService.getMemory().handleFailure()
+        * ... and thus eventually also handleError() ... the result was that
+        * DsfBackendDisassembly would fill the DisassemblyDocument with "invalid"
+        * sections based upon address but no size.  it's algorithm then later attempts
+        * to fill any missing/invalid sections corresponding with the document.  this
+        * results in a visual anomaly where "Unable to retrieve disassembly" would be
+        * populated in the DisassemblyView one block at a time, until there would be a 
+        * large, mostly useless portion of the document view populated with the same
+        * message repeated once for every byte the user had attempted to scroll to.
+        * <p>
+        * the handleError() override implementations that call this utility function
+        * solve the problem whereby DisassemblyBackendDsf interprets DRM.status as
+        * "invalid" sections in its the DisassemblyDocument it is associated with.
+        * <p>
+        * the point of this re-factored code is to create "fences" on regular
+        * boundaries so that chunks of failed memory always get placed on similar
+        * boundaries, thus drastically ameliorating the occurrence of small "invalid"
+        * chunks in the DisassemblyDocument map between chunks of pseudoInstructions
+        * that DisassemblyBackendDsf considers "valid".
+        * <p>
+        * in user terms, this means that scrolling in the view is more consistent
+        * and even, with better performance thanks to fewer attempts to re-retrieve
+        * memory for small "invalid" sections in its map at the boundaries of
+        * previously inserted pseudo-instructions.
+        * 
+        * @param size size of the chunk to break up
+        * @param start location of memory chunk
+        * @param msg message from the target agent
+        * @return array containing 1 or more pseudo-instructions, mostly on asmFence boundaries
+        * @since 2.0
+        */
+       protected static IInstruction[] failedMemoryDsfPseudoInstructions(
+                       IAddress start, final int size, String msg) {
+               ArrayList<IInstruction> pseudoInstr = new ArrayList<IInstruction>();
+               int offset = 0, chunkSize = Math.min(size, asmFence - start.getValue().intValue() % asmFence);
+               do {
+                       pseudoInstr.add(pseudoInstruction(start.add(offset), chunkSize,
+                                                                                         msg + "..[length=" + chunkSize + ']'));
+                       offset += chunkSize;
+                       chunkSize = Math.min(asmFence, size-offset);
+               } while (offset < size);
+               return pseudoInstr.toArray(new IInstruction[pseudoInstr.size()]);
+       }
+
+       /**
+        * Creates the array of instructions to be used to fill the disassembly view.
+        * for a range containing any unreadable instructions, it will create a
+        * fake instruction consisting of the address, the entire unreadable range,
+        * and a message to fill in the mnemonics section about the unreadable range.
+        * @param memBytes the buffer containing the bytes to be disassembled
+        * @param start starting address corresponding to the buffer
+        * @param context context for disassembly
+        * @param disassembler the disassembler object to use
+        * @param options to be passed to the disassembleInstructions() call
+        * @return array of IInstruction
+        * @throws CoreException can be thrown by disassembleInstructions().
+        * @since 2.0
+        */
+       protected ArrayList<IInstruction> fillDisassemblyViewInstructions(
+                       final List<MemoryByte> memBytes, final IAddress start,
+                       final IDisassemblyDMContext context, final IDisassembler disassembler,
+                       Map<String, Object> options)
+                       throws CoreException {
+               ArrayList<IInstruction> ret = new ArrayList<IInstruction>();
+               for (int offset = 0, last = memBytes.size(); offset < last ;) {
+                       ByteBuffer codeBuf = translateMemoryBytes(memBytes.subList(offset, last));
+                       int codeBufSize = codeBuf.limit();
+                       IAddress block = start.add(offset);
+                       if (memBytes.get(offset).isReadable()) {
+                               try {
+                                       List<IDisassembledInstruction> insts
+                                         = disassembler.disassembleInstructions(block, block.add(codeBufSize),
+                                                                                                                        codeBuf, options, context);
+                                       if (insts.size() == 0)
+                                               break;
+                                       for (int i = 0; i < insts.size(); i++) {
+                                               ret.add(new EDCInstruction(insts.get(i)));
+                                               offset += insts.get(i).getSize();
+                                       }
+                               } catch (CodeBufferUnderflowException e) {
+                                       if (offset == 0 && codeBufSize == last) {
+                                               // nothing in entire block can be disassembled;
+                                               // at least tell the Disassembly view code this much
+                                               ret.add(pseudoInstruction(start, codeBufSize,
+                                                                                                 "Buffer Underflow during disassembly")); //$NON-NLS-1$
+                                       }
+                                       offset += codeBufSize;
+                               }
+                       } else {        // this will only occur when the target supports partial bad blocks
+                               ret.add(pseudoInstruction(block, codeBufSize,
+                                                                                 cantReadMemory(block.toHexAddressString(),
+                                                                                                                ((Integer)codeBufSize).toString())));
+                               offset += codeBufSize;
+                       }
+               }
+               return ret;
+       }
+
+       /**
+        * whereas the default implementation of getMixedInstructions() gets and
+        * processes all the disassembly in one pass, some variants are known to need
+        * to override the default implementation to break the retrieval into chunks.
+        * <p>
+        * this portion of the mixing is still the same within those chunks, though,
+        * and so has been extracted and protected for use by extending variant classes.
+        * @param mixedInstructions the growing list of instructions being processed
+        * @param wholeFunctionName name for whole function; if null, will be calculated per line
+        * @param module the module for this block of code
+        * @param codeLines list of ILineEntry containing info for mixing
+        * @param instructions the instructions to be mixed with the source
+        * @since 2.0
+        */
+       protected void mixSource(List<IMixedInstruction> mixedInstructions,
+                       final EDCInstructionFunctionInfo wholeBlockInfo,
+                       final IEDCModuleDMContext module,
+                       final List<ILineEntry> codeLines,
+                       final IInstruction[] instructions) {
+
+               List<IInstruction> instsForLine = new ArrayList<IInstruction>();
+
+               IPath filePath = null;
+               String osString = null;
+
+               EDCInstructionFunctionInfo functionInfo = wholeBlockInfo;
+               int k = 0, instsCnt = instructions.length, lineCnt = codeLines.size();
+               for (int i = 0; i < lineCnt && k < instsCnt; i++) {
+                       // Now map the instructions to source lines to generate
+                       // MixedInstructions.
+                       instsForLine.clear();
+                       ILineEntry line = codeLines.get(i);
+
+                       if (wholeBlockInfo == null && module != null) {
+                               functionInfo = new EDCInstructionFunctionInfo(module, line);
+                       }
+
+                       while (k < instsCnt) {
+                               EDCInstruction inst = (EDCInstruction)instructions[k];
+                               IAddress linkAddress = module.toLinkAddress(new Addr64(inst.getAdress()));
+                               if (linkAddress.compareTo(line.getHighAddress()) >= 0)
+                                       break;
+
+                               if (functionInfo != null) {
+                                       inst.setFunctionName(functionInfo.getFunctionName());
+                                       IAddress functionBase = functionInfo.getFunctionStartAddress();
+                                       if (functionBase != null) {
+                                               inst.setOffset(functionBase.distanceTo(linkAddress).intValue());
+                                       }
+                               }
+                               instsForLine.add(inst);
+                               k++;
+                       }
+                       if (line.getFilePath() != filePath) {
+                               filePath = line.getFilePath();
+                               osString = (filePath != null) ? filePath.toOSString() : null;
+                       }
+                       mixedInstructions.add(new EDCMixedInstruction(osString, line.getLineNumber(),
+                                                                                                                 instsForLine.toArray(new IInstruction[instsForLine.size()])));
+               }
+       }
+
+       /**
+        * disassembly utility function to find the first address for a line-entry 
+        * for an address contained by that line-entry
+        * @param symbolsService
+        * @param modulesService
+        * @param sym_dmc symbol context used to retrieve LineEntry for address
+        * @param initialStartAddress the address of interest
+        * @param endAddress the last address of a range to search
+        * @return the first address of an associated LineEntry if it can be found, else the initialStartAddress
+        * @since 2.0
+        */
+       protected static IAddress getStartAddressForLineEntryContainingAddress(final IEDCSymbols symbolsService,
+                       final IEDCModules modulesService, final ISymbolDMContext sym_dmc, final IAddress initialStartAddress,
+                       final IAddress endAddress) {
+               assert symbolsService != null && modulesService != null;
+               if (symbolsService == null || modulesService == null)
+                       return initialStartAddress;
+
+               if (sym_dmc != null) {
+                       // in case the caller requested a start that falls somewhere other than the
+                       // boundary of an instruction, back up to that boundary for the first instruction
+                       if (symbolsService.getLineEntryForAddress(sym_dmc, initialStartAddress) != null) {
+                               IEDCModuleDMContext module = modulesService.getModuleByAddress(sym_dmc, initialStartAddress);
+                               if (module != null) {
+                                       List<ILineEntry> allLines
+                                         = symbolsService.getLineEntriesForAddressRange(sym_dmc, initialStartAddress, endAddress);
+                                       if (allLines != null && !allLines.isEmpty())
+                                       {
+                                               return module.toRuntimeAddress(allLines.get(0).getLowAddress());
+                                       }
+                               }
+                       }
+               }
+               return initialStartAddress;
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/EDCServicesTracker.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/EDCServicesTracker.java
new file mode 100644 (file)
index 0000000..b7d2320
--- /dev/null
@@ -0,0 +1,242 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Convenience class to help track DSF services that a given
+ * client needs to use.  This class is based on the DsfServicesTracker
+ * but is designed to be thread safe so clients can use it to get
+ * a service reference from any thread. This is important for EDC
+ * services because they are not restricted to the Dsf thread.
+ * 
+ * @since 2.0
+ */
+public class EDCServicesTracker {
+       
+    private static String getServiceFilter(String sessionId) {
+        return ("(" + IDsfService.PROP_SESSION_ID + "=" + sessionId + ")").intern();   //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+    final private static class ServiceKey 
+    {
+        private final String fClassName;
+        private final String fFilter;
+        private final int fHashCode;
+        private final String fHashString;
+        
+        
+        public ServiceKey(Class<?> clazz, String filter) {
+            fClassName = clazz != null ? clazz.getName() : null;
+            fFilter = filter;
+            fHashString =  'C' + (fClassName == null ? "" : fClassName) + //$NON-NLS-1$
+                                          'F' + (fFilter == null ? "" : fFilter); //$NON-NLS-1$
+            fHashCode = fHashString.hashCode();
+        }
+        
+        @Override
+        public boolean equals(Object other) {
+               // hashcodes are not guaranteed to be unique, but objects that are equal must have the same hashcode
+               // thus we can optimize by first comparing hashcodes
+            return other instanceof ServiceKey &&
+               ((((ServiceKey)other).fHashCode == this.fHashCode) && (((ServiceKey)other).fHashString.equals(this.fHashString))); 
+        }
+        
+        @Override
+        public int hashCode() {
+               return fHashCode;
+        }
+    }
+    
+    private final String fSessionId;    
+    private volatile boolean fDisposed = false;
+    private final BundleContext fBundleContext;
+
+    @SuppressWarnings("rawtypes")
+       private final Map<ServiceKey,ServiceReference> fServiceReferences = Collections.synchronizedMap(new HashMap<ServiceKey,ServiceReference>());
+    @SuppressWarnings("rawtypes")
+       private final Map<ServiceReference,Object> fServices = Collections.synchronizedMap(new HashMap<ServiceReference,Object>());
+    private final String fServiceFilter;
+
+    private final ServiceListener fListner = new ServiceListener() {
+        public void serviceChanged(final ServiceEvent event) {
+            // Only listen to unregister events.
+            if (event.getType() != ServiceEvent.UNREGISTERING) {
+                return;
+            }
+            
+            // If session is not active anymore, just exit.  The tracker should 
+            // soon be disposed.
+            DsfSession session = DsfSession.getSession(fSessionId);
+            if (session == null) {
+                return;
+            }
+            
+            handleUnregisterEvent(event);
+        }
+    };
+    
+    @SuppressWarnings("rawtypes")
+       private void handleUnregisterEvent(ServiceEvent event) {
+       synchronized (fServiceReferences)
+       {
+            for (Iterator<Map.Entry<ServiceKey, ServiceReference>> itr = fServiceReferences.entrySet().iterator(); itr.hasNext();) {
+                Map.Entry<ServiceKey, ServiceReference> entry = itr.next();
+                if ( entry.getValue().equals(event.getServiceReference()) ) {
+                    itr.remove();
+                }
+            }
+            if (fServices.remove(event.getServiceReference()) != null) {
+                fBundleContext.ungetService(event.getServiceReference());
+            }
+       }
+    }
+    
+    /** 
+     * Only constructor.
+     * @param bundleContext Context of the plugin that the client lives in. 
+     * @param sessionId The DSF session that this tracker will be used for. 
+     */
+    public EDCServicesTracker(BundleContext bundleContext, String sessionId) {
+        fSessionId = sessionId;
+        fBundleContext = bundleContext;
+        fServiceFilter = getServiceFilter(sessionId); 
+        try {
+            fBundleContext.addServiceListener(fListner, fServiceFilter);
+        } catch (InvalidSyntaxException e) {
+            assert false : "Invalid session ID syntax"; //$NON-NLS-1$
+        }
+    }
+    
+    /**
+     * Retrieves a service reference for given service class and optional filter.  
+     * Filter should be used if there are multiple instances of the desired service
+     * running within the same session. 
+     * @param serviceClass class of the desired service
+     * @param custom filter to use when searching for the service, this filter will 
+     * be used instead of the standard filter so it should also specify the desired 
+     * session-ID 
+     * @return OSGI service reference object to the desired service, null if not found
+     */
+    @SuppressWarnings("rawtypes")
+    public ServiceReference getServiceReference(Class serviceClass, String filter) {
+        if (fDisposed) {
+            return null;
+        }
+        
+        // If the session is not active, all of its services are gone.
+        DsfSession session = DsfSession.getSession(fSessionId);
+        if (session == null) {
+            return null;
+        }
+        
+        ServiceKey key = new ServiceKey(serviceClass, filter != null ? filter : fServiceFilter);
+        if (fServiceReferences.containsKey(key)) {
+            return fServiceReferences.get(key);
+        }
+        
+        try {
+            ServiceReference[] references = fBundleContext.getServiceReferences(key.fClassName, key.fFilter);
+            assert references == null || references.length <= 1;
+            if (references == null || references.length == 0) {
+                return null;
+            } else {
+                fServiceReferences.put(key, references[0]);
+                return references[0];
+            }
+        } catch(InvalidSyntaxException e) {
+            assert false : "Invalid session ID syntax"; //$NON-NLS-1$
+        } catch(IllegalStateException e) {
+            // Can occur when plugin is shutting down.
+        }
+        return null;
+    }
+    
+    /**
+     * Convenience class to retrieve a service based on class name only.
+     * @param serviceClass class of the desired service
+     * @return instance of the desired service, null if not found
+     */
+    public <V> V getService(Class<V> serviceClass) {
+        return getService(serviceClass, null);
+    }
+    
+    /** 
+     * Retrieves the service given service class and optional filter.
+     * Filter should be used if there are multiple instances of the desired service
+     * running within the same session. 
+     * @param serviceClass class of the desired service
+     * @param custom filter to use when searching for the service, this filter will 
+     * be used instead of the standard filter so it should also specify the desired 
+     * session-ID 
+     * @return instance of the desired service, null if not found
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public <V> V getService(Class<V> serviceClass, String filter) {
+        ServiceReference serviceRef = getServiceReference(serviceClass, filter);
+        if (serviceRef == null) {
+            return null;
+        } else {
+            if (fServices.containsKey(serviceRef)) {
+                return (V)fServices.get(serviceRef);
+            } else {
+                V service = (V)fBundleContext.getService(serviceRef);
+                fServices.put(serviceRef, service);
+                return service;
+            }
+        }
+    }
+    
+    /**
+     * Un-gets all the references held by this tracker.  Must be called
+     * to avoid leaking OSGI service references.
+     */
+    public void dispose() {
+        assert !fDisposed;
+        fDisposed = true;
+        doDispose();
+    }
+
+    @SuppressWarnings("rawtypes")
+       private void doDispose() {
+       synchronized (fServices)
+       {
+            try {
+                fBundleContext.removeServiceListener(fListner);
+                for (Iterator<ServiceReference> itr = fServices.keySet().iterator(); itr.hasNext();) {
+                    fBundleContext.ungetService(itr.next());
+                }
+            } catch (IllegalStateException e) {
+                // May be thrown during shutdown (bug 293049).
+            }
+       }
+        fServices.clear();
+        fServiceReferences.clear();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        assert fDisposed;
+        super.finalize();
+    }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IDSFServiceUsingTCF.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IDSFServiceUsingTCF.java
new file mode 100644 (file)
index 0000000..9c8b0f2
--- /dev/null
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.services;
+
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.tm.tcf.protocol.IService;
+
+/**
+ * This is used to link a TCF service to the DSF service that needs it. Objects
+ * that implement {@link IDsfService} using TCF should implement this as well.
+ * 
+ * @author LWang
+ * 
+ */
+public interface IDSFServiceUsingTCF {
+       
+       /**
+        * Tells this DSF service that the TCF service it uses is ready for action.
+        *
+        * @param service the TCF service
+        */
+       public void tcfServiceReady(IService service);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCDMContext.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCDMContext.java
new file mode 100644 (file)
index 0000000..4d8e8dd
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import java.util.Map;
+
+public interface IEDCDMContext {
+
+       /**
+        * Context property description.
+        */
+       public static final String PROP_DESCRIPTION = "Description";
+
+       /**
+        * Context property id.
+        */
+       public static final String PROP_ID = "ID";
+
+       /**
+        * Context property name.
+        */
+       public static final String PROP_NAME = "Name";
+
+       /**
+        * Context property value.
+        */
+       public static final String PROP_VALUE = "Value";
+
+       public Object getProperty(String key);
+
+       public Map<String, Object> getProperties();
+
+       public String getName();
+
+       public void setName(String name);
+
+       public void setProperty(String name, Object object);
+
+       public String getID();
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCExecutionDMC.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCExecutionDMC.java
new file mode 100644 (file)
index 0000000..8fbf5d1
--- /dev/null
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+
+public interface IEDCExecutionDMC extends IExecutionDMContext,IMemoryDMContext, IEDCDMContext {
+
+       public boolean isSuspended();
+       
+       public ISymbolDMContext getSymbolDMContext();
+
+       /**
+        * Does the context (usually a thread) want to be auto-selected/focused in
+        * Eclipse Debug View on suspend ? When this is true, EDC will try to honor
+        * it, but not guaranteed. If multiple contexts ask for focus, EDC will
+        * choose one based on some other standards. See where this is invoked for
+        * more.
+        * 
+        * @since 2.0
+        */
+       public boolean wantFocusInUI();
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCExpression.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCExpression.java
new file mode 100644 (file)
index 0000000..2449caf
--- /dev/null
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.debug.edc.symbols.IType;
+import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions2.CastInfo;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.core.runtime.IStatus;
+
+public interface IEDCExpression extends IExpressionDMContext, IEDCDMContext {
+
+       public Executor getExecutor();
+       /**
+        * @since 2.0
+        */
+       public IEDCExpressions getExpressionsService();
+
+       /**
+        * Change the name of the expression that appears in the Variables view Name
+        * column or the Expressions view Expression column.  This is typically
+        * used to make the subexpressions of an expression show only the
+        * suffix of the expression relative to the parent expression and
+        * to differentiates children from each other (though it is not intended
+        * to have any syntactic significance when catenated to the parent).
+        * 
+        * Note: {@link #getExpression()} is always the full expression.
+        */
+       public void setName(String name);
+       
+       public IFrameDMContext getFrame();
+
+       public void evaluateExpression();
+
+       public FormattedValueDMData getFormattedValue(FormattedValueDMContext dmc);
+
+       public IVariableLocation getValueLocation();
+
+       /** Get error during evaluation, or <code>null</code> if no error, or {@link #evaluateExpression()} has not been called */
+       public IStatus getEvaluationError();
+       /** Get numeric value after {@link #evaluateExpression()} */
+       public Number getEvaluatedValue();
+       /** Get string value after {@link #evaluateExpression()}, or the string value for
+        * a string expression, or the formatted value set by {@link #setEvaluatedValueString(String)} */
+       public String getEvaluatedValueString();
+
+       public void setEvaluatedValue(Number value);
+       public void setEvaluatedValueString(String string);
+
+       public IVariableLocation getEvaluatedLocation();
+
+       public IType getEvaluatedType();
+
+       public String getTypeName();
+
+       public boolean hasChildren();
+
+       /** Get any casting in effect.  May be <code>null</code>. */
+       public CastInfo getCastInfo();
+
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCExpressions.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCExpressions.java
new file mode 100644 (file)
index 0000000..d30712b
--- /dev/null
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import org.eclipse.cdt.dsf.debug.service.IExpressions2;
+
+/**
+ * Interface to the EDC Expressions service.
+ * @since 2.0
+ */
+public interface IEDCExpressions extends IExpressions2 {
+
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCMemory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCMemory.java
new file mode 100644 (file)
index 0000000..0416276
--- /dev/null
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import java.util.ArrayList;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.debug.core.model.MemoryByte;
+
+/**
+ * Interface to the EDC memory service. Used for synchronous access to
+ * target memory.
+ */
+public interface IEDCMemory extends IMemory, IEDCService {
+
+       /**
+        * Fills a buffer with the contents of a range of memory.
+        *
+        * @param context the executable context
+        * @param address the starting address of the range of memory
+        * @param memBuffer the buffer to be filled with the memory contents
+        * @param count the number of words to read
+        * @param word_size the word_size
+        * @return status of the memory request
+        */
+       public IStatus getMemory(IEDCExecutionDMC context, IAddress address,
+                       final ArrayList<MemoryByte> memBuffer, int count, int word_size);
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCModuleDMContext.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCModuleDMContext.java
new file mode 100644 (file)
index 0000000..9d7785a
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
+import org.eclipse.cdt.dsf.debug.service.IModules.IModuleDMContext;
+
+public interface IEDCModuleDMContext extends IModuleDMContext, IEDCDMContext {
+
+       /**
+        * Convert link address to runtime address.
+        * 
+        * @param linkAddress
+        * @return null if the given link address is not in the module.
+        */
+       public IAddress toRuntimeAddress(IAddress linkAddress);
+
+       /**
+        * Convert runtime address to link address.
+        * 
+        * @param runtimeAddress
+        * @return null if the given runtime address is not in the module.
+        */
+       public IAddress toLinkAddress(IAddress runtimeAddress);
+
+       /**
+        * Gets the symbol reader used to read symbols for this module.
+        * 
+        * @return the symbol reader
+        */
+       public IEDCSymbolReader getSymbolReader();
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCModules.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCModules.java
new file mode 100644 (file)
index 0000000..69fb712
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+
+public interface IEDCModules extends IEDCService {
+
+       /**
+        * get module that contains the given runtime address.
+        * 
+        * @param symCtxs
+        * @param instructionAddress
+        *            runtime absolute address.
+        * @return null if not found.
+        */
+       public IEDCModuleDMContext getModuleByAddress(ISymbolDMContext symCtx,
+                       IAddress instructionAddress);
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCService.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCService.java
new file mode 100644 (file)
index 0000000..48c3f57
--- /dev/null
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * @since 2.0
+ */
+public interface IEDCService extends IDsfService {
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCSymbols.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCSymbols.java
new file mode 100644 (file)
index 0000000..be3999e
--- /dev/null
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+
+public interface IEDCSymbols extends IEDCService {
+       /**
+        * Preference to show all variables that are defined as global by the current source file 
+        */
+       public static final String SHOW_ALL_VARIABLES_ENABLED = "show_all_variables_enabled";
+
+       /**
+        * Get the function at the given runtime address
+        * 
+        * @param context
+        *            the context
+        * @param runtimeAddress
+        *            the runtime address
+        * @return the function containing the given address, or null if none found
+        */
+       public IFunctionScope getFunctionAtAddress(ISymbolDMContext context,
+                       IAddress runtimeAddress);
+
+
+       /**
+        * Get the name of any arbitrary symbol at the given runtime address
+        * 
+        * @param context
+        *            the context
+        * @param runtimeAddress
+        *            the runtime address
+        * @return the name of the symbol the given address, or null if none found
+        * @since 2.0
+        */
+       public String getSymbolNameAtAddress(ISymbolDMContext context,
+                       IAddress runtimeAddress);
+
+       /**
+        * Get the line entry at the given runtime address
+        * 
+        * @param context
+        *            the context
+        * @param runtimeAddress
+        *            the runtime address
+        * @return the line entry for the given address, or null if none found
+        */
+       public ILineEntry getLineEntryForAddress(ISymbolDMContext context,
+                       IAddress runtimeAddress);
+
+       /**
+        * <p>
+        * Get source line entries with code that are between the given start and
+        * end startAddress.
+        * <p>
+        * This method is created mainly for supporting disassembly service.
+        * 
+        * @param context
+        * @param start
+        *            start runtime address
+        * @param end
+        *            end runtime address (exclusive).
+        * @return list of source line entries which may or may not be in the same
+        *         source file (note that even one compile unit may have code from
+        *         different source files). It's empty if the start address has no
+        *         source line.
+        */
+       public List<ILineEntry> getLineEntriesForAddressRange(
+                       ISymbolDMContext context, IAddress start, IAddress end);
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IFrameRegisterProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IFrameRegisterProvider.java
new file mode 100644 (file)
index 0000000..a95e3a6
--- /dev/null
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.services;
+
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Provide access to reading values of registers from other stack frames.
+ */
+public interface IFrameRegisterProvider {
+
+       /**
+        * Get the registers available at the given frame and address.
+        * @param session
+        * @param tracker
+        * @param context the frame
+        * @return {@link IFrameRegisters} or <code>null</code> if no information found
+        * @throws CoreException if fatal error handling the symbolics for the frame
+        * @since 2.0
+        */
+       IFrameRegisters getFrameRegisters(DsfSession session, EDCServicesTracker tracker, IFrameDMContext context) throws CoreException;
+       
+       void dispose();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IFrameRegisters.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IFrameRegisters.java
new file mode 100644 (file)
index 0000000..20bb54a
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.services;
+
+import java.math.BigInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Provide values of registers which may be in other stack frames.
+ * This instance is only valid for a given stack trace, since the current
+ * PC at each stack level is used to precisely determine the state of
+ * stored registers.
+ */
+public interface IFrameRegisters {
+       /**
+        * Get the value of the register.  
+        * @param regnum common register #
+        * @param bytes size of register to read (starting from least significant byte)
+        * @return value, never <code>null</code>
+        * @throws CoreException if cannot read
+        */
+       BigInteger getRegister(int regnum, int bytes) throws CoreException;
+       
+       /**
+        * Write the value into the register or its location in the frame.
+        * @param regnum <code>int</code> common register #
+        * @param bytes <code>int</code> size of register to write (starting from least significant byte)
+        * @param value <code>BigInteger</code>
+        * @throws CoreException if cannot write
+        */
+       void writeRegister(int regnum, int bytes, BigInteger value) throws CoreException;
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/ISnapshots.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/ISnapshots.java
new file mode 100644 (file)
index 0000000..6aa5281
--- /dev/null
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+public interface ISnapshots extends IDsfService {
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/ITargetEnvironment.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/ITargetEnvironment.java
new file mode 100644 (file)
index 0000000..8a23112
--- /dev/null
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.services;
+
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.IAddressExpressionEvaluator;
+import org.eclipse.cdt.debug.edc.disassembler.IDisassembler;
+import org.eclipse.cdt.debug.edc.tcf.extension.services.ISimpleRegisters;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.tm.tcf.services.IRegisters;
+
+/**
+ * DSF service that provides data peculiar to the environment the debugger is
+ * targeting. The environment here includes such things as target hardware, OS
+ * if any, and UI preferences for the debugger. <br>
+ * This service is supposed to be called by other DSF services so that they can
+ * be target independent as much as possible.
+ */
+public interface ITargetEnvironment extends IDsfService {
+
+       public final static String ARCH_X86 = "x86";
+       public final static String ARCH_ARM = "ARM";
+
+       public final static String OS_UNKNOWN = "unknown";
+       public final static String OS_WIN32 = "win32";
+       public final static String OS_LINUX = "linux";
+       public final static String OS_SYMBIAN = "symbian";
+
+       /**
+        * Get the string name of the target system architecture.
+        * 
+        * @return string name which is one of the predefined ARCH_xx string in
+        *         {@link ITargetEnvironment}. Cannot be null.
+        */
+       public String getArchitecture();
+
+       /**
+        * Get the string name of the target operating system (if any).
+        * 
+        * @return string name which is one of the predefined OS_xx string in
+        *         {@link ITargetEnvironment}. Cannot be null.
+        *         {@link ITargetEnvironment#OS_UNKNOWN} if the OS is unknown. Empty
+        *         string if there is no OS running.
+        */
+       public String getOS();
+
+       /**
+        * Get sizes of all basic C/C++ data types.
+        * 
+        * @return list of sizes, in bytes, of C/C++ data types. The returned map
+        *         should have TypeUtils#BASIC_TYPE_XXX constants for its keys, and
+        *         type sizes for their values
+        */
+       public Map<Integer, Integer> getBasicTypeSizes();
+
+       /**
+        * Get size of pointer data type
+        * 
+        * @return list of sizes, in bytes, of C/C++ data types
+        */
+       public int getPointerSize();
+
+       /**
+        * Get size of an enumeration data type
+        * 
+        * @return list of sizes, in bytes, of C/C++ data types
+        */
+       public int getEnumSize();
+
+       /**
+        * Get whether plain "char" is signed
+        * 
+        * @return whether "plain" char is signed
+        */
+       public boolean isCharSigned();
+
+       /**
+        * Get ID of program counter (PC) register. E.g. for X86, it could be "EIP". <br>
+        * <br>
+        * (This is temporarily needed with our current TCF {@link ISimpleRegisters}
+        * service. After we implement the TCF {@link IRegisters} service, this can
+        * be removed.)
+        * 
+        * @return string representation of the register ID.
+        */
+       public String getPCRegisterID();
+
+       /**
+        * Get length in bytes of the longest instruction in target architecture.
+        * This return value does not have to be precise, but must be larger than
+        * size of the longest instruction.
+        * 
+        * @return
+        */
+       public int getLongestInstructionLength();
+
+       /**
+        * Get breakpoint instruction that is used to set software breakpoint.<br>
+        * <br>
+        * For architecture like x86 the breakpoint instruction is invariant
+        * ("int 3" or "0xcc") thus the arguments are ignored. But for processor
+        * like ARM the instruction varies depending on processor mode (ARM or
+        * THUMB) in give context.
+        * 
+        * @param context
+        *            the runtime context, usually a process.
+        * @param address
+        *            runtime absolute address where to set a breakpoint.
+        * 
+        * @return byte array of the instruction.
+        */
+       public byte[] getBreakpointInstruction(IDMContext context, IAddress address);
+
+       /**
+        * Allows for modification or addition of target specific breakpoint
+        * properties before breakpoints are set. Note that this applies to TCF
+        * breakpoint service breakpoints.
+        * 
+        * @param context
+        *            the runtime context, usually a process.
+        * @param address
+        *            runtime absolute address where to set a breakpoint.
+        * @param properties
+        *            properties map
+        */
+       public void updateBreakpointProperties(IDMContext context, IAddress address, Map<String, Object> properties);
+
+       /**
+        * Is the target processor in little-endian ?
+        * 
+        * @param context
+        *            context for which the check is based on. For most cases this
+        *            argument can be ignored.
+        * @return
+        */
+       public boolean isLittleEndian(IDMContext context);
+
+       /**
+        * Get disassembler for the target.
+        * 
+        * @return {@link IDisassembler} object. Can be null which means
+        *         disassembler is not implemented yet for the target.
+        */
+       public IDisassembler getDisassembler();
+
+       /**
+        * Get address expression evaluator for the target.
+        * 
+        * @return {@link IAddressExpressionEvaluator} object. null means it's not
+        *         available yet for the target.
+        */
+       public IAddressExpressionEvaluator getAddressExpressionEvaluator();
+
+       /**
+        * In some target environments, user may specify two or more executables
+        * (including things like DLL) to debug in one debug session. This API
+        * allows the target environment to tell EDC in which executable(s) it wants
+        * EDC to try to set startup breakpoint.
+        * 
+        * @param exeName
+        *            a name with or without path.
+        * @return true if the environment wants EDC to try setting startup
+        *         breakpoint in the executable. False otherwise.
+        * @since 2.0
+        */
+       public boolean needStartupBreakpointInExecutable(String exeName);
+       
+       /**
+        * Get minimum size of a memory block that is read and stored in memory
+        * cache. For instance, if the size is 64 bytes, then for a memory read
+        * request that requests 4 bytes, the debugger will read and cache 64 bytes.
+        * Different targets may prefer different size.
+        * 
+        * @return size in bytes. zero (0) means to just cache the number of bytes
+        *         actually requested.
+        */
+       public int getMemoryCacheMinimumBlockSize();
+       
+       /**
+        * Get value of any given property.<br>
+        * <br>
+        * This generic API allows getting any new target property without adding
+        * new API that breaks backward compatibility.
+        * 
+        * @param propertyKey
+        * @return
+        */
+       public String getProperty(String propertyKey);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Messages.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Messages.java
new file mode 100644 (file)
index 0000000..b80e837
--- /dev/null
@@ -0,0 +1,21 @@
+package org.eclipse.cdt.debug.edc.services;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @since 2.0
+ */
+public class Messages extends NLS {
+       private static final String BUNDLE_NAME = "org.eclipse.cdt.debug.edc.services.messages"; //$NON-NLS-1$
+       public static String AbstractEDCService_0;
+       public static String AbstractEDCService_1;
+       public static String AbstractEDCService_2;
+       public static String AbstractEDCService_3;
+       static {
+               // initialize resource bundle
+               NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+       }
+
+       private Messages() {
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Registers.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Registers.java
new file mode 100644 (file)
index 0000000..3158061
--- /dev/null
@@ -0,0 +1,1237 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.debug.edc.MemoryUtils;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.NumberFormatUtils;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.SuspendedEvent;
+import org.eclipse.cdt.debug.edc.internal.snapshot.SnapshotUtils;
+import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
+import org.eclipse.cdt.debug.edc.snapshot.IAlbum;
+import org.eclipse.cdt.debug.edc.snapshot.ISnapshotContributor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.tm.tcf.protocol.IService;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.services.IRegisters.RegistersContext;
+import org.eclipse.tm.tcf.util.TCFTask;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * The Registers service provides information about the target processor
+ * registers.
+ */
+public abstract class Registers extends AbstractEDCService implements IRegisters, ICachingService, IDSFServiceUsingTCF {
+
+       /**
+        * Cache register groups per context.
+        * Keyed on context ID.
+        */
+       private Map<String, List<RegisterGroupDMC>> registerGroupsPerContext = 
+               Collections.synchronizedMap(new HashMap<String, List<RegisterGroupDMC>>());
+
+       /** The TCF registers service. */
+       protected org.eclipse.tm.tcf.services.IRegisters                tcfRegistersService = null;
+       
+       /**
+        * Register value cache per execution context.
+        * Keyed on context ID.
+        */
+       private Map<String, Map<String, BigInteger>> registerValueCache = 
+               Collections.synchronizedMap(new HashMap<String, Map<String, BigInteger>>());
+
+       /** Iimeout value in milliseconds when waiting for a response from the TCF service. */
+       private long tcfTimeout;
+
+       /**
+        * A hex string indicating error in register read.
+        * See where this is used for more.
+        */
+       protected static final String REGISTER_VALUE_ERROR = "badbadba";
+       
+       public static final String PROP_EXECUTION_CONTEXT_ID = "Context_ID";
+
+       private static final String REGISTER = "register";
+
+       /**
+        * Represents a group of registers.
+        */
+       public class RegisterGroupDMC extends DMContext implements IRegisterGroupDMContext, ISnapshotContributor {
+
+               private static final String REGISTER_GROUP = "register_group";
+
+               /** The registers in this group. */
+               private List<RegisterDMC> registers = Collections.synchronizedList(new ArrayList<RegisterDMC>());
+
+               /** The executable context. */
+               private final IEDCExecutionDMC exeContext;
+
+               /**
+                * Instantiates a new register group dmc.
+                *
+                * @param service the service
+                * @param executionDMC the execution context
+                * @param groupName the group name
+                * @param groupDescription the group description
+                * @param groupID the group id
+                */
+               public RegisterGroupDMC(Registers service, IEDCExecutionDMC executionDMC, String groupName, String groupDescription,
+                               String groupID) {
+                       super(service, new IDMContext[] { executionDMC }, groupName, groupID);
+                       exeContext = executionDMC;
+                       properties.put(PROP_DESCRIPTION, groupDescription);
+                       properties.put(PROP_EXECUTION_CONTEXT_ID, executionDMC.getID());
+               }
+
+               /**
+                * Instantiates a new register group dmc.
+                *
+                * @param service the service
+                * @param executionDmc the execution dmc
+                * @param props the props
+                */
+               public RegisterGroupDMC(Registers service, IEDCExecutionDMC executionDmc,
+                                                               Map<String, Object> props) {
+                       super(service, new IDMContext[] { executionDmc }, props);
+                       exeContext = executionDmc;
+                       properties.put(PROP_EXECUTION_CONTEXT_ID, exeContext.getID());
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.services.DMContext#toString()
+                */
+               @Override
+               public String toString() {
+                       return baseToString() + ".group[" + getName() + "]";} //$NON-NLS-1$ //$NON-NLS-2$
+
+               /**
+                * Gets the registers for this group.
+                *
+                * @return array of register contexts for this group
+                * @throws CoreException the core exception
+                */
+               public RegisterDMC[] getRegisters() throws CoreException {
+                       RegisterDMC[] result = new RegisterDMC[0];
+                       synchronized (registers) {
+                               if (registers.size() == 0) {
+                                       registers = Registers.this.createRegistersForGroup(this);
+                               }
+                               result = registers.toArray(new RegisterDMC[registers.size()]);
+                       }
+                       return result;
+               }
+
+               /**
+                * Take a snapshot of this group of registers.
+                *
+                * @param album the snapshot album
+                * @param document the XML document
+                * @param monitor the progress monitor
+                * @return the XML element
+                * @throws Exception the exception if anything goes wrong
+                * @since 2.0
+                */
+               public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor)throws Exception {
+                       Element contextElement = document.createElement(REGISTER_GROUP);
+                       contextElement.setAttribute(PROP_ID, this.getID());
+
+                       Element propsElement = SnapshotUtils.makeXMLFromProperties(document, getProperties());
+                       contextElement.appendChild(propsElement);
+
+                       RegisterDMC[] allRegisters = getRegisters();
+                       SubMonitor progress = SubMonitor.convert(monitor, allRegisters.length * 1000);
+                       progress.subTask("Registers");
+                       for (RegisterDMC registerDMC : allRegisters) {
+                               Element dmcElement = registerDMC.takeSnapshot(album, document, progress.newChild(1000));
+                               contextElement.appendChild(dmcElement);
+                       }
+                       return contextElement;
+               }
+
+               /**
+                * Gets the execution dmc.
+                *
+                * @return the execution dmc
+                */
+               public IEDCExecutionDMC getExecutionDMC() {
+                       return exeContext;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.snapshot.ISnapshotContributor#loadSnapshot(org.w3c.dom.Element)
+                */
+               public void loadSnapshot(Element element) throws Exception {
+                       NodeList registerElement = element.getElementsByTagName(REGISTER);
+
+                       int numRegisters = registerElement.getLength();
+                       for (int i = 0; i < numRegisters; i++) {
+                               Element regElement = (Element) registerElement.item(i);
+                               Element propElement = (Element) regElement.getElementsByTagName(SnapshotUtils.PROPERTIES).item(0);
+                               HashMap<String, Object> properties = new HashMap<String, Object>();
+                               SnapshotUtils.initializeFromXML(propElement, properties);
+
+                               RegisterDMC regdmc = new RegisterDMC(this, exeContext, properties);
+                               regdmc.loadSnapshot(regElement);
+                               registers.add(regdmc);
+                       }
+
+               }
+
+       }
+
+       /**
+        * Represents the context for a single register.
+        */
+       public class RegisterDMC extends DMContext implements IRegisterDMContext, ISnapshotContributor {
+
+               /** The context used by the TCF agent. */
+               private org.eclipse.tm.tcf.services.IRegisters.RegistersContext tcfContext = null;
+               
+               /**
+                * Instantiates a new register dmc.
+                *
+                * @param executableDMC the executable context
+                * @param name the register name
+                * @param description the register description
+                * @param id the register id
+                */
+               public RegisterDMC(IEDCExecutionDMC executableDMC, String name, String description, String id) {
+                       super(Registers.this, new IDMContext[] { executableDMC }, name, id);
+                       properties.put(PROP_EXECUTION_CONTEXT_ID, executableDMC.getID());
+               }
+
+               /**
+                * Instantiates a new register dmc.
+                *
+                * @param registerGroupDmc the register group dmc
+                * @param executableDMC the executable context
+                * @param properties the properties
+                */
+               public RegisterDMC(RegisterGroupDMC registerGroupDmc, IEDCExecutionDMC executableDMC,
+                                                       Map<String, Object> properties) {
+                       super(Registers.this, new IDMContext[] { executableDMC }, properties);
+                       this.properties.put(PROP_EXECUTION_CONTEXT_ID, executableDMC.getID());
+               }
+
+               /**
+                * Construct based on underlying context from TCF IRegisters service.
+                *
+                * @param registerGroupDMC the register group dmc
+                * @param executableDMC the executable context
+                * @param tcfContext the tcf context
+                */
+               public RegisterDMC(RegisterGroupDMC registerGroupDMC, IEDCExecutionDMC executableDMC, RegistersContext tcfContext) {
+                       super(Registers.this, new IDMContext[] { registerGroupDMC }, tcfContext.getProperties());
+                       this.properties.put(PROP_EXECUTION_CONTEXT_ID, executableDMC.getID());
+                       
+                       this.tcfContext = tcfContext;
+               }
+
+               /**
+                * Get the underlying TCF context.
+                * @return may be null.
+                */
+               public RegistersContext getTCFContext() {
+                       return tcfContext;
+               }
+               
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.services.DMContext#toString()
+                */
+               @Override
+               public String toString() {
+                       return baseToString() + ".register[" + getName() + "]";} //$NON-NLS-1$ //$NON-NLS-2$
+
+               /**
+                * Take a snapshot of this register.
+                *
+                * @param album the snapshot album
+                * @param document the XML document
+                * @param monitor the progress monitor
+                * @return the XML element
+                * @throws Exception the exception if anything goes wrong
+                * @since 2.0
+                */
+               public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor) throws Exception {
+                       Element registerElement = document.createElement(REGISTER);
+                       registerElement.setAttribute(PROP_ID, this.getID());
+                       registerElement.setAttribute(PROP_VALUE, getRegisterValueAsHexString(this));
+                       Element propsElement = SnapshotUtils.makeXMLFromProperties(document, getProperties());
+                       registerElement.appendChild(propsElement);
+                       return registerElement;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.debug.edc.snapshot.ISnapshotContributor#loadSnapshot(org.w3c.dom.Element)
+                */
+               public void loadSnapshot(Element element) throws Exception {
+                       String registerValue = element.getAttribute(PROP_VALUE);
+                       String contextID = (String) getProperties().get(PROP_EXECUTION_CONTEXT_ID);
+
+                       synchronized (registerValueCache) {
+                               Map<String, BigInteger> exeDMCRegisters = registerValueCache.get(contextID);
+                               if (exeDMCRegisters == null) {
+                                       exeDMCRegisters = new HashMap<String, BigInteger>();
+                                       registerValueCache.put(contextID, exeDMCRegisters);
+                               }
+                               exeDMCRegisters.put(getID(), new BigInteger(registerValue, 16));
+                       }
+               }
+       }
+
+       class RegisterData implements IRegisterDMData {
+
+               private final HashMap<String, Object> properties = new HashMap<String, Object>();
+
+               public RegisterData(Map<String, Object> properties) {
+                       this.properties.putAll(properties);
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData#isReadable()
+                */
+               public boolean isReadable() {
+            Boolean n = (Boolean)properties.get(org.eclipse.tm.tcf.services.IRegisters.PROP_READBLE);
+            if (n == null) 
+               return true;
+            return n.booleanValue();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData#isReadOnce()
+                */
+               public boolean isReadOnce() {
+            Boolean n = (Boolean)properties.get(org.eclipse.tm.tcf.services.IRegisters.PROP_READ_ONCE);
+            if (n == null) 
+               return false;
+            return n.booleanValue();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData#isWriteable()
+                */
+               public boolean isWriteable() {
+            Boolean n = (Boolean)properties.get(org.eclipse.tm.tcf.services.IRegisters.PROP_WRITEABLE);
+            if (n == null) 
+               return true;
+            return n.booleanValue();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData#isWriteOnce()
+                */
+               public boolean isWriteOnce() {
+            Boolean n = (Boolean)properties.get(org.eclipse.tm.tcf.services.IRegisters.PROP_WRITE_ONCE);
+            if (n == null) 
+               return false;
+            return n.booleanValue();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData#hasSideEffects()
+                */
+               public boolean hasSideEffects() {
+            Boolean n = (Boolean)properties.get(org.eclipse.tm.tcf.services.IRegisters.PROP_SIDE_EFFECTS);
+            if (n == null) 
+               return false;
+            return n.booleanValue();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData#isVolatile()
+                */
+               public boolean isVolatile() {
+            Boolean n = (Boolean)properties.get(org.eclipse.tm.tcf.services.IRegisters.PROP_VOLATILE);
+            if (n == null) 
+               return false;
+            return n.booleanValue();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData#isFloat()
+                */
+               public boolean isFloat() {
+            Boolean n = (Boolean)properties.get(org.eclipse.tm.tcf.services.IRegisters.PROP_FLOAT);
+            if (n == null) 
+               return false;
+            return n.booleanValue();
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData#getName()
+                */
+               public String getName() {
+                       return (String) properties.get(IEDCDMContext.PROP_NAME);
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData#getDescription()
+                */
+               public String getDescription() {
+                       return (String) properties.get(IEDCDMContext.PROP_DESCRIPTION);
+               }
+
+       }
+
+       /**
+        * Event class to notify register value is changed
+        */
+       public static class RegisterChangedDMEvent implements IRegisters.IRegisterChangedDMEvent {
+
+               /** The register dmc. */
+               private final IRegisterDMContext fRegisterDMC;
+
+               /**
+                * Instantiates a new register changed dm event.
+                *
+                * @param registerDMC the register dmc
+                */
+               RegisterChangedDMEvent(IRegisterDMContext registerDMC) {
+                       fRegisterDMC = registerDMC;
+               }
+
+               /* (non-Javadoc)
+                * @see org.eclipse.cdt.dsf.datamodel.IDMEvent#getDMContext()
+                */
+               public IRegisterDMContext getDMContext() {
+                       return fRegisterDMC;
+               }
+       }
+
+       /**
+        * Instantiates a new Registers service.
+        *
+        * @param session the session
+        * @param classNames the type names the service will be registered under. See
+        * AbstractDsfService#register for details. We tack on base DSF's
+        * IRegisters and this class to the list if missing.
+        */
+       public Registers(DsfSession session, String[] classNames) {
+               super(session, 
+                               massageClassNames(classNames,
+                                               new String[] {IRegisters.class.getName(), Registers.class.getName()}));
+               setTCFTimeout(15 * 1000); // Fifteen seconds
+       }
+
+       /**
+        * Find register DMC by register name. <br>
+        * 
+        * It's required the register name be known/recognizable to TCF agent,
+        * meaning host debugger still cannot be totally target neutral on register
+        * access. TCF IRegisters service allows us to access common registers such
+        * as PC, LP and SP in a target-independent way (using Role property). But
+        * debugger need to access other registers (e.g. R0, R1, CPSR on ARM) for
+        * stack crawl and variable evaluation.
+        *
+        * @param exeDMC the exe dmc
+        * @param name the name
+        * @return the register dmc
+        * @throws CoreException the core exception
+        * @since 2.0
+        */
+       public RegisterDMC findRegisterDMCByName(IEDCExecutionDMC exeDMC, String name) throws CoreException {
+               assert RunControl.isNonContainer(exeDMC);
+               
+               // this will create the reg groups for the exeDMC if not yet. 
+               IRegisterGroupDMContext[] regGroups = getGroupsForContext(exeDMC);
+               
+               for (IRegisterGroupDMContext g : regGroups) {
+                       // Note the getRegisters() will create registerDMCs for the group if not yet. 
+                       for (RegisterDMC reg : ((RegisterGroupDMC)g).getRegisters()) {
+                               String n = (String)reg.getProperties().get(org.eclipse.tm.tcf.services.IRegisters.PROP_NAME);
+                               if (name.equals(n))
+                                       return reg;
+                       }
+               }
+               
+               return null;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.services.AbstractEDCService#doInitialize(org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+        */
+       @Override
+       protected void doInitialize(RequestMonitor requestMonitor) {
+               super.doInitialize(requestMonitor);
+               getSession().addServiceEventListener(this, null);
+       }
+
+       /**
+        * Gets the groups for context.
+        *
+        * @param executableContext the executable context
+        * @return the groups for context
+        * @throws CoreException the core exception
+        */
+       public IRegisterGroupDMContext[] getGroupsForContext(IEDCExecutionDMC executableContext) throws CoreException {
+               String contextID = executableContext.getID();
+               List<RegisterGroupDMC> groupsForContext = registerGroupsPerContext.get(contextID);
+               if (groupsForContext == null) {
+                       groupsForContext = createGroupsForContext(executableContext);
+                       synchronized (registerGroupsPerContext) {
+                               registerGroupsPerContext.put(contextID, groupsForContext);
+                       }
+               }
+               return groupsForContext.toArray(new IRegisterGroupDMContext[groupsForContext.size()]);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#writeBitField(org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMContext, java.lang.String, java.lang.String, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+        */
+       public void writeBitField(IBitFieldDMContext bitFieldCtx, String bitFieldValue, String formatId, RequestMonitor rm) {
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#writeBitField(org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMContext, org.eclipse.cdt.dsf.debug.service.IRegisters.IMnemonic, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+        */
+       public void writeBitField(IBitFieldDMContext bitFieldCtx, IMnemonic mnemonic, RequestMonitor rm) {
+               rm.done();
+       }
+
+       /**
+        * Writes a value to a register.
+        *
+        * @param context the context
+        * @param regID register name.
+        * @param regValue big-endian hex string representation of the value to write.
+        * @throws CoreException the core exception
+        */
+       public void writeRegister(IEDCExecutionDMC context, String regID, String regValue) throws CoreException {
+               RegisterDMC regDMC;
+               
+               regDMC = findRegisterDMCByName(context, regID);
+               assert regDMC != null;
+               
+               writeRegister(regDMC, regValue, IFormattedValues.HEX_FORMAT,
+                               new RequestMonitor(getExecutor(), null));
+       }
+
+       /**
+        * Writes a value to a register
+        * @throws CoreException 
+        * @since 2.0
+        */
+       public void writeRegister(IRegisterDMContext regCtx, String regValue, String formatID) throws CoreException {
+               assert (regCtx instanceof RegisterDMC);
+
+               final RegisterDMC regDMC = (RegisterDMC) regCtx;
+               IExecutionDMContext exeDMC = DMContexts.getAncestorOfType(regDMC, IExecutionDMContext.class);
+               if (exeDMC == null || !(exeDMC instanceof IEDCDMContext)) {
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(),
+                                       "No valid execution context for finding the register ID"));
+               }
+
+               final String exeDMCID = ((IEDCDMContext) exeDMC).getID();
+               
+               // Put the incoming value into hex
+               if (formatID.equals(IFormattedValues.OCTAL_FORMAT) || formatID.equals(IFormattedValues.BINARY_FORMAT) ||
+                               formatID.equals(IFormattedValues.DECIMAL_FORMAT))
+               {
+                       BigInteger bigRegValue = null;
+                       
+                       try {
+                               bigRegValue = NumberFormatUtils.parseIntegerByFormat(regValue, formatID);
+                       } catch (NumberFormatException e) {
+                               throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(),
+                                               "Cannot change register to invalid value \"" + regValue + "\""));
+                       }
+                       // if bigRegValue is negative, using bigRegValue.toString(16) directly gives values such as '-af'
+                       regValue = Long.toHexString(bigRegValue.longValue());
+               }
+
+               // if register value string is too long, truncate to register size (2 hex chars per byte)
+               if (tcfRegistersService != null) {      // TCF IRegisters service available)
+                       int regSize = regDMC.getTCFContext().getSize();
+                       if (regValue.length() > regSize * 2)
+                               regValue = regValue.substring(regValue.length() - regSize * 2);
+               }
+
+               if (tcfRegistersService != null) {      // TCF IRegisters service available
+                       final RegistersContext tcfReg = regDMC.getTCFContext();
+                       byte[] bv = null;
+                       try {
+                               bv = MemoryUtils.convertHexStringToByteArray(regValue, tcfReg.getSize(), 2);
+                       } catch (NumberFormatException e) {
+                               throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(),
+                                               "Cannot change register to invalid value \"" + regValue + "\""));
+                       }
+                       
+                       final byte[] byteVal = bv;
+                       
+                       TCFTask<Object> tcfTask = new TCFTask<Object>() {
+                               public void run() {
+                                       tcfReg.set(byteVal, new org.eclipse.tm.tcf.services.IRegisters.DoneSet() {
+                                               public void doneSet(IToken token, Exception error) {
+                                                       if (error == null) {
+                                                               generateRegisterChangedEvent(regDMC);
+                                                               done(null);
+                                                       } else {
+                                                               done(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INTERNAL_ERROR,
+                                                                               "Error writing register.", error));
+                                                       }
+                                               }
+                                       });
+                               }
+                       };
+
+                       try {
+                               Object result = tcfTask.get(getTCFTimeout(), TimeUnit.MILLISECONDS);
+                               if (result != null && result instanceof IStatus)
+                                       throw new CoreException((IStatus) result);
+                       } catch (Exception e) {
+                               throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INTERNAL_ERROR,
+                                               "Error writing register.", e));
+                       }
+               }
+
+               // Update cached register values if register write succeeds
+               Map<String, BigInteger> exeDMCRegisters = registerValueCache.get(exeDMCID);
+               if (exeDMCRegisters != null) {
+                       exeDMCRegisters.put(regDMC.getID(), new BigInteger(regValue, 16));
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IFormattedValues#getAvailableFormats(org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor<String[]> rm) {
+        rm.setData(new String[] { HEX_FORMAT, DECIMAL_FORMAT, OCTAL_FORMAT, BINARY_FORMAT, NATURAL_FORMAT });
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IFormattedValues#getFormattedExpressionValue(org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getFormattedExpressionValue(FormattedValueDMContext dmc, DataRequestMonitor<FormattedValueDMData> rm) {
+               if (dmc.getParents().length == 1 && dmc.getParents()[0] instanceof RegisterDMC) {
+                       getRegisterDataValue((RegisterDMC) dmc.getParents()[0], dmc.getFormatID(), rm);
+               } else {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
+                       rm.done();
+               }
+       }
+
+       /**
+        * Read register with given ID, usually a name that's recognizable by TCF agent.
+        *
+        * @param context the context
+        * @param id the id
+        * @return a hex string on success, and {@link #REGISTER_VALUE_ERROR} on error.
+        * @throws CoreException the core exception
+        */
+       public String getRegisterValue(IExecutionDMContext context, String id) throws CoreException {
+               RegisterDMC regDMC;
+               
+               regDMC = findRegisterDMCByName((IEDCExecutionDMC) context, id);
+               assert regDMC != null;
+               
+               return getRegisterValueAsHexString(regDMC);
+       }
+
+       /**
+        * Gets the register value as hex string.
+        *
+        * @param registerDMC the register dmc
+        * @return the register value as hex string
+        * @throws CoreException the core exception
+        * @since 2.0
+        */
+       public String getRegisterValueAsHexString(RegisterDMC registerDMC) throws CoreException {
+               return getRegisterValue(registerDMC).toString(16);
+       }
+       
+       /**
+        * Gets the register value as a big integer.
+        *
+        * @param registerDMC the register dmc
+        * @return the register value
+        * @throws CoreException the core exception
+        * @since 2.0
+        */
+       public BigInteger getRegisterValue(RegisterDMC registerDMC) throws CoreException {
+
+               IExecutionDMContext exeDMC = DMContexts.getAncestorOfType(registerDMC, IExecutionDMContext.class);
+               if (exeDMC == null || !(exeDMC instanceof IEDCDMContext)) {
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "No valid executionDMC for the register."));
+               }
+
+               final String exeDMCID = ((IEDCDMContext) exeDMC).getID();
+               final String registerDMCID = registerDMC.getID();
+
+               synchronized (registerValueCache) {
+       
+                       Map<String, BigInteger> exeDMCRegisters = registerValueCache.get(exeDMCID);
+                       if (exeDMCRegisters != null) {
+                               BigInteger cachedValue = exeDMCRegisters.get(registerDMC.getID());
+                               if (cachedValue != null) {
+                                       return cachedValue;
+                               }
+                       }
+               }
+       
+               if (tcfRegistersService != null) {      // TCF IRegisters service available
+                       final RegistersContext tcfReg = registerDMC.getTCFContext();
+                       
+            if (tcfReg == null) {
+                       throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "RegisterDMC " + registerDMC.getID() + " has no underlying TCF register context."));
+            }
+
+            TCFTask<byte[]> tcfTask = new TCFTask<byte[]>() {
+               
+                               public void run() {
+                                       tcfReg.get(new org.eclipse.tm.tcf.services.IRegisters.DoneGet() {
+               
+                                               public void doneGet(IToken token, Exception error, byte[] value) {
+                                                       done(value);
+                                               }
+                                       });
+                               }
+                       };
+                       
+                       try {
+                               byte[] value = tcfTask.get(getTCFTimeout(), TimeUnit.MILLISECONDS);     // ignore the return
+                               String strVal = MemoryUtils.convertByteArrayToHexString(value);
+                               BigInteger biValue = new BigInteger(strVal, 16);
+                               synchronized (registerValueCache) {
+                                       Map<String, BigInteger> exeDMCRegisters = registerValueCache.get(exeDMCID);
+                                       if (exeDMCRegisters == null) {
+                                               exeDMCRegisters = new HashMap<String, BigInteger>();
+                                               registerValueCache.put(exeDMCID, exeDMCRegisters);
+                                       }
+                                       exeDMCRegisters.put(registerDMCID, biValue);
+                               }
+                               return biValue;
+                       } catch (Throwable e) {
+                       throw new CoreException(EDCDebugger.dsfRequestFailedStatus("Exception reading register " + registerDMC.getName(), e));
+                       }
+               }
+               throw new CoreException(new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "No data for register " + registerDMC.getName()));
+       }
+
+       /**
+        * Generate a register changed event.
+        *
+        * @param dmc the register dmc
+        */
+       private void generateRegisterChangedEvent(IRegisterDMContext dmc) {
+               getSession().dispatchEvent(new RegisterChangedDMEvent(dmc), getProperties());
+
+               // need to notify listeners via suspended event if the PC has changed
+               RegisterDMC regdmc = (RegisterDMC) dmc;
+               if (regdmc.getName().equals(getTargetEnvironmentService().getPCRegisterID())) {
+                       IExecutionDMContext exeDMC = DMContexts.getAncestorOfType(dmc, IExecutionDMContext.class);
+                       getSession().dispatchEvent(new SuspendedEvent(exeDMC, StateChangeReason.USER_REQUEST, new HashMap<String, Object>()), getProperties());
+               }
+       }
+
+       /**
+        * Gets the register data value.
+        *
+        * @param registerDMC the register dmc
+        * @param formatID the format id
+        * @param rm the request monitor
+        * @return the register data value
+        */
+       private void getRegisterDataValue(RegisterDMC registerDMC, final String formatID,
+                       final DataRequestMonitor<FormattedValueDMData> rm) {
+               try {
+                       BigInteger bigIntValue = getRegisterValue(registerDMC);
+
+                       String formattedValue = bigIntValue.toString(16);
+
+                       if (formatID.equals(IFormattedValues.OCTAL_FORMAT))
+                               formattedValue = NumberFormatUtils.toOctalString(bigIntValue);
+                       if (formatID.equals(IFormattedValues.BINARY_FORMAT))
+                               formattedValue = NumberFormatUtils.asBinary(bigIntValue);
+                       if (formatID.equals(IFormattedValues.DECIMAL_FORMAT))
+                               formattedValue = bigIntValue.toString();
+                       
+                       rm.setData(new FormattedValueDMData(formattedValue));
+
+               } catch (CoreException e) {
+                       Status s = new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), "Error in getRegisterDataValue.", e);
+                       EDCDebugger.getMessageLogger().log(s);
+                       rm.setStatus(s);
+               }
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IFormattedValues#getFormattedValueContext(org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext, java.lang.String)
+        */
+       public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext dmc, String formatId) {
+               if (dmc instanceof RegisterDMC) {
+                       return new FormattedValueDMContext(Registers.this, dmc, formatId);
+               }
+               return null;
+       }
+
+       /**
+        * Gets the model data for a register.
+        *
+        * @param dmc the dmc
+        * @param rm the request monitor
+        * @return the model data
+        */
+       @SuppressWarnings("unchecked")
+       public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
+
+               if (dmc instanceof RegisterGroupDMC)
+                       getRegisterGroupData((IRegisterGroupDMContext) dmc, (DataRequestMonitor<IRegisterGroupDMData>) rm);
+               else if (dmc instanceof RegisterDMC)
+                       getRegisterData((IRegisterDMContext) dmc, (DataRequestMonitor<IRegisterDMData>) rm);
+               else if (dmc instanceof FormattedValueDMContext)
+                       getFormattedExpressionValue((FormattedValueDMContext) dmc, (DataRequestMonitor<FormattedValueDMData>) rm);
+               else
+                       rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.ICachingService#flushCache(org.eclipse.cdt.dsf.datamodel.IDMContext)
+        */
+       public void flushCache(IDMContext context) {
+               if (isSnapshot())
+                       return;
+               // Why flush this static info ?
+               // registerGroupsPerThread.clear();
+               
+               registerValueCache.clear();
+       }
+
+       /**
+        * Load register groups for an executable context.
+        *
+        * @param executionDmc the execution dmc
+        * @param element the element
+        * @throws Exception the exception
+        */
+       public void loadGroupsForContext(IEDCExecutionDMC executionDmc, Element element) throws Exception {
+               // Can't call flushCache here because it does nothing for snapshot
+               // services.
+               String cxtID = ((IEDCDMContext)executionDmc).getID();
+               // It does not hurt if the context is not in the caches.
+               registerGroupsPerContext.remove(cxtID);
+               registerValueCache.remove(cxtID);
+
+               NodeList registerGroups = element.getElementsByTagName(RegisterGroupDMC.REGISTER_GROUP);
+
+               List<RegisterGroupDMC> regGroups = Collections.synchronizedList(new ArrayList<RegisterGroupDMC>());
+
+               int numGroups = registerGroups.getLength();
+               for (int i = 0; i < numGroups; i++) {
+                       Element groupElement = (Element) registerGroups.item(i);
+                       Element propElement = (Element) groupElement.getElementsByTagName(SnapshotUtils.PROPERTIES).item(0);
+                       HashMap<String, Object> properties = new HashMap<String, Object>();
+                       SnapshotUtils.initializeFromXML(propElement, properties);
+
+                       RegisterGroupDMC regdmc = new RegisterGroupDMC(this, executionDmc, properties);
+                       regdmc.loadSnapshot(groupElement);
+                       regGroups.add(regdmc);
+               }
+               registerGroupsPerContext.put(((IEDCDMContext) executionDmc).getID(), regGroups);
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.debug.edc.services.IDSFServiceUsingTCF#tcfServiceReady(org.eclipse.tm.tcf.protocol.IService)
+        */
+       public void tcfServiceReady(IService service) {
+               tcfRegistersService = (org.eclipse.tm.tcf.services.IRegisters)service;
+       }
+
+       /**
+        * Gets the register value.
+        *
+        * @param executionDMC the execution dmc
+        * @param id the register id
+        * @return the register value
+        * @throws CoreException the core exception
+        */
+       public String getRegisterValue(IEDCExecutionDMC executionDMC, int id) throws CoreException {
+               String name = getRegisterNameFromCommonID(id);
+               if (name != null) {
+                       return getRegisterValue(executionDMC, name);
+               }
+               return null;
+       }
+
+       /**
+        * Get TCF child registers contexts for the given parent.
+        * If parent is a thread, the registers contexts are register groups.
+        * If parent is a register group, the contexts returned are registers.
+        *
+        * @param parentID thread ID or register group ID.
+        * @return the tCF registers contexts
+        * @throws CoreException the core exception
+        */
+       protected List<RegistersContext>        getTCFRegistersContexts(final String parentID) throws CoreException {
+               List<RegistersContext> tcfRegContexts = new ArrayList<RegistersContext>();
+               
+               TCFTask<String[]> getChildIDTask = new TCFTask<String[]>() {
+                       public void run() {
+                               tcfRegistersService.getChildren(parentID, new org.eclipse.tm.tcf.services.IRegisters.DoneGetChildren() {
+
+                                       public void doneGetChildren(IToken token, Exception error, String[] contextIds) {
+                                               if (error == null)
+                                                       done(contextIds);
+                                               else
+                                                       error(error);
+                                       }});
+                       }
+               };
+               
+               String[] childIDs;
+               try {
+                       childIDs = getChildIDTask.get(getTCFTimeout(), TimeUnit.MILLISECONDS);
+               } catch (Throwable e) {
+                       throw new CoreException(EDCDebugger.dsfRequestFailedStatus("Fail to get TCF context for: " + parentID, e));
+               }
+               
+               for (String gid: childIDs) {
+                       final String id = gid;
+                       TCFTask<RegistersContext> getGroupContextTask = new TCFTask<RegistersContext>() {
+                               public void run() {
+                                       tcfRegistersService.getContext(id, new org.eclipse.tm.tcf.services.IRegisters.DoneGetContext(){
+                                               public void doneGetContext(IToken token, Exception error, RegistersContext context) {
+                                                       if (error == null)
+                                                               done(context);
+                                                       else
+                                                               error(error);
+                                               }});
+                               }
+                       };
+               
+                       RegistersContext rgc = null;
+                       try {
+                               rgc = getGroupContextTask.get(getTCFTimeout(), TimeUnit.MILLISECONDS);
+                       } catch (Throwable e) {
+                               throw new CoreException(EDCDebugger.dsfRequestFailedStatus("Fail to get TCF context for: " + parentID, e));
+                       }
+                       
+                       if (rgc != null)
+                               tcfRegContexts.add(rgc);
+               }
+
+               return tcfRegContexts;
+       }
+       
+       /**
+        * Handle a suspended event by flushing the cache.
+        *
+        * @param e the event
+        */
+       @DsfServiceEventHandler
+       public void eventDispatched(ISuspendedDMEvent e) {
+               flushCache(null);
+       }
+
+       /**
+        * Handle a resumed event by flushing the cache.
+        *
+        * @param e the event
+        */
+       @DsfServiceEventHandler
+       public void eventDispatched(IResumedDMEvent e) {
+               flushCache(null);
+       }
+
+       /**
+        * When a context (e.g. a thread) is killed/detached, we should forget
+        * cached register info & values for it so that we can properly access
+        * registers when we re-attach to it.
+        *
+        * @param e the event
+        * @since 2.0
+        */
+       @DsfServiceEventHandler
+       public void eventDispatched(IExitedDMEvent e) {
+               IExecutionDMContext cxt = e.getDMContext();
+               if (cxt != null && cxt instanceof IEDCDMContext) {
+                       String cxtID = ((IEDCDMContext)cxt).getID();
+                       // It does not hurt if the context is not in the caches.
+                       registerGroupsPerContext.remove(cxtID);
+                       registerValueCache.remove(cxtID);
+               }
+       }
+
+       /**
+        * Creates the registers for group.
+        *
+        * @param registerGroupDMC the register group dmc
+        * @return the list
+        * @throws CoreException the core exception
+        */
+       protected List<RegisterDMC> createRegistersForGroup(RegisterGroupDMC registerGroupDMC) throws CoreException {
+               ArrayList<RegisterDMC> registers = new ArrayList<RegisterDMC>();
+       
+               if (tcfRegistersService != null) {
+                       List<RegistersContext> tcfRegs = getTCFRegistersContexts(registerGroupDMC.getID());
+                       
+                       for (RegistersContext rg: tcfRegs) {
+                               registers.add(new RegisterDMC(registerGroupDMC, registerGroupDMC.getExecutionDMC(), rg));
+                       }
+               }
+               
+               return registers;
+       }
+       
+       /**
+        * Creates the groups for context.
+        *
+        * @param ctx the ctx
+        * @return the list
+        * @throws CoreException the core exception
+        */
+       protected List<RegisterGroupDMC> createGroupsForContext(IEDCExecutionDMC ctx) throws CoreException {
+
+               List<RegisterGroupDMC> groups = Collections.synchronizedList(new ArrayList<RegisterGroupDMC>());
+
+               if (RunControl.isNonContainer(ctx)) {
+                       if (tcfRegistersService != null) {
+                               List<RegistersContext> tcfRegGroups = getTCFRegistersContexts(ctx.getID());
+                               
+                               for (RegistersContext rg: tcfRegGroups) {
+                                       groups.add(new RegisterGroupDMC(this, ctx, rg.getProperties()));
+                               }
+                       }
+               }
+
+               return groups;
+       }
+
+       /**
+        * Given a common general purpose register id (e.g. from symbolics), get the
+        * corresponding register name.
+        * 
+        * @param id
+        *            the common general purpose register id (0-31)
+        * @return the corresponding register name, or null of n/a
+        */
+       public abstract String getRegisterNameFromCommonID(int id);
+       
+       /**
+        * Sets the TCF timeout.
+        *
+        * @param msecs the new TCF timeout
+        * @since 2.0
+        */
+       public void setTCFTimeout(long msecs) {
+               tcfTimeout = msecs;
+       }
+
+       /**
+        * Gets the TCF timeout.
+        *
+        * @return the TCF timeout
+        * @since 2.0
+        */
+       public long getTCFTimeout() {
+               return tcfTimeout;
+       }
+
+       // Implementation of org.eclipse.cdt.dsf.debug.service.IRegisters
+       
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#getRegisterGroups(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getRegisterGroups(final IDMContext ctx, final DataRequestMonitor<IRegisterGroupDMContext[]> rm) {
+               
+               asyncExec(new Runnable() {
+                       
+                       public void run() {
+                               IEDCExecutionDMC execDmc = DMContexts.getAncestorOfType(ctx, IEDCExecutionDMC.class);
+                               if (execDmc != null && RunControl.isNonContainer(execDmc)) {
+                                       try {
+                                               rm.setData(getGroupsForContext(execDmc));
+                                       } catch (CoreException e) {
+                                               EDCDebugger.getMessageLogger().log(e.getStatus());
+                                               rm.setStatus(e.getStatus());
+                                       }
+                                       rm.done();
+                                       return;
+                               }
+
+                               StackFrameDMC frameDmc = DMContexts.getAncestorOfType(ctx, StackFrameDMC.class);
+                               if (frameDmc != null) {
+                                       try {
+                                               rm.setData(getGroupsForContext(frameDmc.getExecutionDMC()));
+                                       } catch (CoreException e) {
+                                               EDCDebugger.getMessageLogger().log(e.getStatus());
+                                               rm.setStatus(e.getStatus());
+                                       }
+                                       rm.done();
+                                       return;
+                               }
+                               
+                               rm.setData(new IRegisterGroupDMContext[0]);
+                               rm.done();
+                       }
+               }, rm);
+               
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#getRegisters(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getRegisters(final IDMContext ctx, final DataRequestMonitor<IRegisterDMContext[]> rm) {
+
+               asyncExec(new Runnable() {
+                       
+                       public void run() {
+                               RegisterGroupDMC groupContext = DMContexts.getAncestorOfType(ctx, RegisterGroupDMC.class);
+                               IEDCExecutionDMC executionContext = DMContexts.getAncestorOfType(ctx, IEDCExecutionDMC.class);
+                               RegisterDMC[] allRegisters;
+                               try {
+                                       if (groupContext != null && executionContext != null) {
+                                               allRegisters = groupContext.getRegisters();
+                                       }
+                                       else {
+                                               allRegisters = new RegisterDMC[0];
+                                       }
+                                       rm.setData(allRegisters);
+                               } catch (CoreException e) {
+                                       EDCDebugger.getMessageLogger().log(e.getStatus());
+                                       rm.setStatus(e.getStatus());
+                               }
+                               rm.done();
+                       }
+               }, rm);
+               
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#getBitFields(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getBitFields(IDMContext ctx, DataRequestMonitor<IBitFieldDMContext[]> rm) {
+               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, NOT_SUPPORTED, "BitField not supported", null)); //$NON-NLS-1$
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#findRegisterGroup(org.eclipse.cdt.dsf.datamodel.IDMContext, java.lang.String, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void findRegisterGroup(IDMContext ctx, String name, DataRequestMonitor<IRegisterGroupDMContext> rm) {
+               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, NOT_SUPPORTED, "findRegisterGroup not supported", null)); //$NON-NLS-1$
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#findRegister(org.eclipse.cdt.dsf.datamodel.IDMContext, java.lang.String, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void findRegister(IDMContext ctx, String name, DataRequestMonitor<IRegisterDMContext> rm) {
+               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, NOT_SUPPORTED, "findRegister not supported", null)); //$NON-NLS-1$
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#findBitField(org.eclipse.cdt.dsf.datamodel.IDMContext, java.lang.String, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void findBitField(IDMContext ctx, String name, DataRequestMonitor<IBitFieldDMContext> rm) {
+               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, NOT_SUPPORTED, "findBitField not supported", null)); //$NON-NLS-1$
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#getRegisterGroupData(org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getRegisterGroupData(IRegisterGroupDMContext dmc, DataRequestMonitor<IRegisterGroupDMData> rm) {
+
+               class RegisterGroupData implements IRegisterGroupDMData {
+                       private final String name;
+                       private final String description;
+
+                       public RegisterGroupData(RegisterGroupDMC dmc) {
+                               this.name = dmc.getName();
+                               this.description = (String) dmc.getProperty(IEDCDMContext.PROP_DESCRIPTION);
+                       }
+
+                       public String getName() {
+                               return name;
+                       }
+
+                       public String getDescription() {
+                               return description;
+                       }
+               }
+
+               rm.setData(new RegisterGroupData((RegisterGroupDMC) dmc));
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#getRegisterData(org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getRegisterData(IRegisterDMContext dmc, DataRequestMonitor<IRegisterDMData> rm) {
+               RegisterDMC regdmc = (RegisterDMC) dmc;
+               rm.setData(new RegisterData(regdmc.getProperties()));
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#getBitFieldData(org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getBitFieldData(IBitFieldDMContext dmc, DataRequestMonitor<IBitFieldDMData> rm) {
+               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, NOT_SUPPORTED,
+                               "Bit fields not yet supported", null)); //$NON-NLS-1$
+               rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IRegisters#writeRegister(org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext, java.lang.String, java.lang.String, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+        */
+       public void writeRegister(final IRegisterDMContext regCtx, final String regValue, final String formatID, final RequestMonitor rm) {
+
+               asyncExec(new Runnable() {
+                       
+                       public void run() {
+                               try{
+                               writeRegister(regCtx, regValue, formatID);
+                               } catch (CoreException e) {
+                                       EDCDebugger.getMessageLogger().log(e.getStatus());
+                                       rm.setStatus(e.getStatus());
+                               }
+                               rm.done();
+                       }
+               }, rm);
+               
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Stack.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Stack.java
new file mode 100644 (file)
index 0000000..1e04ebc
--- /dev/null
@@ -0,0 +1,1639 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.services;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.internal.launch.CSourceLookup;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Symbols;
+import org.eclipse.cdt.debug.edc.internal.snapshot.SnapshotUtils;
+import org.eclipse.cdt.debug.edc.internal.symbols.MemoryVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.EDCSymbolReader;
+import org.eclipse.cdt.debug.edc.internal.symbols.files.UnmanglerEABI;
+import org.eclipse.cdt.debug.edc.internal.symbols.files.UnmanglingException;
+import org.eclipse.cdt.debug.edc.snapshot.IAlbum;
+import org.eclipse.cdt.debug.edc.snapshot.ISnapshotContributor;
+import org.eclipse.cdt.debug.edc.symbols.ICompileUnitScope;
+import org.eclipse.cdt.debug.edc.symbols.IDebugInfoProvider;
+import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
+import org.eclipse.cdt.debug.edc.symbols.IEnumerator;
+import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
+import org.eclipse.cdt.debug.edc.symbols.IModuleLineEntryProvider;
+import org.eclipse.cdt.debug.edc.symbols.IModuleScope;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IUnmangler;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+import org.eclipse.cdt.debug.edc.symbols.TypeEngine;
+import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public abstract class Stack extends AbstractEDCService implements IStack, ICachingService {
+
+       public static final String STACK_FRAME = "stack_frame";
+       
+       public Boolean showAllVariablesEnabled = null;
+
+       private final Map<String, List<StackFrameDMC>> stackFrames = Collections
+                       .synchronizedMap(new HashMap<String, List<StackFrameDMC>>());
+       private final Map<String, Boolean> allFramesCached = Collections
+       .synchronizedMap(new HashMap<String, Boolean>());
+
+       
+       
+       public static class StackFrameData implements IFrameDMData {
+
+               public final IAddress address;
+               public final int level;
+               public final String function;
+               public final String module;
+               private final String file;
+               private final int lineNumber;
+
+               StackFrameData(StackFrameDMC dmc) {
+                       level = dmc.getLevel();
+                       address = dmc.getInstructionPtrAddress();
+                       module = dmc.getModuleName();
+                       file = dmc.getSourceFile(); // "" instead of null if no file.
+                       lineNumber = dmc.getLineNumber();
+                       function = dmc.getFunctionName();
+               }
+
+               public IAddress getAddress() {
+                       return address;
+               }
+
+               public String getFunction() {
+                       return function;
+               }
+
+               public int getLevel() {
+                       return level;
+               }
+
+               // DSF requires non-null return value.
+               public String getFile() {
+                       return file;
+               }
+
+               public int getLine() {
+                       return lineNumber;
+               }
+
+               public int getColumn() {
+                       return 0;
+               }
+
+               public String getModule() {
+                       return module;
+               }
+
+               @Override
+               public boolean equals(Object other) {
+                       return
+                               this == other
+                               || (other != null && other instanceof StackFrameData
+                                       && getAddress().equals(((StackFrameData)other).getAddress())
+                                       && getFunction().equals(((StackFrameData)other).getFunction())
+                                       && getLevel() == ((StackFrameData)other).getLevel()
+                                       && getFile().equals(((StackFrameData)other).getFile())
+                                       && getLine() == ((StackFrameData)other).getLine()
+                                       && getColumn() == ((StackFrameData)other).getColumn()
+                                       && getModule().equals(((StackFrameData)other).getModule()));
+               }
+       }
+
+    /**
+     * Variable or enumerator context.  This interface provides a wrapper
+     * for treating variables and enumerators the same when needed.
+     **/
+    public interface IVariableEnumeratorContext {}
+
+    /**
+     * Enumerator context.
+     **/
+    public interface IEnumeratorDMContext {}
+
+    public static final class CurrentFrameRegisters implements IFrameRegisters {
+       private final Registers registers;
+               private final IEDCExecutionDMC executionDMC;
+       
+       public CurrentFrameRegisters(IEDCExecutionDMC executionDMC, Registers registers) {
+               this.executionDMC = executionDMC;
+                       this.registers = registers;
+       }
+       
+       public BigInteger getRegister(int regnum, int bytes) throws CoreException {
+               String value = registers.getRegisterValue(executionDMC, regnum);
+               if (value == null || value.equals(Registers.REGISTER_VALUE_ERROR))
+                       throw EDCDebugger.newCoreException("failed to read register");
+               return new BigInteger(value, 16);
+       }
+
+               public void writeRegister(int regnum, int bytes, BigInteger value) throws CoreException {
+                       String id = registers.getRegisterNameFromCommonID(regnum);
+                       if (id != null) {
+                               // if value is negative, using value.toString(16) directly gives values such as '-af'
+                               registers.writeRegister(executionDMC, id, Long.toHexString(value.longValue()));
+                       } else
+                               throw EDCDebugger.newCoreException(MessageFormat.format("could not find register number {0}", regnum));
+               }
+    }
+    
+    /**
+        * Frame registers read from preserved registers on the stack frame.
+        */
+       public static class PreservedFrameRegisters implements IFrameRegisters {
+               private final Map<Integer, BigInteger> preservedRegisters;
+               private final EDCServicesTracker dsfServicesTracker;
+               private final StackFrameDMC context;
+
+               /**
+                * @param preservedRegisters map of register number to the address
+                * where the register is saved
+                * @since 2.0
+                */
+               public PreservedFrameRegisters(EDCServicesTracker dsfServicesTracker,
+                               StackFrameDMC context,
+                               Map<Integer, BigInteger> preservedRegisters) {
+                       this.dsfServicesTracker = dsfServicesTracker;
+                       this.context = context;
+                       this.preservedRegisters = preservedRegisters;
+               }
+
+               public BigInteger getRegister(int regnum, int bytes) throws CoreException {
+                       BigInteger addrVal = preservedRegisters.get(regnum);
+                       if (addrVal != null) {
+                               MemoryVariableLocation location = new MemoryVariableLocation(
+                                               dsfServicesTracker, context, 
+                                               addrVal, true);
+                               return location.readValue(bytes);
+                       }
+                       throw EDCDebugger.newCoreException("cannot read $R" + regnum + " from frame");
+               }
+
+               public void writeRegister(int regnum, int bytes, BigInteger value) throws CoreException {
+                       BigInteger addrVal = preservedRegisters.get(regnum);
+                       if (addrVal != null) {
+                               MemoryVariableLocation location = new MemoryVariableLocation(
+                                               dsfServicesTracker, context, 
+                                               addrVal, true);
+                               location.writeValue(bytes, value);
+                       }
+               }
+       }
+
+       /**
+        * Frame registers which always throws an exception.
+        */
+       public static class AlwaysFailingFrameRegisters implements IFrameRegisters {
+               private final CoreException e;
+
+               public AlwaysFailingFrameRegisters(CoreException e) {
+                       this.e = e;
+               }
+
+               public BigInteger getRegister(int regnum, int bytes) throws CoreException {
+                       throw e;
+               }
+
+               public void writeRegister(int regnum, int bytes, BigInteger value)
+                               throws CoreException {
+                       throw e;
+               }
+       }
+
+       public class StackFrameDMC extends DMContext implements IFrameDMContext, Comparable<StackFrameDMC>,
+                       ISnapshotContributor {
+
+               /** 
+                * Stack frame level.  Zero is used for the first frame, where the PC is.
+                */
+               public static final String LEVEL_INDEX = "Level";
+               /**
+                * If set and True, tells that this frame is the topmost that we can fetch.
+                */
+               public static final String ROOT_FRAME = "root_frame";
+               public static final String BASE_ADDR = "Base_address";
+               /**
+                * @since 2.0 - previously "IP_ADDR"
+                */
+               public static final String INSTRUCTION_PTR_ADDR = "Instruction_address";
+               public static final String MODULE_NAME = "module_name";
+               public static final String SOURCE_FILE = "source_file";
+               public static final String FUNCTION_NAME = "function_name";
+               public static final String LINE_NUMBER = "line_number";
+               /** 
+                * For LEVEL_INDEX == 0, if set and True, this tells us that this frame
+                * is not "authentic" yet, e.g., that the frame still represents the caller's
+                * state.  This means we cannot trust the parameters and locals,
+                * and must resolve variables from other frames differently.
+                */
+               public static final String IN_PROLOGUE = "in_prologue"; // Boolean
+               /**
+                * Provides a Map<Integer, BigInteger> instance which can yield addresses of
+                * registers pushed into the stack frame if debug info does not provide it.
+                */
+               public static final String PRESERVED_REGISTERS = "preserved_registers";
+               private static final String FRAME_PROPERTY_CACHE = "_frame_properties";
+               /**
+                * @since 2.0 The id of the owning execution dmc
+                */
+               public static final String EXECUTION_DMC_ID = "execution_dmc_id";
+
+               private final EDCServicesTracker dsfServicesTracker = Stack.this.getEDCServicesTracker();
+               private final IEDCExecutionDMC executionDMC;
+               private final int level;
+               private IAddress baseAddress;
+               private IAddress instructionPtrAddress;
+
+               private String moduleName = "";
+               private String sourceFile = "";
+               private String functionName = "";
+               private int lineNumber;
+               private IScope variableScope = null;
+               private List<VariableDMC> locals;
+               private List<EnumeratorDMC> enumerators;
+               private final Map<String, VariableDMC> localsByName = Collections
+                               .synchronizedMap(new HashMap<String, VariableDMC>());
+               private final Map<String, EnumeratorDMC> enumeratorsByName = Collections
+                               .synchronizedMap(new HashMap<String, EnumeratorDMC>());
+               private final Map<String, IVariable> thisPtrs = Collections
+                               .synchronizedMap(new LinkedHashMap<String, IVariable>());
+               private IFunctionScope functionScope;
+               private IFrameRegisters frameRegisters;
+               public StackFrameDMC calledFrame;
+               private TypeEngine typeEngine;
+               private IEDCModuleDMContext module;
+
+               // additional items may be null but are usually set early and used repeatedly
+               private IAddress instrPtrLinkAddr = null;
+               private IEDCSymbolReader reader = null;
+               private IModuleLineEntryProvider provider = null;
+               private IDebugInfoProvider debugInfoProvider = null;
+               private IPath symbolFile = null;
+
+               /**
+                * @since 2.0
+                */
+               @SuppressWarnings("unchecked")
+               public StackFrameDMC(final IEDCExecutionDMC executionDMC, EdcStackFrame edcFrame) {
+                       super(Stack.this, new IDMContext[] { executionDMC }, createFrameID(executionDMC, edcFrame), edcFrame.props);
+                       
+                       Map<String, Object> frameProperties = edcFrame.props;
+                       
+                       this.executionDMC = executionDMC;
+                       frameProperties.put(EXECUTION_DMC_ID, executionDMC.getID());
+
+                       this.level = (Integer) frameProperties.get(LEVEL_INDEX);
+                       this.moduleName = (String) frameProperties.get(MODULE_NAME);
+                       this.baseAddress = address(frameProperties.get(BASE_ADDR));
+                       this.instructionPtrAddress = address(frameProperties.get(INSTRUCTION_PTR_ADDR));
+
+                       // compute the source location
+                       IEDCSymbols symbolsService = getService(Symbols.class);
+                       functionScope = symbolsService.getFunctionAtAddress(executionDMC.getSymbolDMContext(),
+                                                                                                                               instructionPtrAddress);
+
+                       boolean usingCachedProperties = false;
+                       IEDCModules modules = dsfServicesTracker.getService(IEDCModules.class);
+                       Map<IAddress, Map<String, Object>> cachedFrameProperties
+                         = new HashMap<IAddress, Map<String, Object>>();
+                       if (modules != null) {
+                               module = modules.getModuleByAddress(executionDMC.getSymbolDMContext(), instructionPtrAddress);
+                               if (module != null) {
+                                       instrPtrLinkAddr = module.toLinkAddress(instructionPtrAddress);
+                                       reader = module.getSymbolReader();
+                                       if (reader != null) {
+                                               symbolFile = this.reader.getSymbolFile();
+                                               if (symbolFile != null) {
+                                                       // Check the persistent cache
+                                                       String cacheKey = reader.getSymbolFile().toOSString() + FRAME_PROPERTY_CACHE;
+                                                       Map<IAddress, Map<String, Object>> cachedData
+                                                         = EDCDebugger.getDefault().getCache().getCachedData(cacheKey, Map.class,
+                                                                                                                                                                 reader.getModificationDate());
+                                                       if (cachedData != null) {
+                                                               cachedFrameProperties = cachedData;
+                                                               Map<String, Object> cachedProperties
+                                                                 = cachedFrameProperties.get(instrPtrLinkAddr);
+                                                               if (cachedProperties != null) {
+                                                                       if (cachedProperties.containsKey(SOURCE_FILE))
+                                                                               frameProperties.put(SOURCE_FILE, cachedProperties.get(SOURCE_FILE));
+
+                                                                       boolean cachedPropertiesHasFunctionName = false;
+                                                                       if (cachedProperties.containsKey(FUNCTION_NAME)) {
+                                                                               Object fnObj = cachedProperties.get(FUNCTION_NAME);
+                                                                               if (fnObj != null 
+                                                                                       && fnObj instanceof String
+                                                                                       && ((String)fnObj).length() != 0) {
+                                                                                       frameProperties.put(FUNCTION_NAME, fnObj);
+                                                                                       cachedPropertiesHasFunctionName = true;
+                                                                       }       }
+
+                                                                       if (!cachedPropertiesHasFunctionName) {
+                                                                               setFunctionName(executionDMC, frameProperties, symbolsService);
+                                                                               cachedProperties.put(FUNCTION_NAME, functionName);
+                                                                       }
+
+                                                                       if (cachedProperties.containsKey(LINE_NUMBER))
+                                                                               frameProperties.put(LINE_NUMBER, cachedProperties.get(LINE_NUMBER));
+                                                                       usingCachedProperties = true;                                                           
+                       }       }       }       }       }       }       // null-checks on cachedProperties <= cachedData <= symbolFile
+
+                       if (frameProperties.containsKey(SOURCE_FILE)) {
+                               sourceFile   = (String) frameProperties.get(SOURCE_FILE);
+                               functionName = (String) frameProperties.get(FUNCTION_NAME);
+                               lineNumber   = (Integer) frameProperties.get(LINE_NUMBER);
+                       } else if (frameProperties.containsKey(FUNCTION_NAME)) {
+                               functionName = (String) frameProperties.get(FUNCTION_NAME);
+                       } else if (!usingCachedProperties) {
+                               ILineEntry line
+                                 = symbolsService.getLineEntryForAddress(executionDMC.getSymbolDMContext(),
+                                                                                                                 instructionPtrAddress);
+                               if (line != null)
+                                       setSourceProperties(frameProperties, line);
+
+                               setFunctionName(executionDMC, frameProperties, symbolsService);
+                       }
+                       properties.putAll(frameProperties);
+
+                       if (symbolFile != null) {
+                               String cacheKey = symbolFile.toOSString() + FRAME_PROPERTY_CACHE;
+                               cachedFrameProperties.put(this.instrPtrLinkAddr, frameProperties);
+                               EDCDebugger.getDefault().getCache().putCachedData(cacheKey,
+                                                                                                                                 (Serializable)cachedFrameProperties,
+                                                                                                                                 this.reader.getModificationDate());
+                       }
+
+                       if (reader instanceof EDCSymbolReader)
+                               debugInfoProvider = ((EDCSymbolReader)reader).getDebugInfoProvider();
+                       typeEngine = new TypeEngine(getTargetEnvironmentService(), debugInfoProvider);
+               }
+
+               private void setFunctionName(final IEDCExecutionDMC executionDMC,
+                               Map<String, Object> frameProperties, IEDCSymbols symbolsService) {
+                       if (functionScope != null) {
+                               // ignore inlined functions
+                               IFunctionScope containerScope = functionScope;
+                               while (containerScope.getParent() instanceof IFunctionScope) {
+                                       containerScope = (IFunctionScope) containerScope.getParent();
+                               }
+                               functionName = unmangle(containerScope.getName());
+                               adjustFunctionSourceInfo(containerScope, frameProperties);
+                       } else {
+                               functionName
+                                 = unmangle(symbolsService.getSymbolNameAtAddress(executionDMC.getSymbolDMContext(),
+                                                                                                                                  instructionPtrAddress));
+                       }
+
+                       frameProperties.put(FUNCTION_NAME, functionName);
+               }
+
+               /**
+                * Modify the name to refer to the inline function within the parent function.
+                * <p>
+                * However, ignore the inline function name if the pointer is on the first
+                * line of the inline function and the "previous" line is
+                * <br> (a) in the parent function; or
+                * <br> (b) not in the original inline (meaning it was part of a prior inline); or 
+                * <br> (c) is nested in another inline
+                * @param container the ultimate function containing the inline(s)
+                * @param frameProperties so source-file and line-number can also be adjusted
+                */
+               private void adjustFunctionSourceInfo(IFunctionScope container,
+                               Map<String, Object> frameProperties) {
+                       if (functionScope.equals(container)) {
+                               ILineEntry funcFirstEntry = this.getLineEntryInFunction(functionScope);
+                               if (funcFirstEntry != null
+                                               && !instrPtrLinkAddr.equals(funcFirstEntry.getLowAddress())) {
+                                       // this case covers the compiler having inline LNT entries
+                                       // whose bounds are outside the DWARF function scope boundaries
+                                       // for the inlines
+                                       setSourceProperties(frameProperties, funcFirstEntry);
+                               }
+                               return;         // i.e. never fall through to "inline" re-naming below
+                       }
+
+                       ILineEntry containerEntry = this.getLineEntryInFunction(container);
+                       if (containerEntry != null && isInlineShouldBeHidden(containerEntry)) {
+                               setSourceProperties(frameProperties, containerEntry);
+                               return;
+                       }
+
+                       this.functionName
+                         = unmangle(functionScope.getName()) + " inlined in " + this.functionName;
+               }
+               
+               /**
+                * Attempt to determine if the frame's instruction pointer is
+                * <br>(a) at the first instruction of an inlined function; and
+                * <br>(b) coincidentally at the first instruction of the line
+                * entry corresponding to the line that caused the inline to
+                * be generated.<p>
+                * @param entry if null, will be calculated based on established
+                *                      frame instruction pointer and function scope; can be passed
+                *                      in if caller needs line entry for other usage
+                * @return true if it can be determined that the instruction pointer is
+                *                      the first instruction of an inline function and coincidentally the
+                *                      first instruction of the line entry for which the inline was generated
+                * @since 2.0
+                */
+               public boolean isInlineShouldBeHidden(ILineEntry entry) {
+                       if (functionScope == null
+                                       || !(functionScope.getParent() instanceof IFunctionScope)
+                                       || !instrPtrLinkAddr.equals(functionScope.getLowAddress()))
+                               return false;
+
+                       if (entry == null) {
+                               entry = getLineEntryInFunction(functionScope);
+                               if (entry == null)
+                                       return false;
+                       }
+
+                       if (instrPtrLinkAddr.equals(entry.getLowAddress())) {
+                               ILineEntry prevEntry = getPreviousLineEntry(entry, true);
+                               if (prevEntry != null) {
+                                       ILineEntry testEntry = getNextLineEntry(prevEntry, true);
+                                       if (entry.equals(testEntry)) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               return true;
+                       }
+                       return false;
+               }
+
+               /**
+                * Private utility function to call the module's reader's provider's interfaces
+                * @see org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider#getLineEntryInFunction
+                * @see IModuleScope#getModuleLineEntryProvider
+                */
+               private ILineEntry getLineEntryInFunction(IFunctionScope func) {
+                       return getModuleLineEntryProvider().getLineEntryInFunction(instrPtrLinkAddr, func);
+               }
+
+               /**
+                * Private utility function to call the module's reader's provider's interfaces
+                * @see IModuleScope#getModuleLineEntryProvider
+                * @return {@link IModuleLineEntryProvider} never <code>null</code>
+                */
+               private IModuleLineEntryProvider getModuleLineEntryProvider() {
+                       if (provider == null && reader != null) {
+                               IModuleScope moduleScope = reader.getModuleScope();
+                               if (moduleScope != null)
+                                       provider = moduleScope.getModuleLineEntryProvider();                    
+                       }
+                       return provider;
+               }
+
+               /**
+                * Private utility function to call the module's reader's provider's interfaces
+                * @see org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider#getNextLineEntry
+                * @see IModuleScope#getModuleLineEntryProvider
+                */
+               private ILineEntry getNextLineEntry(ILineEntry entry, boolean collapseInlineFunctions) {
+                       return getModuleLineEntryProvider().getNextLineEntry(entry, collapseInlineFunctions);
+               }                                       
+
+               /**
+                * Private utility function to call the module's reader's provider's interfaces
+                * @see org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider#getPreviousLineEntry
+                * @see IModuleScope#getModuleLineEntryProvider
+                */
+               private ILineEntry getPreviousLineEntry(ILineEntry entry, boolean collapseInlineFunctions) {
+                       return getModuleLineEntryProvider().getPreviousLineEntry(entry, collapseInlineFunctions);
+               }                                       
+
+               private void setSourceProperties(Map<String, Object> frameProperties,
+                               ILineEntry entry) {
+                       frameProperties.put(SOURCE_FILE, (sourceFile = entry.getFilePath().toOSString()));
+                       frameProperties.put(LINE_NUMBER, (lineNumber = entry.getLineNumber()));
+               }
+
+               private String unmangle(String name) {
+                       if (name == null)
+                               return null;
+                       
+                       // unmangle the name
+                       IUnmangler unmangler = null;
+                       if (reader instanceof EDCSymbolReader) {
+                               unmangler = ((EDCSymbolReader) reader).getUnmangler();
+                       }
+                       if (unmangler == null) {
+                               unmangler = new UnmanglerEABI();
+                       }
+                       
+                       if (!unmangler.isMangled(name))
+                               return name;
+                       
+                       try {
+                               return unmangler.unmangleWithoutArgs(name);
+                       } catch (UnmanglingException e) {
+                               return name;
+                       }
+               }
+
+               private IAddress address(Object obj) {
+                       if (obj instanceof Integer)
+                               return new Addr64(obj.toString());
+                       if (obj instanceof Long)
+                               return new Addr64(obj.toString());
+                       if (obj instanceof String) // the string should be hex string
+                               return new Addr64((String) obj, 16);
+                       return null;
+               }
+
+               private void setInstructionPtrAddress(IAddress ipAddrPtr) {
+                       this.instructionPtrAddress = ipAddrPtr;
+                       if (module != null)
+                               this.instrPtrLinkAddr = module.toLinkAddress(instructionPtrAddress);
+               }
+
+               public IFunctionScope getFunctionScope() {
+                       return functionScope;
+               }
+
+               public String getModuleName() {
+                       return moduleName;
+               }
+
+               /**
+                * Get source file name if any for the frame. 
+                * @return valid file name or "" otherwise.
+                */
+               public String getSourceFile() {
+                       return sourceFile;
+               }
+
+               public String getFunctionName() {
+                       return functionName;
+               }
+
+               public int getLineNumber() {
+                       return lineNumber;
+               }
+
+               public IEDCExecutionDMC getExecutionDMC() {
+                       return executionDMC;
+               }
+
+               public IAddress getBaseAddress() {
+                       return baseAddress;
+               }
+
+               /**
+                * @since 2.0
+                */
+               public IAddress getInstructionPtrAddress() {
+                       return instructionPtrAddress;
+               }
+
+               public int getLevel() {
+                       return level;
+               }
+
+               /**
+                * @since 2.0
+                */
+               public EDCServicesTracker getEDCServicesTracker() {
+                       return Stack.this.getEDCServicesTracker();
+               }
+
+               public int compareTo(StackFrameDMC f) {
+                       if (level < f.level)
+                               return -1;
+                       if (level > f.level)
+                               return +1;
+                       return 0;
+               }
+
+               
+               @Override
+               public String toString() {
+                       return "StackFrameDMC [baseAddress=" + baseAddress.toHexAddressString() + ", ipAddress="
+                                       + instructionPtrAddress.toHexAddressString() + ", sourceFile=" + sourceFile
+                                       + ", functionName=" + functionName + ", lineNumber="
+                                       + lineNumber + "]";
+               }
+
+               @Override
+               public int hashCode() {
+                       final int prime = 31;
+                       int result = super.hashCode();
+                       result = prime * result + getOuterType().hashCode();
+                       result = prime * result
+                                       + ((baseAddress == null) ? 0 : baseAddress.hashCode());
+                       result = prime * result
+                                       + ((executionDMC == null) ? 0 : executionDMC.hashCode());
+                       result = prime * result + level;
+                       return result;
+               }
+
+               @Override
+               public boolean equals(Object obj) {
+                       if (this == obj)
+                               return true;
+                       if (!super.equals(obj))
+                               return false;
+                       if (getClass() != obj.getClass())
+                               return false;
+
+                       StackFrameDMC other = (StackFrameDMC) obj;
+                       if (!getOuterType().equals(other.getOuterType()))
+                               return false;
+
+                       if (baseAddress == null) {
+                               if (other.baseAddress != null)
+                                       return false;
+                       } else if (!baseAddress.equals(other.baseAddress))
+                               return false;
+
+                       if (executionDMC == null) {
+                               if (other.executionDMC != null)
+                                       return false;
+                       } else if (!executionDMC.equals(other.executionDMC))
+                               return false;
+
+                       if (level != other.level)
+                               return false;
+                       return true;
+               }
+
+               /**
+                * Finds a source file using the source lookup director.
+                * 
+                * @param sourceFile the raw source file location, usually from the symbol data
+                * 
+                * @return location of the source file
+                */
+               private String findSourceFile(String sourceFile) {
+                       String result = "";
+                       CSourceLookup lookup = getService(CSourceLookup.class);
+                       RunControl runControl = getService(RunControl.class);
+                       CSourceLookupDirector[] directors = lookup.getSourceLookupDirectors(runControl.getRootDMC());
+
+                       for (CSourceLookupDirector cSourceLookupDirector : directors) {
+                               try {
+                                       Object[] elements = cSourceLookupDirector.findSourceElements(sourceFile);
+                                       if (elements != null && elements.length > 0)
+                                       {
+                                               Object element = elements[0];
+                                               if (element instanceof File) {
+                                                       try {
+                                                               result = (((File) element).getCanonicalPath());
+                                                       } catch (IOException e) {
+                                                               EDCDebugger.getMessageLogger().logError(null, e);
+                                                       }
+                                               } else if (element instanceof IFile) {
+                                                       result = (((IFile) element).getLocation().toOSString());
+                                               } else if (element instanceof IStorage) {
+                                                       result = (((IStorage) element).getFullPath().toOSString());
+                                               } else if (element instanceof ITranslationUnit) {
+                                                       result =(((ITranslationUnit) element).getLocation().toOSString());
+                                               }
+                                               break;
+                                       }                       
+                               } catch (CoreException e1) {
+                                       EDCDebugger.getMessageLogger().logError(sourceFile, e1);
+                               }
+                       }
+                       return result;
+               }
+
+               /**
+                * @since 2.0
+                */
+               public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor) {
+                       Element contextElement = document.createElement(STACK_FRAME);
+                       contextElement.setAttribute(PROP_ID, this.getID());
+
+                       Element propsElement = SnapshotUtils.makeXMLFromProperties(document, getProperties());
+                       contextElement.appendChild(propsElement);
+                       // Locate the actual source file to be included in the album.
+                       if (sourceFile.length() > 0) // No source file for this frame (just module/address)
+                               album.addFile(new Path(findSourceFile(sourceFile)));
+                       return contextElement;
+               }
+
+               @SuppressWarnings("unchecked")
+               public void loadSnapshot(Element element) {
+                       // fix up registers to use integers again
+                       Map<String, String> preservedRegisters = (Map<String, String>) properties.get(PRESERVED_REGISTERS);
+                       if (preservedRegisters != null) {
+                               Map<Integer, BigInteger> newPreservedRegisters = new HashMap<Integer, BigInteger>();
+                               for (Map.Entry<String, String> entry : preservedRegisters.entrySet()) {
+                                       newPreservedRegisters.put(Integer.valueOf(entry.getKey().toString()), new BigInteger(entry.getValue().toString()));
+                               }
+                               properties.put(PRESERVED_REGISTERS, newPreservedRegisters);
+                       }
+               }
+
+               public IVariableDMContext[] getLocals() {
+                       return getLocals(/* boolean useCachedVariables => */ true);
+               }
+
+               private IVariableDMContext[] getLocals(boolean useCachedVariables) {
+                       // may need to refresh the locals list because "Show All Variables"
+                       // toggle has changed
+                   if (showAllVariablesEnabled == null) {
+                               IEclipsePreferences scope = InstanceScope.INSTANCE.getNode(EDCDebugger.PLUGIN_ID);
+                       showAllVariablesEnabled = scope.getBoolean(IEDCSymbols.SHOW_ALL_VARIABLES_ENABLED, false);
+                   }
+
+                       boolean enabled = showAllVariablesEnabled.booleanValue();
+                       if (locals != null) {
+                               IEclipsePreferences scope = InstanceScope.INSTANCE.getNode(EDCDebugger.PLUGIN_ID);
+                               enabled = scope.getBoolean(IEDCSymbols.SHOW_ALL_VARIABLES_ENABLED, showAllVariablesEnabled);
+                       }
+
+                       if (locals == null || !useCachedVariables || enabled != showAllVariablesEnabled) {
+                               showAllVariablesEnabled = enabled;
+                               locals = new ArrayList<VariableDMC>();
+                               localsByName.clear();
+                               thisPtrs.clear();
+                               IEDCSymbols symbolsService = getService(IEDCSymbols.class);
+                               IFunctionScope scope = symbolsService
+                                               .getFunctionAtAddress(executionDMC.getSymbolDMContext(), instructionPtrAddress);
+                               if (scope != null) {
+                                       this.variableScope = scope;
+                               }
+                               
+                               while (scope != null && instrPtrLinkAddr != null) {
+                                       Collection<IVariable> scopedVariables = scope.getScopedVariables(instrPtrLinkAddr);
+                                       for (IVariable variable : scopedVariables) {
+                                               VariableDMC var = new VariableDMC(Stack.this, this, variable);
+                                               String name = variable.getName();
+                                               // because of inlined functions, debugger information may indicate that
+                                               // more than one "this" pointer is live at one time
+                                               if (name != null && name.equals("this")) {
+                                                       thisPtrs.put(variable.getScope().getName(), variable);
+                                               } else {
+                                                       // now that we've screened out compiler generated "this" variables,
+                                                       // get rid of other compiler generated variables
+                                                       // TODO: Allow user to choose whether to show compiler generated variables
+                                                       if (var.getVariable().isDeclared()) {
+                                                               VariableDMC haveLocal = localsByName.get(name);
+                                                               if (haveLocal != null) {
+                                                                       localsByName.remove(name);
+                                                                       locals.remove(haveLocal);
+                                                               }
+                                                               locals.add(var);
+                                                               localsByName.put(name, var);
+                                                       }
+                                               }
+                                       }
+
+                                       // if requesting to show all variables, add file-scope globals too
+                                       // (this isn't nearly sufficient since globals can show up
+                                       // in a header while all code is in the source file)
+                                       IScope parentScope = null;
+                                       if (showAllVariablesEnabled)
+                                               parentScope = scope.getParent();
+                                       while (parentScope != null) {
+                                               if (parentScope instanceof ICompileUnitScope) {
+                                                       ICompileUnitScope cuScope = ((ICompileUnitScope) parentScope);
+
+                                                       List<ICompileUnitScope> cuScopes = null;
+                                                       if (this.debugInfoProvider != null) {
+                                                               cuScopes = debugInfoProvider.getCompileUnitsForFile(cuScope.getFilePath());
+                                                       } else {
+                                                               cuScopes = new ArrayList<ICompileUnitScope>(1);
+                                                               cuScopes.add(cuScope);
+                                                       }
+
+                                                       // add the globals of all compile unit scopes for the source file
+                                                       String cuFile = ((ICompileUnitScope) parentScope).getFilePath().toOSString();
+                                                       for (ICompileUnitScope nextCuScope : cuScopes) {
+                                                               Collection<IVariable> globals = nextCuScope.getVariables();
+                                                               if (globals != null) {
+                                                                       for (IVariable variable : globals) {
+                                                                               IPath varFile = variable.getDefiningFile();
+                                                                               if (varFile != null && !varFile.toOSString().equalsIgnoreCase(cuFile))
+                                                                                       continue;
+
+                                                                               VariableDMC var = new VariableDMC(Stack.this, this, variable);
+                                                                               String name = var.getName();
+                                                                               VariableDMC haveLocal = localsByName.get(name);
+                                                                               if (haveLocal != null) {
+                                                                                       localsByName.remove(name);
+                                                                                       locals.remove(haveLocal);
+                                                                               }
+                                                                               locals.add(var);
+                                                                               localsByName.put(name, var);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               parentScope = parentScope.getParent();
+                                       }
+                                       
+                                       if (!(scope.getParent() instanceof IFunctionScope))
+                                               break;
+                                       scope = (IFunctionScope) scope.getParent();
+                               }
+                       }
+                       
+                       // start with "this" pointers, if any
+                       VariableDMC[] localsArray = new VariableDMC[(thisPtrs.isEmpty() ? 0 : 1) + locals.size()];
+                       int i = 0;
+                       if (!thisPtrs.isEmpty())
+                               localsArray[i++] = new VariableDMC(Stack.this, this, getOuterThis());
+                       // TODO For now, turn off ability to see multiple this pointers
+                       // of the form "this$ScopeName"
+//                     for (IVariable variable : thisPtrs.values()) {
+//                             VariableDMC var = new VariableDMC(Stack.this, this, variable);
+//                             var.setName("this$" + variable.getScope().getName());
+//                             localsArray[i++] = var;
+//                     }
+                       for (VariableDMC var : locals)
+                               localsArray[i++] = var;
+                       return localsArray;
+               }
+               
+               /**
+                * From a list of "this" pointers in scope, return the one from the outermost scope
+                * @return this pointer from the outermost scope
+                */
+               private IVariable getOuterThis() {
+                       if (thisPtrs.isEmpty())
+                               return null;
+                       
+                       if (thisPtrs.size() == 1)
+                               return thisPtrs.values().iterator().next();
+
+                       IVariable outer = null;
+                       for (IVariable variable : thisPtrs.values()) {
+                               if (outer == null)
+                                       outer = variable;
+                               else {
+                                       IScope outerScope    = outer.getScope();
+                                       IScope variableScope = variable.getScope();
+                                       if (   variableScope.getLowAddress().compareTo(outerScope.getLowAddress()) < 0
+                                               || variableScope.getHighAddress().compareTo(outerScope.getHighAddress()) > 0)
+                                               outer = variable;
+                               }
+                       }
+                       return outer;
+               }
+
+
+               /**
+                * Find a variable or enumerator by name
+                * 
+                * @param name required name of the variable or enumerator
+                * @param qualifiedName optional fully qualified name of the variable or enumerator
+                * @param localsOnly whether to restrict search to local variables and enumerators only
+                * @return variable or enumerator, if found; otherwise, null
+                * @since 2.0
+                */
+               public IVariableEnumeratorContext findVariableOrEnumeratorByName(String name, String qualifiedName, boolean localsOnly) {
+                       if (name == null)
+                               return null;
+
+                       if (locals == null)
+                               getLocals();
+
+                       // quickly check for a local variable or enumerator
+                       IVariableEnumeratorContext variableOrEnumerator;
+                       
+                       if (qualifiedName != null) {
+                               variableOrEnumerator = localsByName.get(qualifiedName);
+                               if (variableOrEnumerator != null)
+                                       return variableOrEnumerator;
+                       }
+
+                       variableOrEnumerator = localsByName.get(name);
+                       if (variableOrEnumerator != null)
+                               return variableOrEnumerator;
+
+                       if (enumerators == null)
+                               getEnumerators();
+                       
+                       if (qualifiedName != null) {
+                               variableOrEnumerator = enumeratorsByName.get(qualifiedName);
+                               if (variableOrEnumerator != null)
+                                       return variableOrEnumerator;
+                       }
+                       
+                       variableOrEnumerator = enumeratorsByName.get(name);
+                       if (variableOrEnumerator != null)
+                               return variableOrEnumerator;
+                       
+                       if (name.equals("this")) {
+                               if (thisPtrs.isEmpty())
+                                       return null;
+                               return new VariableDMC(Stack.this, this, getOuterThis());
+                       }
+
+                       // TODO For now, turn off ability to see multiple this pointers
+                       // of the form "this$ScopeName"
+//                     if (name.startsWith("this$")) {
+//                             // return the one with the right scope
+//                             if (thisPtrs.isEmpty())
+//                                     return null;
+//                             IVariable variable = thisPtrs.get(name.substring("this$".length()));
+//                             if (variable == null)
+//                                     return null;
+//                             return new VariableDMC(Stack.this, this, variable);
+//                     }
+
+                       if (localsOnly || this.getVariableScope() == null)
+                               return null;
+
+                       // if there is no local variable or enumerator with this name, not very
+                       // efficiently check enclosing scopes for a variable or enumerator
+                       IScope variableScope = this.getVariableScope().getParent();
+
+                       // to find file scope variables, we may need to check several compile units
+                       // associated with one file
+                       ArrayList<IScope> scopes = new ArrayList<IScope>();
+
+                       while (variableOrEnumerator == null && variableScope != null) {
+                               // At the module level, match against globals across the entire symbol
+                               // file, even for big symbol files.
+                               if (variableScope instanceof IModuleScope) {
+                                       Collection<IVariable> variables = ((IModuleScope)variableScope).getVariablesByName(qualifiedName != null ? qualifiedName : name, true);
+                                       if (variables.size() > 0) {
+                                               // list may contain non-global variables, so return the first global
+                                               for (Object varObject : variables) {
+                                                       if (varObject instanceof IVariable) {
+                                                               IVariable variable = (IVariable)varObject;
+                                                               if (variable.getScope() instanceof IModuleScope) {
+                                                                       variableOrEnumerator = new VariableDMC(Stack.this, this, variable);
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       // module scope has no matching global variables
+                                       break;
+                               }
+
+                               scopes.clear();
+
+                               if (variableScope instanceof ICompileUnitScope) {
+                                       // there may be several compile units for a file
+
+                                       // find the module scope parent of the compile unit
+                                       IScope parent = variableScope.getParent();
+                                       while (parent != null && !(parent instanceof IModuleScope))
+                                               parent = parent.getParent();
+
+                                       // find all compile units for the file
+                                       if (parent != null) {
+                                               IPath currentFile = ((ICompileUnitScope)variableScope).getFilePath();
+                                               if (currentFile != null)
+                                                       for (ICompileUnitScope cu : ((IModuleScope)parent).getCompileUnitsForFile(currentFile))
+                                                               scopes.add(cu);
+                                       }
+                               }
+
+                               if (scopes.isEmpty())
+                                       scopes.add(variableScope);
+
+                               for (IScope scope : scopes) {
+                                       for (IVariable scopeVariable : scope.getVariables()) {
+                                               String scopeVariableName = scopeVariable.getName();
+                                               if (qualifiedName != null && scopeVariableName.equals(qualifiedName)) {
+                                                       variableOrEnumerator = new VariableDMC(Stack.this, this, scopeVariable);
+                                                       break;
+                                               }
+
+                                               if (scopeVariableName.equals(name)) {
+                                                       variableOrEnumerator = new VariableDMC(Stack.this, this, scopeVariable);
+                                                       break;
+                                               }
+                                       }
+
+                                       if (variableOrEnumerator == null && scope instanceof IFunctionScope) {
+                                               IFunctionScope functionScope = (IFunctionScope)scope;
+                                               for (IVariable scopeVariable : functionScope.getParameters()) {
+                                                       String scopeVariableName = scopeVariable.getName();
+                                                       if (qualifiedName != null && scopeVariableName.equals(qualifiedName)) {
+                                                               variableOrEnumerator = new VariableDMC(Stack.this, this, scopeVariable);
+                                                               break;
+                                                       }
+
+                                                       if (scopeVariableName.equals(name)) {
+                                                               variableOrEnumerator = new VariableDMC(Stack.this, this, scopeVariable);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+
+                                       if (variableOrEnumerator == null) {
+                                               for (IEnumerator scopeEnumerator : scope.getEnumerators()) {
+                                                       String scopeEnumeratorName = scopeEnumerator.getName();
+                                                       if (qualifiedName != null && scopeEnumeratorName.equals(qualifiedName)) {
+                                                               variableOrEnumerator = new EnumeratorDMC(this, scopeEnumerator);
+                                                               break;
+                                                       }
+
+                                                       if (scopeEnumeratorName.equals(name)) {
+                                                               variableOrEnumerator = new EnumeratorDMC(this, scopeEnumerator);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               variableScope = variableScope.getParent();
+                       }
+                       
+                       return variableOrEnumerator;
+               }
+               
+               public IScope getVariableScope() {
+                       return variableScope;
+               }
+
+               public EnumeratorDMC[] getEnumerators() {
+                       if (enumerators == null) {
+                               enumerators = new ArrayList<EnumeratorDMC>();
+                               if (getServicesTracker() != null) {
+                                       IEDCSymbols symbolsService = getService(Symbols.class);
+                                       if (executionDMC != null && symbolsService != null) {
+                                               IFunctionScope scope = symbolsService.getFunctionAtAddress(executionDMC.getSymbolDMContext(),
+                                                               instructionPtrAddress);
+                                               while (scope != null) {
+                                                       Collection<IEnumerator> localEnumerators = scope.getEnumerators();
+                                                       for (IEnumerator enumerator : localEnumerators) {
+                                                               EnumeratorDMC enumeratorDMC = new EnumeratorDMC(this, enumerator);
+                                                               enumerators.add(enumeratorDMC);
+                                                               enumeratorsByName.put(enumerator.getName(), enumeratorDMC);
+                                                       }
+                                                       if (!(scope.getParent() instanceof IFunctionScope))
+                                                               break;
+                                                       scope = (IFunctionScope) scope.getParent();
+                                               }
+                                       }
+                               }
+                       }
+                       return enumerators.toArray(new EnumeratorDMC[enumerators.size()]);
+               }
+
+               public EnumeratorDMC findEnumeratorbyName(String name) {
+                       if (enumerators == null)
+                               getEnumerators();
+                       return enumeratorsByName.get(name);
+               }
+               
+               /**
+                * Get the view onto registers for this stack frame.  For the top stack frame, this
+                * forwards to the {@link Registers} service.  Otherwise, this information
+                * is synthesized from unwind information in the debug information.  
+                * @return {@link IFrameRegisters}, never <code>null</code>
+                */
+               @SuppressWarnings("unchecked")
+               public IFrameRegisters getFrameRegisters() {
+                       if (frameRegisters == null) {
+                               if (level == 0) {
+                                       // for top of stack, the registers service does the work
+                                       final Registers registers = getEDCServicesTracker().getService(Registers.class);
+                                       frameRegisters = new CurrentFrameRegisters(executionDMC, registers);
+                               } else {
+                                       // see if symbolics can provide unwinding support
+                                       if (module != null) {
+                                               Symbols symbolsService = getService(Symbols.class);
+                                               IFrameRegisterProvider frameRegisterProvider = symbolsService.getFrameRegisterProvider(
+                                                               executionDMC.getSymbolDMContext(), instructionPtrAddress);
+                                               if (frameRegisterProvider != null) {
+                                                       try {
+                                                               frameRegisters = frameRegisterProvider.getFrameRegisters(
+                                                                               getSession(), getEDCServicesTracker(), this);
+                                                       } catch (CoreException e) {
+                                                               // debug info failure; we should report this 
+                                                               frameRegisters = new AlwaysFailingFrameRegisters(e);
+                                                       }
+                                               }
+                                       }
+                                       
+                                       if (frameRegisters == null) {
+                                               // no information from symbolics; see if the stack unwinder found anything
+                                               final Map<Integer, BigInteger> preservedRegisters = (Map<Integer,BigInteger>) properties.get(
+                                                               PRESERVED_REGISTERS);
+                                               if (preservedRegisters != null) {
+                                                       frameRegisters = new PreservedFrameRegisters(dsfServicesTracker, StackFrameDMC.this, preservedRegisters);
+                                               }
+                                       }
+                                       
+                                       if (frameRegisters == null) {
+                                               frameRegisters = new AlwaysFailingFrameRegisters(
+                                                               EDCDebugger.newCoreException("cannot read variables in this frame"));
+                                       }
+                               }
+                       }
+                       return frameRegisters;
+               }
+
+               /**
+                * Get the frame this one has called.
+                * @return StackFrameDMC or <code>null</code> for top of stack
+                */
+               public StackFrameDMC getCalledFrame() throws CoreException {
+                       return calledFrame;
+               }
+
+               /**
+                * Get a type engine (which holds cached information about types for use by expressions)
+                * @return TypeEngine instance
+                */
+               public TypeEngine getTypeEngine() {
+                       return typeEngine;
+               }
+               
+               public IEDCModuleDMContext getModule() {
+                       return module;
+               }
+
+               private Stack getOuterType() {
+                       return Stack.this;
+               }
+               
+       }
+
+       public class VariableData implements IVariableDMData {
+
+               private final String name;
+
+               public VariableData(VariableDMC variableDMC) {
+                       name = variableDMC.getName();
+               }
+
+               public String getName() {
+                       return name;
+               }
+
+               public String getValue() {
+                       return "0";
+               }
+
+       }
+
+       public class VariableDMC extends DMContext implements IVariableDMContext, IVariableEnumeratorContext {
+
+               public static final String PROP_LOCATION = "Location";
+               private final IVariable variable;
+
+               public VariableDMC(IDsfService service, StackFrameDMC frame, IVariable variable) {
+                       super(Stack.this, new IDMContext[] { frame }, variable.getName(), variable.getName());
+                       this.variable = variable;
+               }
+
+               public IVariable getVariable() {
+                       return variable;
+               }
+       }
+
+       public class EnumeratorDMC extends DMContext implements IEnumeratorDMContext, IVariableEnumeratorContext {
+
+               private final IEnumerator enumerator;
+
+               public EnumeratorDMC(StackFrameDMC frame, IEnumerator enumerator) {
+                       super(Stack.this, new IDMContext[] { frame }, enumerator.getName(), enumerator.getName());
+                       this.enumerator = enumerator;
+               }
+
+               public IEnumerator getEnumerator() {
+                       return enumerator;
+               }
+       }
+
+       /**
+        * @param classNames
+        *            the type names the service will be registered under. See
+        *            AbstractDsfService#register for details. We tack on base DSF's
+        *            IStack and this class to the list if not provided.
+        */
+       public Stack(DsfSession session, String[] classNames) {
+               super(session, 
+                               massageClassNames(classNames, 
+                                               new String[] { IStack.class.getName(), Stack.class.getName() }));
+       }
+
+       /**
+        * @since 2.0
+        */
+       public static String createFrameID(IEDCExecutionDMC executionDMC, EdcStackFrame edcFrame) {
+               int level = (Integer) edcFrame.props.get(StackFrameDMC.LEVEL_INDEX);
+               String parentID = executionDMC.getID();
+               return parentID + ".frame[" + level + "]";
+       }
+
+       @Override
+       protected void doInitialize(RequestMonitor requestMonitor) {
+               super.doInitialize(requestMonitor);
+               getSession().addServiceEventListener(this, null);
+       }
+
+       public void getArguments(IFrameDMContext frameCtx, DataRequestMonitor<IVariableDMContext[]> rm) {
+               // never called by DSF. it expects arguments to be lumped in with
+               // locals.
+               rm.done();
+       }
+
+       public void getFrameData(IFrameDMContext frameDmc, DataRequestMonitor<IFrameDMData> rm) {
+               if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(frameDmc)); }
+               rm.setData(new StackFrameData((StackFrameDMC) frameDmc));
+               if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(rm.getData())); }
+               rm.done();
+       }
+
+       public void getFrames(final IDMContext execContext, final DataRequestMonitor<IFrameDMContext[]> rm) {
+               if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(execContext)); }
+
+               final ExecutionDMC execDmc = DMContexts.getAncestorOfType(execContext, ExecutionDMC.class);
+               if (execDmc != null)
+               {
+                       if (!execDmc.isSuspended())
+                       {
+                               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_STATE, "Context is running: " + execDmc, null)); //$NON-NLS-1$
+                               rm.done();
+                               return;
+                       }
+                       
+                       asyncExec(new Runnable() {
+                               public void run() {
+                                       try {
+                                               rm.setData(getFramesForDMC((ExecutionDMC) execContext, 0, ALL_FRAMES));
+                                               if (rm.getData().length == 0)
+                                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_STATE, "No stack frame available for: " + execDmc, null)); //$NON-NLS-1$
+                                       } catch (CoreException e) {
+                                               Status s = new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), null, e);
+                                               EDCDebugger.getMessageLogger().log(s);
+                                               rm.setStatus(s);
+                                       }
+                                       if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(rm.getData())); }
+                                       rm.done();
+                               }
+                               
+                       }, rm);
+
+               }
+               else {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+                       rm.done();
+               }
+       }
+
+       public void getLocals(final IFrameDMContext frameCtx, final DataRequestMonitor<IVariableDMContext[]> rm) {
+               asyncExec(new Runnable() {
+                       public void run() {
+                               final StackFrameDMC frameContext = (StackFrameDMC) frameCtx;
+                               IAddress contextIPAddress = frameContext.getInstructionPtrAddress();
+                               boolean useVariableCache = false;
+                               // the frame context passed in may be "stale".  it may prove equal to the current frame,
+                               // but if the instruction ptr address is different, then the locals won't be collected properly
+                               try {
+                                       IFrameDMContext[] iFrames = getFramesForDMC(frameContext.getExecutionDMC(), 0, ALL_FRAMES);
+                                       for (IFrameDMContext iFrameDMC : iFrames) {
+                                               if (frameCtx == iFrameDMC) {
+                                                       useVariableCache = true;
+                                                       break;
+                                               }
+                                               if (frameContext.equals(iFrameDMC)) {
+                                                       StackFrameDMC frameDMC = (StackFrameDMC)iFrameDMC;
+                                                       IAddress stackFrameIPAddr = frameDMC.getInstructionPtrAddress(); 
+                                                       if (contextIPAddress.equals(stackFrameIPAddr)) {
+                                                               useVariableCache = true;
+                                                       } else {
+                                                               frameContext.setInstructionPtrAddress(stackFrameIPAddr);
+                                                       }
+                                                       break;
+                                               }
+                                       }
+
+                                       rm.setData(frameContext.getLocals(useVariableCache));
+                               } catch (CoreException e) {
+                                       EDCDebugger.getMessageLogger().log(e.getStatus());
+                                       rm.setStatus(e.getStatus());
+                               }
+                               rm.done();
+                       }
+               }, rm);
+       }
+
+       public void getStackDepth(IDMContext dmc, final int maxDepth, final DataRequestMonitor<Integer> rm) {
+               if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { dmc, maxDepth })); }
+               
+               final ExecutionDMC execDmc = DMContexts.getAncestorOfType(dmc, ExecutionDMC.class);
+               if (execDmc != null)
+               {
+                       if (!execDmc.isSuspended())
+                       {
+                               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_STATE, "Context is running: " + execDmc, null)); //$NON-NLS-1$
+                               rm.done();
+                               return;
+                       }
+
+                       asyncExec(new Runnable() {
+                               public void run() {
+                                       int startFrame = 0;
+                                       int endFrame = ALL_FRAMES;      
+                                       if (maxDepth > 0)
+                                               endFrame = maxDepth - 1;
+                                       try {
+                                               rm.setData(getFramesForDMC(execDmc, startFrame, endFrame).length);
+                                               if (rm.getData() == 0)
+                                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_STATE, "No stack frame available for: " + execDmc, null)); //$NON-NLS-1$
+                                               if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceExit(null, rm.getData()); }
+                                       } catch (CoreException e) {
+                                               Status s = new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), null, e);
+                                               EDCDebugger.getMessageLogger().log(s);
+                                               rm.setStatus(s);
+                                       }
+                                       rm.done();
+                               }
+                       }, rm);
+               }
+               else {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+                       rm.done();
+               }
+       }
+
+       public void getTopFrame(final IDMContext execContext, final DataRequestMonitor<IFrameDMContext> rm) {
+               if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(execContext)); }
+
+               asyncExec(new Runnable() {
+                       public void run() {
+                               try {
+                                       IFrameDMContext[] frames = getFramesForDMC((ExecutionDMC) execContext, 0, 0);
+                                       if (frames.length == 0) {
+                                               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_STATE,
+                                                               "No top stack frame available", null)); //$NON-NLS-1$
+                                               rm.done();
+                                               return;
+                                       }
+                                       rm.setData(frames[0]);
+                               } catch (CoreException e) {
+                                       Status s = new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), null, e);
+                                       EDCDebugger.getMessageLogger().log(s);
+                                       rm.setStatus(s);
+                               }
+                               if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(rm.getData())); }
+                               rm.done();
+                       }
+               }, rm);
+
+       }
+
+       public void getVariableData(IVariableDMContext variableDmc, DataRequestMonitor<IVariableDMData> rm) {
+               rm.setData(new VariableData((VariableDMC) variableDmc));
+               rm.done();
+       }
+
+       @SuppressWarnings("unchecked")
+       public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
+               if (dmc instanceof IFrameDMContext) {
+                       getFrameData((IFrameDMContext) dmc, (DataRequestMonitor<IFrameDMData>) rm);
+               } else if (dmc instanceof IVariableDMContext) {
+                       getVariableData((IVariableDMContext) dmc, (DataRequestMonitor<IVariableDMData>) rm);
+               } else
+                       rm.done();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.cdt.dsf.debug.service.IStack#getFrames(org.eclipse.cdt.dsf.datamodel.IDMContext, int, int, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+        */
+       public void getFrames(final IDMContext execContext, final int startIndex, final int endIndex, final DataRequestMonitor<IFrameDMContext[]> rm) {
+               if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { execContext, startIndex, endIndex })); }
+               final ExecutionDMC execDmc = DMContexts.getAncestorOfType(execContext, ExecutionDMC.class);
+               if (execDmc != null)
+               {
+                       if (!execDmc.isSuspended())
+                       {
+                               rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_STATE, "Context is running: " + execDmc, null)); //$NON-NLS-1$
+                               rm.done();
+                               return;
+                       }
+
+                       asyncExec(new Runnable() {
+                               public void run() {
+                                       try {
+                                               rm.setData(getFramesForDMC((ExecutionDMC) execContext, startIndex, endIndex));
+                                               if (rm.getData().length == 0)
+                                                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_STATE, "No stack frame available for: " + execContext, null)); //$NON-NLS-1$
+                                       } catch (CoreException e) {
+                                               Status s = new Status(IStatus.ERROR, EDCDebugger.getUniqueIdentifier(), null, e);
+                                               EDCDebugger.getMessageLogger().log(s);
+                                               rm.setStatus(s);
+                                       }
+                                       if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArgs(rm.getData())); }
+                                       rm.done();
+                               }
+                               
+                       }, rm);
+
+               }
+               else {
+                       rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+                       rm.done();
+               }
+               if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArgs(rm.getData())); }
+       }
+
+       public IFrameDMContext[] getFramesForDMC(IEDCExecutionDMC context, int startIndex, int endIndex) throws CoreException {
+               if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { context, startIndex, endIndex })); }
+
+               if (!context.isSuspended() || 
+                       ! RunControl.isNonContainer(context))   // no frames for container context. 
+               {
+                       return new IFrameDMContext[0];
+               }
+
+               boolean needsUpdate = false;
+               synchronized (stackFrames) {
+                       List<StackFrameDMC> frames = stackFrames.get(context.getID());
+                       // Need to update the frames if there is no cached list for this
+                       // context or if the cached list does not include all of the
+                       // requested frames.
+                       if (frames == null) {
+                               // nothing in the cache so need to update
+                               needsUpdate = true;
+                       } else if (allFramesCached.get(context.getID())) {
+                               // all frames are cached
+                               needsUpdate = false;
+                       } else if (endIndex == ALL_FRAMES) {
+                               // some but not all frames cached
+                               needsUpdate = true;
+                       } else {
+                               // some but not all requested frames cached
+                               needsUpdate = (frames.get(0).getLevel() > startIndex || 
+                                               frames.get(frames.size() - 1).getLevel() < endIndex);
+                       }
+
+                       if (needsUpdate)
+                               updateFrames(context, startIndex, endIndex);
+
+                       frames = stackFrames.get(context.getID());
+                       // endIndex is inclusive and may be negative to fetch all frames
+                       if (endIndex >= 0) {
+                               if (startIndex < frames.size() && startIndex <= endIndex) {
+                                       frames = frames.subList(startIndex, Math.min(endIndex + 1, frames.size()));
+                               } else {
+                                       frames = Collections.emptyList();
+                               }
+                       }
+                       IFrameDMContext[] result = frames.toArray(new IFrameDMContext[frames.size()]);
+                       if (EDCTrace.STACK_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArgs(result)); }
+                       return result;
+               }
+       }
+
+       private void updateFrames(IEDCExecutionDMC context, int startIndex, int endIndex) throws CoreException {
+               ArrayList<StackFrameDMC> frames = new ArrayList<StackFrameDMC>();
+               List<EdcStackFrame> edcFrames = computeStackFrames(context, startIndex, endIndex);
+               StackFrameDMC previous = null;
+               for (EdcStackFrame edcFrame : edcFrames) {
+                       StackFrameDMC frame = new StackFrameDMC(context, edcFrame);
+                       if (previous != null) {
+                               frame.calledFrame = previous;
+                               // note: don't store "callerFrame" since this is missing if only a partial stack was fetched
+                       }
+                       frames.add(frame);
+                       previous = frame;
+               }
+               
+               stackFrames.put(context.getID(), frames);
+               
+               // all frames are cached if we request all frames, or if the returned number of frames was less than
+               // the requested max number of frames.  e.g. if we ask for 10 and they return 9, it's because there
+               // are only 9 frames.  so we have calculated all of them.
+               allFramesCached.put(context.getID(), startIndex == 0 && ((endIndex == ALL_FRAMES) || (frames.size() <= endIndex)));
+       }
+
+       /**
+        * A stack frame described as one or more of the following properties, plus
+        * any additional custom ones.
+        * 
+        * <ul>
+        * <li>{@link StackFrameDMC#LEVEL_INDEX}
+        * <li>{@link StackFrameDMC#ROOT_FRAME}
+        * <li>{@link StackFrameDMC#BASE_ADDR}
+        * <li>{@link StackFrameDMC#INSTRUCTION_PTR_ADDR}
+        * <li>{@link StackFrameDMC#MODULE_NAME}
+        * <li>{@link StackFrameDMC#SOURCE_FILE}
+        * <li>{@link StackFrameDMC#FUNCTION_NAME}
+        * <li>{@link StackFrameDMC#LINE_NUMBER}
+        * <li>{@link StackFrameDMC#IN_PROLOGUE}
+        * <li>{@link StackFrameDMC#PRESERVED_REGISTERS}
+        * </ul>
+        * 
+        * @since 2.0
+        */
+       public class EdcStackFrame {
+               public EdcStackFrame(Map<String, Object> props) { 
+                       this.props = props; 
+               }
+               public Map<String, Object> props;
+       }
+       
+       protected abstract List<EdcStackFrame> computeStackFrames(IEDCExecutionDMC context, int startIndex, int endIndex) throws CoreException;
+
+       public void loadFramesForContext(IEDCExecutionDMC exeDmc, Element allFrames) throws Exception {
+               flushCache(null);
+               List<StackFrameDMC> frames = Collections.synchronizedList(new ArrayList<StackFrameDMC>());
+
+               NodeList frameElements = allFrames.getElementsByTagName(STACK_FRAME);
+
+               int numFrames = frameElements.getLength();
+               StackFrameDMC previousFrameDMC = null;
+               
+               for (int i = 0; i < numFrames; i++) {
+                       Element groupElement = (Element) frameElements.item(i);
+                       Element propElement = (Element) groupElement.getElementsByTagName(SnapshotUtils.PROPERTIES).item(0);
+                       HashMap<String, Object> properties = new HashMap<String, Object>();
+                       SnapshotUtils.initializeFromXML(propElement, properties);
+
+                       // ensure that stack level numbering is canonical: 
+                       // we expect level==0 to be the top, but it used to be 1
+                       properties.put(StackFrameDMC.LEVEL_INDEX, i);
+                       
+                       StackFrameDMC frameDMC = new StackFrameDMC(exeDmc, new EdcStackFrame(properties));
+                       frameDMC.loadSnapshot(groupElement);
+                       if (previousFrameDMC != null) {
+                               frameDMC.calledFrame = previousFrameDMC;
+                       }
+                       frames.add(frameDMC);
+
+                       previousFrameDMC = frameDMC;
+               }
+               stackFrames.put(exeDmc.getID(), frames);
+               allFramesCached.put(exeDmc.getID(), true);
+       }
+
+       public void flushCache(IDMContext context) {
+               if (isSnapshot())
+                       return;
+               if (context != null && context instanceof IEDCDMContext) {
+                       String contextID = ((IEDCDMContext) context).getID();
+                       stackFrames.remove(contextID);
+                       allFramesCached.remove(contextID);
+               } else {
+                       stackFrames.clear();
+                       allFramesCached.clear();
+               }
+       }
+
+       @DsfServiceEventHandler
+       public void eventDispatched(ISuspendedDMEvent e) {
+               flushCache(e.getDMContext());
+       }
+
+       @DsfServiceEventHandler
+       public void eventDispatched(IResumedDMEvent e) {
+               flushCache(e.getDMContext());
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/messages.properties b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/messages.properties
new file mode 100644 (file)
index 0000000..6d2918b
--- /dev/null
@@ -0,0 +1,4 @@
+AbstractEDCService_0=The EDC session thread pool has been overwhelmed. This may be indicative of either a problem with the debugger or an unexpectedly high concentration of activity. The latter can be remedied. Contact the CDT development team for more info.
+AbstractEDCService_1=Unhandled exception
+AbstractEDCService_2=Unhandled exception
+AbstractEDCService_3=User cancelled operation
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/snapshot/IAlbum.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/snapshot/IAlbum.java
new file mode 100644 (file)
index 0000000..71fa679
--- /dev/null
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.snapshot;
+
+import java.util.HashMap;
+import java.util.List;
+
+import org.eclipse.cdt.debug.core.sourcelookup.MappingSourceContainer;
+import org.eclipse.cdt.debug.edc.internal.snapshot.Snapshot;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
+
+public interface IAlbum {
+
+       public String getName();
+
+       public String getDisplayName();
+
+       public String getSessionID();
+
+       public String getRecordingSessionID();
+
+       public void openSnapshot(final int index);
+
+       /**
+        * Zero based index
+        * 
+        * @return current index of snapshot being played
+        */
+       public int getCurrentSnapshotIndex();
+
+       public void openNextSnapshot() throws Exception;
+
+       public void openPreviousSnapshot() throws Exception;
+
+       /**
+        * Get the location of the album contents, extracted to disk in the workspace.
+        * @return path to the extracted files
+        */
+       public IPath getAlbumRootDirectory();
+
+       public String getLaunchTypeID();
+
+       public HashMap<String, Object> getLaunchProperties();
+
+       public String getLaunchName();
+
+
+       public void addFile(IPath path);
+
+       public IPath getLocation();
+
+       public void configureSourceLookupDirector(ISourceLookupDirector director);
+
+       public void configureMappingSourceContainer(
+                       MappingSourceContainer mappingContainer);
+
+       public List<Snapshot> getSnapshots();
+
+       public boolean isLoaded();
+
+       public boolean isRecording();
+       
+       /**
+        * @since 2.0
+        */
+       public void playSnapshots();
+       
+       /**
+        * @since 2.0
+        */
+       public boolean isPlayingSnapshots();
+       
+       /**
+        * @since 2.0
+        */
+       public void stopPlayingSnapshots();
+
+}
\ No newline at end of file
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/snapshot/ISnapshotContributor.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/snapshot/ISnapshotContributor.java
new file mode 100644 (file)
index 0000000..b84f5cb
--- /dev/null
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.snapshot;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * The Interface ISnapshotContributor provides a way for objects to contribute data to
+ * a debug snapshot.
+ */
+public interface ISnapshotContributor {
+
+       /**
+        * Take a snapshot of this object's data.
+        *
+        * @param album the owning snapshot album
+        * @param document the xml document used to store the data
+        * @param monitor the progress monitor to use for reporting progress to the user. It is the caller's responsibility
+        to call done() on the given monitor. Accepts null, indicating that no progress should be
+        reported and that the operation cannot be canceled.
+        * @return the xml element containing the saved data.
+        * @since 2.0
+        */
+       public Element takeSnapshot(IAlbum album, Document document, IProgressMonitor monitor) throws Exception;
+
+       /**
+        * Load an object's data from a previously saved snapshot.
+        *
+        * @param element the xml element containing the data
+        * @throws Exception if anything goes wrong
+        */
+       public void loadSnapshot(Element element) throws Exception;
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ICompileUnitScope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ICompileUnitScope.java
new file mode 100644 (file)
index 0000000..d40b4e2
--- /dev/null
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.util.Collection;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Interface representing a compile unit scope. A compile unit is a source or
+ * header file which contains functions.
+ */
+public interface ICompileUnitScope extends IScope {
+
+       /**
+        * Get the path to the compile unit file (source/header)
+        * 
+        * @return the file path as defined in the symbolics
+        */
+       IPath getFilePath();
+
+       /**
+        * Get the function at the given link address
+        * 
+        * @param linkAddress
+        *            the link address
+        * @return the function, or null if none found
+        */
+       IFunctionScope getFunctionAtAddress(IAddress linkAddress);
+       
+
+       /**
+        * Get all the top-level functions in the compilation unit.
+        * (This ensures the CU is parsed, unlike {@link #getChildren()}.)
+        * @return the list of functions
+        * @return an unmodifiable list of functions, maybe empty
+        */
+       Collection<IFunctionScope> getFunctions();
+
+       /**
+        * Get the list of line table entries for the entire compile unit.
+        * These may represent contributions for multiple files (e.g.,
+        * sources and #included headers).
+        * 
+        * @return unmodifiable list of line entries, which may be empty
+        */
+       Collection<ILineEntry> getLineEntries();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IDebugInfoProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IDebugInfoProvider.java
new file mode 100644 (file)
index 0000000..b6578a1
--- /dev/null
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * This interface handles fetching debug information from a particular 
+ * debug information format.
+ */
+public interface IDebugInfoProvider {
+       /**
+        * Dispose resources held by the provider 
+        */
+       void dispose();
+
+       /**
+        * Get the absolute host path to the symbolics
+        * @return IPath, never <code>null</code>
+        */
+       IPath getSymbolFile();
+       
+       /**
+        * Get the corresponding executable used for symbolics.  This may be different from the
+        * running executable.
+        */
+       IExecutableSymbolicsReader getExecutableSymbolicsReader();
+
+       /**
+        * Get the module scope, which contains the unified set of global code
+        * and symbols (and, implicitly, the types they reference) accessible at runtime. 
+        */
+       IModuleScope getModuleScope();
+
+       /**
+        * Get the paths to all source files known for the module.
+        * @return non-<code>null</code> array of build-time paths
+        */
+       String[] getSourceFiles(IProgressMonitor monitor);
+       
+       /**
+        * Get all functions with the given name in any scope in the module
+        * 
+        * @param name
+        *            the function name
+        * @return unmodifiable list of functions, which may be empty
+        */
+       Collection<IFunctionScope> getFunctionsByName(String name);
+
+       /**
+        * Get all variables with the given name in any scope in the module
+        * 
+        * @param name
+        *            the variable name, or <code>null</code> to get all variables
+        * @param globalsOnly
+        *            whether to assume local variables in scope have been recorded
+     *            and only globally-visible variables remain to be found
+        * @return unmodifiable list of variables, which may be empty
+        */
+       Collection<IVariable> getVariablesByName(String name, boolean globalsOnly);
+
+       /**
+        * Get the compile unit at the given link address
+        * 
+        * @param address
+        *            the link address
+        * @return the compile unit at the address, or null if none
+        */
+       ICompileUnitScope getCompileUnitForAddress(IAddress linkAddress);
+
+       /**
+        * Get the compile unit for the given file
+        * 
+        * @param filePath
+        *            the file path as defined in the symbolics
+        * @return a list of the compile units for this file, or null if none
+        */
+       List<ICompileUnitScope> getCompileUnitsForFile(IPath filePath);
+       
+       /**
+        * Get the type with the given name
+        * @param name
+        *              canonical base type name (trimmed, multiple     spaces replaced
+        *              by single spaces, no "*" chars)
+        * @return unmodifiable list of types, which may be empty
+        */
+       Collection<IType> getTypesByName(String name);
+
+       /**
+        * Get all the types declared in the module (which may
+     * include forward definitions).
+        * @return unmodifiable list of types, which may be empty.
+        */
+       Collection<IType> getTypes();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IDebugInfoProviderFactory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IDebugInfoProviderFactory.java
new file mode 100644 (file)
index 0000000..028cf61
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.symbols;
+
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * This factory creates debug info providers for files.
+ */
+public interface IDebugInfoProviderFactory {
+       String EXTENSION_ID = "org.eclipse.cdt.debug.edc.debugInfoProviderFactory"; //$NON-NLS-1$
+
+       /**
+        * Create a debug info provider for the given executable reader.  This can
+        * fetch information from the executable itself or reference an associated
+        * symbolics file (e.g. *.sym or *.dbg).
+        * @param binaryFile the host-side path of the binary
+        * @param reader the reader for the executable, or <code>null</code>
+        * @return a new {@link IDebugInfoProvider} or <code>null</code> if unsupported 
+        */
+       IDebugInfoProvider createDebugInfoProvider(IPath binaryFile, IExecutableSymbolicsReader reader);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IEDCSymbolReader.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IEDCSymbolReader.java
new file mode 100644 (file)
index 0000000..ff87372
--- /dev/null
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import org.eclipse.cdt.core.ISymbolReader;
+
+/**
+ * Top-level interface for getting symbolics information.  The executable
+ * symbolics reader and IDebugInfoProvider (behind the scenes) work together
+ * to provide the full information.  The symbolics
+ * information includes debug information (e.g. DWARF, CODEVIEW) and symbol
+ * table data. A binary file may only have symbol table without debug
+ * information.
+ */
+public interface IEDCSymbolReader extends IExecutableSymbolicsReader, ISymbolReader {
+       /**
+        * Call when the reader is no longer needed and should free up any resources.
+        */
+       void shutDown();
+
+       /**
+        * Check whether the symbol file has debug information recognized by this
+        * reader. The debug information here means data in the binary file that's
+        * specially for debugger, such as DWARF and CODEVIEW. The symbol table
+        * section data in many types of binary files is not considered debug
+        * information here.
+        * 
+        * @return true if the symbol reader has dedicated debug information
+        */
+       boolean hasRecognizedDebugInformation();
+       
+       /**
+        * Get the module-level scope for the primary symbol file
+        * @return scope, never <code>null</code>
+        * @see #getSymbolFile()
+        */
+       IModuleScope getModuleScope();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IEnumerator.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IEnumerator.java
new file mode 100644 (file)
index 0000000..2aa4ef0
--- /dev/null
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+/**
+ * Interface representing an enumerator (what's inside enum {}). E.g.,
+*  enum {Red, Green, Blue} has enumerators Red, Green, Blue
+ */
+public interface IEnumerator {
+
+       /**
+        * Get the name of the enumerator
+        * 
+        * @return the enumerator name
+        */
+       String getName();
+
+       /**
+        * Get the value of the enumerator.
+        * 
+        * @return the enumerator value
+        */
+       long getValue();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IExecutableSection.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IExecutableSection.java
new file mode 100644 (file)
index 0000000..2eef95f
--- /dev/null
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import org.eclipse.cdt.debug.edc.IStreamBuffer;
+
+/**
+ * This abstracts access to a particular section in an executable
+ */
+public interface IExecutableSection {
+       /**
+        * Get the name of the section.
+        */
+       String getName();
+       
+       /**
+        * Get the buffer for the section.  This may be thrown away and reloaded on demand.
+        * The buffer has the correct endianness already set.
+        * @return buffer, or <code>null</code> if failed to load
+        */
+       IStreamBuffer getBuffer();
+
+       /**
+        * Free the buffer allocated for this section.
+        */
+       void dispose();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IExecutableSymbolicsReader.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IExecutableSymbolicsReader.java
new file mode 100644 (file)
index 0000000..c4ba5b5
--- /dev/null
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.nio.ByteOrder;
+import java.util.Collection;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISection;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Interface for handling different kinds of executables.  This manages
+ * the mid-level access to different executable formats (ELF, PE-COFF, etc.). 
+ */
+public interface IExecutableSymbolicsReader {
+       /**
+        * Dispose the reader and any files or memory it is holding
+        */
+       void dispose();
+       
+       /**
+        * Get the file represented by this reader
+        */
+       IPath getSymbolFile();
+       
+       /**
+        * Get the executable sections from the symbol file (names and buffers)
+        * @return unmodifiable list of sections
+        */
+       Collection<IExecutableSection> getExecutableSections();
+
+       /**
+        * Get a section with the given name
+        * @param sectionName
+        * @return {@link IExecutableSection} or <code>null</code>
+        */
+       IExecutableSection findExecutableSection(String sectionName);
+       
+       /**
+        * Get the (low level) sections from the symbol file
+        * 
+        * @return unmodifiable list of sections
+        */
+       Collection<ISection> getSections();
+
+       /**
+        * Get the base image address generated by the linker
+        * 
+        * @return the base address, or null if unknown
+        */
+       IAddress getBaseLinkAddress();
+
+       /**
+        * Get the modification date of the symbol file when it was parsed. This is
+        * used for caching purposes.
+        * 
+        * @return the modification date (e.g. file.lastModified())
+        */
+       long getModificationDate();
+       
+       /**
+        * Find symbol(s) with the given name.  If no exact
+        * matches are found, also search for a symbol whose
+        * undecorated variant matches the name (e.g. in Win32, "_main" -> "main",
+        * "__imp_foo@8" -> "foo"). 
+        * @param name name of the symbol
+        * @return collection of matching symbols, may be empty
+        */
+       Collection<ISymbol> findSymbols(String name);
+
+       /**
+        * Find symbol(s) with the given unmangled name.
+        * The name will be interpreted as if spaces are irrelevant.
+        * The name will be matched as if a fully qualified name (e.g.
+     * leading "::" may be missing).
+        * If a symbol is a function and the name does not include
+        * arguments, any function with the same qualified name matches
+     * (e.g. "foo(int)" for name="foo").
+        * @param name name of unmangled string (e.g. "Foo::Bar", "main", "::std::myfunc(int)")
+        * @return collection of matching symbols, may be empty
+        */
+       Collection<ISymbol> findUnmangledSymbols(String name);
+
+       /**
+        * Get the symbols from the symbol table
+        * 
+        * @return unmodifiable list of symbols
+        */
+       Collection<ISymbol> getSymbols();
+
+
+       /**
+        * Get the symbol that contains the given link address
+        * 
+        * @param linkAddress
+        *            the link address
+        * @return the symbol containing this address, or null if none found
+        */
+       ISymbol getSymbolAtAddress(IAddress linkAddress);
+
+       /**
+        * Get the byte order of data in the executable
+        * @return {@link ByteOrder}
+        */
+       ByteOrder getByteOrder();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IExecutableSymbolicsReaderFactory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IExecutableSymbolicsReaderFactory.java
new file mode 100644 (file)
index 0000000..78a21b0
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.symbols;
+
+import org.eclipse.core.runtime.IPath;
+
+public interface IExecutableSymbolicsReaderFactory {
+
+       String EXTENSION_ID = "org.eclipse.cdt.debug.edc.executableSymbolicsReaderFactory"; //$NON-NLS-1$
+
+       /**
+        * @since 2.0
+        */
+       static final int NO_CONFIDENCE = 0;
+       /**
+        * @since 2.0
+        */
+       static final int LOW_CONFIDENCE = 25;
+       /**
+        * @since 2.0
+        */
+       static final int NORMAL_CONFIDENCE = 50;
+       /**
+        * @since 2.0
+        */
+       static final int HIGH_CONFIDENCE = 75;
+
+       /**
+        * Used to help determine if this factory can read the given binary file.  If so,
+        * the confidence returned is used to help determine which factory to use if more
+        * than one can read this file.
+        * @param binaryFile
+        * @return NO_CONFIDENCE if it cannot read the binary, otherwise one of LOW_CONFIDENCE,
+        * NORMAL_CONFIDENCE or HIGH_CONFIDENCE.
+        * @since 2.0
+        */
+       int getConfidence(IPath binaryFile);
+
+       /**
+        * Create an executable symbolics reader for the given binary file.
+        * @param binaryFile
+        * @return a new {@link IExecutableSymbolicsReader} or <code>null</code> if unsupported 
+        */
+       IExecutableSymbolicsReader createExecutableSymbolicsReader(IPath binaryFile);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IFunctionScope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IFunctionScope.java
new file mode 100644 (file)
index 0000000..4094d3a
--- /dev/null
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.util.Collection;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Interface representing a function scope. A function is a block of code
+ * (function/method) which may have parameters and lexical blocks.
+ * <p>
+ * TODO: Note: a function's scope is either {@link IFunctionScope} or {@link ICompileUnitScope}.
+ * This does <b>not</b> reflect language scoping.  Thus, there is currently no way to
+ * find out if a function is a method of a given class (except, perhaps, by looking
+ * at a 'this' parameter and introspecting its type).  (But nothing currently handles
+ * namespaces.)
+ */
+public interface IFunctionScope extends IScope {
+
+       /**
+        * Gets the list of variables in this scope and any child scopes
+        * (for functions and lexical blocks)
+        * 
+        * @return unmodifiable list of variables which may be empty
+        */
+       Collection<IVariable> getVariablesInTree();
+       
+       
+       /**
+        * Get function parameters
+        * 
+        * @return unmodifiable list of parameters which may be empty
+        */
+       Collection<IVariable> getParameters();
+       
+       /**
+        * Get the variables live at the given address, by using ILexicalBlockScope
+        * and embedded IFunctionScopes, as well as using {@link IVariable#getLocationProvider()}
+        * information.
+        * @param linkAddress the link-time address
+        * @return unmodifiable list of locals which may be empty
+        */
+       Collection<IVariable> getScopedVariables(IAddress linkAddress);
+       
+       /**
+        * Get the location provider for the frame base.
+        * 
+        * @return the location provider, or null if none
+        */
+       ILocationProvider getFrameBaseLocation();
+
+       /**
+        * Get the file where the function was declared, if known.
+        * @return IPath or <code>null</code>
+        */
+       IPath getDeclFile();
+
+       /**
+        * Get the line number where the function was declared, if known.
+        * @return line number, 1-based (0 if unknown)
+        */
+       int getDeclLine();
+       
+       /**
+        * Get the column number where the function was declared, if known.
+        * @return column number, 1-based (0 if unknown)
+        */
+       int getDeclColumn();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IInvalidVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IInvalidVariableLocation.java
new file mode 100644 (file)
index 0000000..6e5b409
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+
+/**
+ * Interface representing that a variable location is invalid
+ */
+public interface IInvalidVariableLocation extends IVariableLocation {
+
+       /**
+        * Set message
+        * 
+        * @param message
+        *            description of why the location is not valid
+        */
+       public void setMessage(String message);
+
+       /**
+        * Get message
+        * 
+        * @return description of why the location is not valid
+        */
+       public String getMessage();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ILineEntry.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ILineEntry.java
new file mode 100644 (file)
index 0000000..1dfbfe5
--- /dev/null
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Interface that represents a line table entry
+ */
+public interface ILineEntry extends Comparable<Object> {
+
+       /**
+        * Get the file path that the line entry applies to
+        * 
+        * @return the file path as defined in the symbolics
+        */
+       IPath getFilePath();
+
+       /**
+        * Get the line number in the file
+        * 
+        * @return the line number
+        */
+       int getLineNumber();
+
+       /**
+        * Get the column number in the line
+        * 
+        * @return
+        */
+       int getColumnNumber();
+
+       /**
+        * Get the low link address of the line entry
+        * 
+        * @return the low address
+        */
+       IAddress getLowAddress();
+
+       /**
+        * Get the high link address of the line entry
+        * 
+        * @return the high address
+        */
+       IAddress getHighAddress();
+
+       /**
+        * Set the high link address of the line entry
+        */
+       void setHighAddress(IAddress highAddress);
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ILineEntryProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ILineEntryProvider.java
new file mode 100644 (file)
index 0000000..6df888d
--- /dev/null
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Provides line table lookup support.
+ */
+public interface ILineEntryProvider {
+
+       /**
+        * A source line and address(es) mapped to it. The address here may be
+        * runtime address or link address, depending on context in which the
+        * objects are used.
+        * 
+        * @since 2.0
+        */
+       public interface ILineAddresses {
+               public int getLineNumber();             // line number
+               public IAddress[] getAddress(); // addresses mapped to the line 
+       }
+
+       /**
+        * Get the line table entry for the given link address
+        * 
+        * @param linkAddress
+        *            the link address
+        * @return the line table entry, or null if none found
+        */
+       ILineEntry getLineEntryAtAddress(IAddress linkAddress);
+
+       /**
+        * Get the list of line table entries for the given sequence of line
+        * numbers. startLineNumber and endLineNumber can be the same if you're only
+        * interested in one source line. 
+        * <p>
+        * Note that there can be multiple line entries for a single source line,
+        * due to multiple statements per line, template expansion, static functions
+        * in headers, etc. 
+        * 
+        * @param file
+        *            the file to examine (source or header); as a full path.
+        * @param startLineNumber
+        *            the first line number
+        * @param endLineNumber
+        *            the last line number. if -1, the line entries for the
+        *            remainder of the file will be returned
+        * @return unmodifiable list of line entries, which may be empty
+        */
+       Collection<ILineEntry> getLineEntriesForLines(IPath file, int startLineNumber, int endLineNumber);
+
+       /**
+        * Gets the next line table entry in the same scope by line number that also
+        * has a higher address (useful for source level stepping)
+        * 
+        * @param entry
+        *            the current entry
+        * @param collapseInlineFunctions
+        *                        treat inline code as though it were a function to be stepped over
+        * @return the next entry, or null if none
+        * @since 2.0
+        */
+       ILineEntry getNextLineEntry(ILineEntry entry, boolean collapseInlineFunctions);
+
+       /**
+        * Gets the previous line table entry in the same scope by line number that also
+        * has a lower address (useful for source level stepping)
+        * 
+        * @param entry
+        *            the current entry
+        * @param collapseInlineFunctions
+        *                        treat inline code as though it were a function to be stepped over
+        * @return the next entry, or null if none
+        * @since 2.0
+        */
+       ILineEntry getPreviousLineEntry(ILineEntry entry, boolean collapseInlineFunctions);
+
+       /**
+        * Gets the line entry for the given link address within a given function.
+        * (Useful for inline stepping and stack-crawl function name determination.)
+        * 
+        * @param linkAddress
+        * @param parentFunction
+        * @return
+        * @since 2.0
+        */
+       public ILineEntry getLineEntryInFunction(IAddress linkAddress, IFunctionScope parentFunction);
+
+       /**
+        * Given a source line (let's call it anchor), find the line(s) closest to
+        * the anchor in the neighborhood (including the anchor itself) that has
+        * machine code. <br>
+        * <br>
+        * The search is done in the context of this line provider which is usually
+        * a compile unit (CU) or a module (one executable file).<br>
+        * <br>
+        * In the context of a CU, only one code line will be returned. If the
+        * closest line above the anchor and the closest line below the anchor have
+        * the same distance from the anchor, the one below will be selected.<br>
+        * <br>
+        * In the context of a module, more than one code lines may be found. For
+        * instance, one source line of an inline function in a header may have code
+        * in one CU but not in another where a neighboring code line may be found.
+        * 
+        * @param sourceFile
+        *            the file that contains the source lines in question.
+        * @param anchorLine
+        *            line number of the anchor source line.
+        * @param neighborLimit
+        *            specify the limit of the neighborhood: up to this number of
+        *            lines above the anchor and up to this number of lines below
+        *            the anchor will be checked if needed. But the check will never
+        *            go beyond the source file. When the limit is zero, no neighbor
+        *            lines will be checked. If the limit has value of -1, it means
+        *            the actual limit is the source file.
+        * 
+        * @return List of {@link ILineAddresses} objects containing link addresses.
+        *         Empty list if no code line is found.
+        * 
+        * @since 2.0
+        */
+       List<ILineAddresses> findClosestLineWithCode(IPath sourceFile, int anchorLine,
+                       int neighborLimit);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ILocationProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ILocationProvider.java
new file mode 100644 (file)
index 0000000..b978291
--- /dev/null
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+
+/**
+ * Interface to interpret the location of a variable at runtime.
+ */
+public interface ILocationProvider {
+
+       /**
+        * Get the location of the variable for the given execution address
+        * 
+        * @param tracker
+        *            DSF services tracker to obtain needed services (registers,
+        *            memory, etc)
+        * @param stack
+        *            frame context to use for register based operations
+        * @param forLinkAddress
+        *            the link-time address for use if the variable can live at
+        *            different location depending on the execution context
+        * @param isNonLocalConstVariable
+        *            whether variable is a global or static (non-local) constant 
+        * @return the variable location
+        * @since 2.0
+        */
+       IVariableLocation getLocation(EDCServicesTracker tracker, IFrameDMContext context,
+                                                                       IAddress forLinkAddress, boolean isNonLocalConstVariable);
+
+       /**
+        * Tell if the variable has a known location at this address.
+        * @param forLinkAddress
+        *            the link-time address for use if the variable 
+        * @return true if a location is known for the variable at this address, or false if not.
+        * Note: if a variable has a static address, always return true. 
+        */
+       boolean isLocationKnown(IAddress forLinkAddress);
+
+       /**
+        * Tell if the variable's lifetime must be the same as its enclosing scope.
+        * @return true if a lifetime range must match its enclosing scope's, or false if not.
+        * Note: If a variable has a static address, always return true.
+        * @since 2.0
+        */
+       boolean lifetimeMustMatchScope();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IMemoryVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IMemoryVariableLocation.java
new file mode 100644 (file)
index 0000000..fee00fa
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+/**
+ * Interface representing a variable value located in memory.
+ */
+public interface IMemoryVariableLocation extends IVariableLocation {
+       /**
+        * Is this address a runtime address or a link address?
+        * @return true if runtime address, false if link address
+        */
+       boolean isRuntimeAddress();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IModuleLineEntryProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IModuleLineEntryProvider.java
new file mode 100644 (file)
index 0000000..dabf3c7
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Added functionality for finding line information across a module.
+ */
+public interface IModuleLineEntryProvider extends ILineEntryProvider {
+       /**
+        * Get the line entry providers for the given source file.  
+        * @path sourceFile the absolute path to the source file
+        * @return the unmodifiable list of providers for the file, possibly empty.
+        */
+       Collection<ILineEntryProvider> getLineEntryProvidersForFile(IPath sourceFile);
+
+       /**
+        * Check if the module uses the given source file.<br>
+        * Note that line table has more complete list of files (esp. headers) used
+        * in a compile unit than debug_info section of Dwarf.
+        * 
+        * @since 2.0
+        */
+       boolean hasSourceFile(IPath sourceFile);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IModuleScope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IModuleScope.java
new file mode 100644 (file)
index 0000000..3495a82
--- /dev/null
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.services.IFrameRegisterProvider;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Interface representing a module scope. A module is a symbol file which
+ * contains compile units.
+ */
+public interface IModuleScope extends IScope {
+
+       /**
+        * Get the module described
+        */
+       IPath getSymbolFile();
+       
+       /**
+        * Get the compile unit at the given link address
+        * 
+        * @param address
+        *            the link address
+        * @return the compile unit at the address, or null if none
+        */
+       ICompileUnitScope getCompileUnitForAddress(IAddress linkAddress);
+
+       /**
+        * Get the compile unit(s) for the given file
+        * 
+        * @param filePath
+        *            the file path as defined in the symbolics
+        * @return the compile unit for this file, possibly empty
+        */
+       List<ICompileUnitScope> getCompileUnitsForFile(IPath filePath);
+       
+       /**
+        * Get all functions with the given name in any scope in the module
+        * 
+        * @param name
+        *            the function name, or <code>null</code> for all functions
+        * @return unmodifiable list of functions, which may be empty
+        */
+       Collection<IFunctionScope> getFunctionsByName(String name);
+
+       /**
+        * Get all variables with the given name in any scope in the module
+        * 
+        * @param name
+        *            the variable name, or <code>null</code> to get all variables
+        * @param globalsOnly
+        *            whether to assume local variables in scope have been recorded
+     *            and only globally-visible variables remain to be found
+        * @return unmodifiable list of variables, which may be empty
+        */
+       Collection<IVariable> getVariablesByName(String name, boolean globalsOnly);
+
+       
+       /**
+        * Get all the types declared in the module.
+        * <p>
+        * This does not load types on demand; each IType instance may be a proxy for a
+        * type loaded once methods are called on it.  Thus, do not use "instanceof" to
+        * check the type.
+        * @return unmodifiable list of types, which may be empty.
+        */
+       Collection<IType> getTypes();
+       
+       /**
+        * Get the line entry provider for the module.  This aggregates the
+        * information for any source or header file referenced in the module.
+        * @return {@link IModuleLineEntryProvider}, never <code>null</code> 
+        */
+       IModuleLineEntryProvider getModuleLineEntryProvider();
+       
+       /**
+        * Get a provider that allows access to registers stored in other stack frames.
+        * @return {@link IFrameRegisterProvider} or <code>null</code>
+        */
+       IFrameRegisterProvider getFrameRegisterProvider();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IRangeList.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IRangeList.java
new file mode 100644 (file)
index 0000000..ca92dd1
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.util.Iterator;
+
+/**
+ * This describes a range of non-contiguous addresses. 
+ * 
+ * Note: this uses long instead of IAddress for efficiency.
+ */
+public interface IRangeList extends Iterable<IRangeList.Entry> {
+
+       static class Entry implements Comparable<Entry> {
+               public Entry(long low, long high) {
+                       this.low = low;
+                       this.high = high;
+               }
+
+               final public long low, high;
+               
+               @Override
+               public String toString() {
+                       return "[" + Long.toHexString(low) + "-" + Long.toHexString(high) + ")";
+               }
+               /* (non-Javadoc)
+                * @see java.lang.Comparable#compareTo(java.lang.Object)
+                */
+               public int compareTo(Entry o) {
+                       if (low < o.low)
+                               return -1;
+                       if (low > o.low && high >= o.high)
+                               return 1;
+                       if (low == o.low && high > o.high)
+                               return 1;
+                       return 0;
+               }
+               /* (non-Javadoc)
+                * @see java.lang.Object#hashCode()
+                */
+               @Override
+               public int hashCode() {
+                       final int prime = 31;
+                       int result = 1;
+                       result = prime * result + (int) (high ^ (high >>> 32));
+                       result = prime * result + (int) (low ^ (low >>> 32));
+                       return result;
+               }
+               /* (non-Javadoc)
+                * @see java.lang.Object#equals(java.lang.Object)
+                */
+               @Override
+               public boolean equals(Object obj) {
+                       if (this == obj)
+                               return true;
+                       if (obj == null)
+                               return false;
+                       if (getClass() != obj.getClass())
+                               return false;
+                       Entry other = (Entry) obj;
+                       if (high != other.high)
+                               return false;
+                       if (low != other.low)
+                               return false;
+                       return true;
+               }
+
+               
+       }
+       
+       /** Get absolute low address for the range */
+       long getLowAddress();
+       /** Get absolute high address for the range */
+       long getHighAddress();
+       
+       /** Iterate over every portion of the range */
+       Iterator<IRangeList.Entry> iterator();
+       
+       /**
+        * Tell if an address is in the range.
+        * @param addr
+        */
+       boolean isInRange(long addr);
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IRegisterOffsetVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IRegisterOffsetVariableLocation.java
new file mode 100644 (file)
index 0000000..9ff707c
--- /dev/null
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+
+/**
+ * Interface representing a variable value located at an address specified
+ * as [register + offset].
+ * <p>
+ * This may refer to a register that is saved inside a caller's stack frame
+ * and not necessarily to a current living register.
+ */
+public interface IRegisterOffsetVariableLocation extends IRegisterVariableLocation {
+       /**
+        * Get the offset from the register containing the variable value
+        * 
+        * @return the offset in bytes
+        */
+       long getOffset();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IRegisterVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IRegisterVariableLocation.java
new file mode 100644 (file)
index 0000000..b95da6f
--- /dev/null
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+
+/**
+ * Interface representing a variable value located in a register.
+ * <p>
+ * This may refer to a register that is saved inside a caller's stack frame
+ * and not necessarily to a current living register.
+ */
+public interface IRegisterVariableLocation extends IVariableLocation {
+
+       /**
+        * Get the name of the register containing the variable value
+        * 
+        * @return the register name if known, null otherwise
+        */
+       String getRegisterName();
+
+       /**
+        * Get the id of the register containing the variable value
+        * 
+        * @return the register id if known, -1 otherwise
+        */
+       int getRegisterID();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IScope.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IScope.java
new file mode 100644 (file)
index 0000000..210e2ed
--- /dev/null
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.util.Collection;
+
+import org.eclipse.cdt.core.IAddress;
+
+/**
+ * Generic symbolic scope interface.
+ */
+public interface IScope extends Comparable<Object> {
+
+       /**
+        * Get the name of the scope
+        * 
+        * @return the name
+        */
+       String getName();
+
+       /**
+        * Tell whether the scope has an empty address range (either unset or unspecified)
+        */
+       boolean hasEmptyRange();
+
+       /**
+        * Get the low link address of this scope (absolute or synthesized from a range list)
+        * 
+        * @return low address, or null if unknown
+        */
+       IAddress getLowAddress();
+
+       /**
+        * Get the high link address of this scope (absolute or synthesized from a range list)
+        * 
+        * @return high address, or null if unknown
+        */
+       IAddress getHighAddress();
+
+       /**
+        * Get the list of non-consecutive ranges for the scope.
+        * @return list or <code>null</code> if the low and high addresses specify a contiguous range
+        */
+       IRangeList getRangeList();
+       
+       /**
+        * Get the parent of this scope
+        * 
+        * @return the parent scope, or null if the highest level scope
+        */
+       IScope getParent();
+
+       /**
+        * Gets the list of child scopes (if any)
+        * 
+        * @return unmodifiable list of child scopes which may be empty
+        */
+       Collection<IScope> getChildren();
+
+       /**
+        * Gets the list of variables in this scope only 
+        * 
+        * @return unmodifiable list of variables which may be empty
+        */
+       Collection<IVariable> getVariables();
+
+       /**
+        * Gets the list of enumerators in this scope (if any)
+        * 
+        * @return unmodifiable list of enumerators which may be empty
+        */
+       Collection<IEnumerator> getEnumerators();
+
+       /**
+        * Find the smallest scope at the given link address
+        * 
+        * @param address
+        *            the link address
+        * @return the smallest scope containing the given address, or null if none
+        *         found
+        */
+       IScope getScopeAtAddress(IAddress linkAddress);
+
+       /**
+        * 
+        */
+       void dispose();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ISymbol.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ISymbol.java
new file mode 100644 (file)
index 0000000..5a148e9
--- /dev/null
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import org.eclipse.cdt.core.IAddress;
+
+/**
+ * Interface representing a symbol from the symbol table
+ */
+public interface ISymbol extends Comparable<Object> {
+
+       /**
+        * Get the symbol name
+        * 
+        * @return the symbol name
+        */
+       String getName();
+
+       /**
+        * Get the address of the symbol
+        * 
+        * @return the symbol address
+        */
+       IAddress getAddress();
+
+       /**
+        * Get the size of the symbol
+        * 
+        * @return the symbol size
+        */
+       long getSize();
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ISymbolReaderFactory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/ISymbolReaderFactory.java
new file mode 100644 (file)
index 0000000..7252921
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.io.IOException;
+
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * This interface detects a specific executable format and yields a symbol
+ * reader for it.
+ */
+public interface ISymbolReaderFactory {
+       /**
+        * Create a symbol reader for the given executable.  The symbols do
+        * not have to live in the provided executable, but may be in associated files (e.g. exeFile + .sym).
+        * @param exeFile start point for searching
+        * @return a symbol reader, or <code>null</code> if not compatible
+        * @throws IOException if the reader fails to handle the file after detecting its type
+        */
+       IEDCSymbolReader createSymbolReader(IPath exeFile) throws IOException;
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IType.java
new file mode 100644 (file)
index 0000000..f9660c7
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.util.Map;
+
+
+/**
+ * Interface for types.
+ * 
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IType {
+
+       /**
+        * Get type name
+        * 
+        * @return type name
+        */
+       public String getName();
+
+       /**
+        * Get type scope
+        * 
+        * @return scope
+        */
+       public IScope getScope();
+
+       /**
+        * Get size of data type in bytes
+        * 
+        * @return size in bytes of the effective type (e.g. skipping qualifiers, typedefs, etc.)
+        */
+       public int getByteSize();
+
+       /**
+        * Get properties
+        * 
+        * @return general map of type properties
+        */
+       public Map<Object, Object> getProperties();
+
+       /**
+        * Get type pointed to, accessed, qualified, etc. by this type
+        */
+       public IType getType();
+
+       /**
+        * Set type pointed to, accessed, qualified, etc. by this type
+        * 
+        * @param type
+        *           type pointed to, accessed, qualified, etc.
+        */
+       public void setType(IType type);
+
+       public void dispose();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IUnmangler.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IUnmangler.java
new file mode 100644 (file)
index 0000000..32fe8dd
--- /dev/null
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.files.UnmanglingException;
+
+/**
+ * This interface supports unmangling symbols from executables
+ * or debug information into the high-level language format.
+ */
+public interface IUnmangler {
+       /**
+        * Undecorate a symbol which may have architecture or OS specific prefixes
+        * or suffixes independent of the actual mangling scheme underneath.
+        * @param symbol
+        * @return undecorated variant, possibly same as symbol
+        */
+       String undecorate(String symbol);
+       
+       /**
+        * Tell if a symbol looks mangled
+        * @param symbol undecorated symbol
+        * @return true if it might be mangled, false if the symbol mangling is not recognized
+        * (or, it is the same as an extern "C" name)
+        */
+       boolean isMangled(String symbol);
+       
+       /**
+        * Unmangle the symbol
+        * @param symbol undecorated symbol
+        * @return unmangled symbol 
+        * @throws UnmanglingException if symbol cannot be mangled 
+        */
+       String unmangle(String symbol) throws UnmanglingException;
+
+       /**
+        * Unmangle the symbol without args
+        * @param symbol
+        * @return the function name without args
+        * @throws UnmanglingException
+        * @since 2.0
+        */
+       String unmangleWithoutArgs(String symbol) throws UnmanglingException;
+
+
+       /**
+        * Unmangle a type, which may start at a different point in the BNF tree
+        * @param symbol
+        * @return the unmangled type name
+        * @throws UnmanglingException
+        * @since 2.0
+        */
+       String unmangleType(String symbol) throws UnmanglingException;
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IValueVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IValueVariableLocation.java
new file mode 100644 (file)
index 0000000..6c2cada
--- /dev/null
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.symbols;
+
+/**
+ * This represents a synthetic location where the value is stored directly.  
+ */
+public interface IValueVariableLocation extends IVariableLocation {
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IVariable.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IVariable.java
new file mode 100644 (file)
index 0000000..0741195
--- /dev/null
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.ILexicalBlockScope;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Interface representing a variable or parameter.
+ */
+public interface IVariable {
+
+       /**
+        * Get the name of the variable
+        * 
+        * @return the variable name
+        */
+       String getName();
+
+       /**
+        * Get the scope that the variable belongs to
+        * 
+        * @return the variable scope
+        */
+       IScope getScope();
+
+       /**
+        * Get the type of the variable
+        * 
+        * @return the variable type
+        */
+       IType getType();
+
+       /**
+        * Get the location provider for the variable
+        * 
+        * @return the location provider
+        */
+       ILocationProvider getLocationProvider();
+
+       /**
+        * A variable's lifetime may start somewhere inside its parent scope (without being
+        * inside an {@link ILexicalBlockScope}).  This provides the offset from the
+        * start address of the parent scope at which time the variable is considered
+        * live.
+        * <p>
+        * This scope may be narrower than the scope implied by {@link ILocationProvider#isLocationKnown(org.eclipse.cdt.core.IAddress)}.
+        * <p>
+        * Note: a variable is always considered to be live until the end of the parent scope.
+        * @return offset in bytes (0 means the lifetime is the same as the parent scope)
+        */
+       long getStartScope();
+       
+       /**
+        * Whether a variable was explicitly declared in the source, rather than generated
+        * by a tool such as a compiler
+        *  
+        * @return whether the variable was explicitly declared 
+        * @since 2.0
+        */
+       boolean isDeclared();
+       
+       /**
+        * Get the path of the file in which this variable is defined
+        *  
+        * @return file in which this variable is defined, or null if unknown
+        * @since 2.0
+        */
+       IPath getDefiningFile();
+
+       /**
+        * 
+        */
+       void dispose();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IVariableLocation.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IVariableLocation.java
new file mode 100644 (file)
index 0000000..8ea0b6e
--- /dev/null
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Interface representing a variable value location.
+ */
+public interface IVariableLocation {
+
+       /**
+        * Read the item's value
+        * @param bytes number of bytes to fetch 
+        * @return value, never <code>null</code>
+        * @throws CoreException on error
+        */
+       BigInteger readValue(int bytes) throws CoreException;
+       
+       
+       /**
+        * Writes the item's value
+        * @param bytes <code>int</code> number of bytes to write
+        * @param value <code>BigInteger</code>
+        * @throws CoreException
+        */
+       void writeValue(int bytes, BigInteger value) throws CoreException;
+
+       /**
+        * Create another location at the given offset from this location.
+        * @param offset
+        * @return {@link IVariableLocation}
+        */
+       IVariableLocation addOffset(long offset);
+
+       /**
+        * Get the name for the location, to show in the UI
+        * @return name
+        */
+       String getLocationName();
+       
+       /**
+        * Get the address of the location, if the location has an address.
+        * @return address or <code>null</code>
+        */
+       IAddress getAddress();
+       
+       /**
+        * Get the context for the location, if the location has a context
+        * @return context or <code>null</code>
+        * @since 2.0
+        */
+       public IDMContext getContext();
+
+       /**
+        * Get the services tracker for the location, if the location has a services tracker
+        * @return services tracker or <code>null</code>
+        * @since 2.0
+        */
+       public EDCServicesTracker getServicesTracker();
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/SymbolsMessages.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/SymbolsMessages.java
new file mode 100644 (file)
index 0000000..f0c15d8
--- /dev/null
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import org.eclipse.osgi.util.NLS;
+
+public class SymbolsMessages extends NLS {
+       private static final String BUNDLE_NAME = "org.eclipse.cdt.debug.edc.symbols.SymbolsMessages"; //$NON-NLS-1$
+
+       public static String TypeEngine_CannotResolveBaseType;
+       public static String TypeEngine_CannotResolveType;
+       public static String TypeEngine_ExpectedIntegerConstant;
+       public static String TypeEngine_NoDecltypeSupport;
+       public static String TypeEngine_NoTypeToCast;
+       public static String TypeEngine_UnhandledType;
+
+       static {
+               // initialize resource bundle
+               NLS.initializeMessages(BUNDLE_NAME, SymbolsMessages.class);
+       }
+
+       private SymbolsMessages() {
+       }
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/SymbolsMessages.properties b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/SymbolsMessages.properties
new file mode 100644 (file)
index 0000000..8c348f4
--- /dev/null
@@ -0,0 +1,16 @@
+###############################################################################
+# Copyright (c) 2010 Nokia and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Nokia - Initial API and implementation
+###############################################################################
+TypeEngine_CannotResolveBaseType=cannot resolve base type of 
+TypeEngine_CannotResolveType=cannot resolve type 
+TypeEngine_ExpectedIntegerConstant=expected an integer constant, got 
+TypeEngine_NoDecltypeSupport=decltype() not implemented
+TypeEngine_NoTypeToCast=no type to cast
+TypeEngine_UnhandledType=unhandled type: 
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/TypeEngine.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/TypeEngine.java
new file mode 100644 (file)
index 0000000..659b87e
--- /dev/null
@@ -0,0 +1,554 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.core.dom.ast.ASTSignatureUtil;
+import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
+import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTExpression;
+import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
+import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
+import org.eclipse.cdt.core.dom.ast.IASTProblemTypeId;
+import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTTypeId;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTArrayDeclarator;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
+import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.PushLongOrBigInteger;
+import org.eclipse.cdt.debug.edc.internal.symbols.ArrayBoundType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.CPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayBoundType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICompositeType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.PointerType;
+import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * This class manages the {@link IType} instances relevant to a given target.
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+@SuppressWarnings("deprecation")
+public class TypeEngine {
+       private Map<Integer, Integer> typeSizeMap;
+       private Map<Object, IType> typeMap = new HashMap<Object, IType>();
+       private int addressSize;
+       private Map<IType, String> typeNameMap = new HashMap<IType, String>();
+       private final IDebugInfoProvider debugInfoProvider;
+       /** map of type signature to IType or CoreException */
+       private Map<String, Object> typeIdToTypeMap = new HashMap<String, Object>();
+       private Map<String, IArrayType> typeToArrayTypeMap = new HashMap<String, IArrayType>();
+       private boolean charIsSigned;
+
+       /**
+        * @since 2.0
+        */
+       public TypeEngine(ITargetEnvironment targetEnvironment, IDebugInfoProvider debugInfoProvider) {
+               this.debugInfoProvider = debugInfoProvider;
+               if (targetEnvironment != null) {
+                       typeSizeMap = targetEnvironment.getBasicTypeSizes();
+                       addressSize = targetEnvironment.getPointerSize();
+                       charIsSigned = targetEnvironment.isCharSigned();
+               } else {
+                       typeSizeMap = Collections.emptyMap();
+                       addressSize = 4;
+                       charIsSigned = true;
+               }
+       }
+               
+       /**
+        * Get the target's basic type for an integer of the given size 
+        * @param size
+        * @param isSigned
+        * @return type or <code>null</code> if no match
+        */
+       public IType getIntegerTypeOfSize(int size, boolean isSigned) {
+               int basicType;
+               int flags;
+               
+               if (isSigned && typeSizeMap.get(TypeUtils.BASIC_TYPE_CHAR) == size) {
+                       basicType = ICPPBasicType.t_char;
+                       flags = ICPPBasicType.IS_SIGNED;
+               } else if (!isSigned && typeSizeMap.get(TypeUtils.BASIC_TYPE_CHAR) == size) {
+                       basicType = ICPPBasicType.t_char;
+                       flags = ICPPBasicType.IS_UNSIGNED;
+               } else if (isSigned && typeSizeMap.get(TypeUtils.BASIC_TYPE_SHORT) == size) {
+                       basicType = ICPPBasicType.t_int;
+                       flags = ICPPBasicType.IS_SHORT + ICPPBasicType.IS_SIGNED;
+               } else if (!isSigned && typeSizeMap.get(TypeUtils.BASIC_TYPE_SHORT) == size) {
+                       basicType = ICPPBasicType.t_int;
+                       flags = ICPPBasicType.IS_SHORT + ICPPBasicType.IS_UNSIGNED;
+               } else if (isSigned && typeSizeMap.get(TypeUtils.BASIC_TYPE_INT) == size) {
+                       basicType = ICPPBasicType.t_int;
+                       flags = ICPPBasicType.IS_SIGNED;
+               } else if (!isSigned && typeSizeMap.get(TypeUtils.BASIC_TYPE_INT) == size) {
+                       basicType = ICPPBasicType.t_int;
+                       flags = ICPPBasicType.IS_UNSIGNED;
+               } else if (isSigned && typeSizeMap.get(TypeUtils.BASIC_TYPE_LONG) == size) {
+                       basicType = ICPPBasicType.t_int;
+                       flags = ICPPBasicType.IS_LONG + ICPPBasicType.IS_SIGNED;
+               } else if (!isSigned && typeSizeMap.get(TypeUtils.BASIC_TYPE_LONG) == size) {
+                       basicType = ICPPBasicType.t_int;
+                       flags = ICPPBasicType.IS_LONG + ICPPBasicType.IS_UNSIGNED;
+               } else if (isSigned && typeSizeMap.get(TypeUtils.BASIC_TYPE_LONG_LONG) == size) {
+                       basicType = ICPPBasicType.t_int;
+                       flags = ICPPBasicType.IS_LONG_LONG + ICPPBasicType.IS_SIGNED;
+               } else if (!isSigned && typeSizeMap.get(TypeUtils.BASIC_TYPE_LONG_LONG) == size) {
+                       basicType = ICPPBasicType.t_int;
+                       flags = ICPPBasicType.IS_LONG_LONG + ICPPBasicType.IS_UNSIGNED;
+               } else {
+                       return null;
+               }
+               
+               return getBasicType(basicType, flags, size);
+       }
+
+       /**
+        * Get the target's basic type for an integer of the given kind
+        * @param typeUtilsType from TypeUtils#BASIC_TYPE
+        * @param isSigned
+        * @return type or <code>null</code> if no match
+        */
+       public IType getIntegerTypeFor(int typeUtilsBasicType, boolean isSigned) {
+               return getIntegerTypeOfSize(typeSizeMap.get(typeUtilsBasicType), isSigned);
+       }
+       
+       /**
+        * Get a cached ICPPBasicType instance
+        * @param basicType
+        * @param flags
+        * @param size
+        * @return IType
+        */
+       public IType getBasicType(int basicType, int flags, int size) {
+               return getBasicType(null, basicType, flags, size);
+       }
+
+       /**
+        * Get a cached ICPPBasicType instance, using a custom name.
+        * @param name
+        * @param basicType
+        * @param flags
+        * @param size
+        * @return IType
+        */
+       public IType getBasicType(String name, int basicType, int flags, int size) {
+               Object typeCode = (flags << 16) + (basicType << 8) + size;
+               if (name != null)
+                       typeCode = name + ":" + typeCode; //$NON-NLS-1$
+               IType type = typeMap.get(typeCode);
+               if (type == null) {
+                       if (name == null)
+                               name = getBasicTypeName(basicType, flags);
+                       type = new CPPBasicType(name, basicType, flags, size);
+                       typeMap.put(typeCode, type);
+               }
+               return type;
+       }
+
+       /**
+        * @param basicType
+        * @param flags
+        * @return
+        */
+       private String getBasicTypeName(int basicType, int flags) {
+               String name;
+               switch (basicType) {
+               case ICPPBasicType.t_bool:
+                       name = "bool"; break; //$NON-NLS-1$
+               case ICPPBasicType.t_wchar_t:
+                       name = "wchar_t"; break; //$NON-NLS-1$
+               case ICPPBasicType.t_char:
+                       name = "char"; break; //$NON-NLS-1$
+               case ICPPBasicType.t_int:
+                       if ((flags & ICPPBasicType.IS_SHORT) != 0)
+                               name = "short"; //$NON-NLS-1$
+                       else if ((flags & ICPPBasicType.IS_LONG) != 0)
+                               name = "long"; //$NON-NLS-1$
+                       else if ((flags & ICPPBasicType.IS_LONG_LONG) != 0)
+                               name = "long long"; //$NON-NLS-1$
+                       else
+                               name = "int";  //$NON-NLS-1$
+                       break;
+               case ICPPBasicType.t_float:
+                       name = "float"; break; //$NON-NLS-1$
+               case ICPPBasicType.t_double:
+                       if ((flags & ICPPBasicType.IS_LONG) != 0)
+                               name = "long double"; //$NON-NLS-1$
+                       else
+                               name = "double";  //$NON-NLS-1$
+                       break;
+               case ICPPBasicType.t_unspecified:
+                       name = "<<unknown>>"; //$NON-NLS-1$
+                       break;
+               case ICPPBasicType.t_void:
+                       name = "void"; //$NON-NLS-1$
+                       break;
+               default:
+                       assert(false);
+                       name = ""; //$NON-NLS-1$
+                       break;
+               }
+               
+               if ((flags & ICPPBasicType.IS_SIGNED) != 0)
+                       name = "signed " + name; //$NON-NLS-1$
+               else if ((flags & ICPPBasicType.IS_UNSIGNED) != 0)
+                       name = "unsigned " + name; //$NON-NLS-1$
+               if ((flags & ICPPBasicType.IS_COMPLEX) != 0)
+                       name = "complex " + name; //$NON-NLS-1$
+               if ((flags & ICPPBasicType.IS_IMAGINARY) != 0)
+                       name = "imaginary " + name; //$NON-NLS-1$
+               return name;
+       }
+
+       /**
+        * Get the target's basic type for a float of the given size 
+        * @param size
+        * @param isSigned
+        * @return type or <code>null</code> if no match
+        */
+       public IType getFloatTypeOfSize(int size) {
+               if (typeSizeMap.get(TypeUtils.BASIC_TYPE_FLOAT) == size) {
+                       return getBasicType(ICPPBasicType.t_float, 0, size);
+               }
+               if (typeSizeMap.get(TypeUtils.BASIC_TYPE_DOUBLE) == size) {
+                       return getBasicType(ICPPBasicType.t_double, 0, size);
+               }
+               if (typeSizeMap.get(TypeUtils.BASIC_TYPE_LONG_DOUBLE) == size) {
+                       return getBasicType(ICPPBasicType.t_double, ICPPBasicType.IS_LONG, size);
+               }
+               return null;
+       }
+
+       /**
+        * Get the basic type for a character of a given size.
+        * @param size
+        * @return IType
+        */
+       public IType getCharacterType(int size) {
+               if (typeSizeMap.get(TypeUtils.BASIC_TYPE_CHAR) == size) {
+                       return getBasicType(ICPPBasicType.t_char, 0, size);
+               }
+               return getBasicType(ICPPBasicType.t_wchar_t, 0, size);
+       }
+
+       /**
+        * Get the basic type for a character of a given size.
+        * @param size
+        * @return IType
+        */
+       public IType getWideCharacterType(int size) {
+               return getBasicType(ICPPBasicType.t_wchar_t, 0, size);
+       }
+
+       public IType getBooleanType(int size) {
+               return getBasicType(ICPPBasicType.t_bool, 0, size);
+       }
+
+       public IType getCharArrayType(IType charType, int length) {
+               IArrayBoundType bounds = new ArrayBoundType(null, length);
+               IArrayType array = new ArrayType(charType.getName() + "[" + length + "]", null, length, null); //$NON-NLS-1$ //$NON-NLS-2$
+               array.addBound(bounds);
+               array.setType(charType);
+               return array;
+       }
+
+       /**
+        * Get the integral type the same size as a pointer. 
+        * @return IType or <code>null</code>
+        */
+       public IType getPointerSizeType() {
+               int size = getPointerSize();
+               return getBasicType("ptrsize_t", ICPPBasicType.t_int, 0, size); //$NON-NLS-1$
+       }
+
+       private int getPointerSize() {
+               return addressSize;
+       }
+
+       /**
+        * Get the byte size of a type
+        * @param basicType (TypeUtils#BASIC_TYPE_xxx)
+        * @return type, or 0 if unknown
+        */
+       public int getTypeSize(int basicType) {
+               Integer size = typeSizeMap.get(basicType);
+               return size != null ? size.intValue() : 0;
+       }
+
+       /**
+        * @param valueType
+        * @return
+        */
+       public String getTypeName(IType valueType) {
+               if (valueType == null)
+                       return ""; //$NON-NLS-1$
+               
+               String typeName = typeNameMap.get(valueType);
+               if (typeName == null) {
+                       typeName = TypeUtils.getFullTypeName(valueType);
+                       typeNameMap.put(valueType, typeName);
+               }
+               return typeName;
+       }
+
+       /**
+        * Convert an AST type ID into an EDC IType.
+        * @param typeId
+        * @return IType
+        * @throws CoreException if the IType cannot be created
+        */
+       public IType getTypeForTypeId(IASTTypeId typeId) throws CoreException {
+               if (typeId == null)
+                       throw EDCDebugger.newCoreException(SymbolsMessages.TypeEngine_NoTypeToCast);
+
+               if (typeId instanceof IASTProblemTypeId)
+                       throw EDCDebugger.newCoreException(((IASTProblemTypeId) typeId).getProblem().getMessage());
+               
+               String typeSignature = ASTSignatureUtil.getSignature(typeId);
+
+               Object obj = typeIdToTypeMap.get(typeSignature);
+               if (obj instanceof CoreException)
+                       throw (CoreException) obj;
+               
+               obj = null; //HACK
+               IType type = null;
+               if (!(obj instanceof IType)) {
+                       try {
+                               type = createTypeForTypeId(typeId, typeSignature, type);
+                               typeIdToTypeMap.put(typeSignature, type);
+                       } catch (CoreException e) {
+                               typeIdToTypeMap.put(typeSignature, e);
+                               throw e;
+                       }
+               } else {
+                       type = (IType) obj;
+               }
+               
+               return type;
+       }
+
+       /**
+        * Create an IType mapping to IASTTypeId
+        * @param typeId
+        * @param typeSignature
+        * @param type
+        * @return new IType
+        * @throws CoreException
+        */
+       @SuppressWarnings("unused")
+       private IType createTypeForTypeId(IASTTypeId typeId, String typeSignature, IType type) throws CoreException {
+               IASTDeclSpecifier declSpec = typeId.getDeclSpecifier();
+               if (declSpec instanceof IASTSimpleDeclSpecifier) {
+                       type = getTypeForDeclSpecifier((IASTSimpleDeclSpecifier) declSpec);
+               } else if (declSpec instanceof IASTNamedTypeSpecifier || declSpec instanceof IASTElaboratedTypeSpecifier) {
+                       String typeName;
+                       
+                       int elaboration = -1;
+                       
+                       if (declSpec instanceof IASTNamedTypeSpecifier) {
+                               typeName = ((IASTNamedTypeSpecifier) declSpec).getName().toString();
+                       } else /*if (declSpec instanceof IASTElaboratedTypeSpecifier)*/ {
+                               // note: ignore the elaboration (class/struct/etc) since compilers are
+                               // inconsistent with how they do this, and furthermore, only one name
+                               // should be visible at a time, usually, anyway
+                               elaboration = ((IASTElaboratedTypeSpecifier) declSpec).getKind();
+                               typeName = ((IASTElaboratedTypeSpecifier) declSpec).getName().toString();
+                       }
+                       
+                       if (debugInfoProvider != null) {
+                               Collection<IType> types;
+                               IType aMatch = null;
+                               types = debugInfoProvider.getTypesByName(typeName);
+                               
+                               // try to find one matching struct/class/etc 
+                               for (IType aType : types) {
+                                       aMatch = aType;
+                                       if (elaboration < 0 ||
+                                                       (type instanceof ICompositeType && ((ICompositeType) type).getKey() == elaboration)) { 
+                                               type = aType;
+                                               break;
+                                       }
+                               }
+                               
+                               // if no match, just take a matching name
+                               if (type == null && aMatch != null) {
+                                       type = aMatch;
+                               }
+                               
+                               // fall through to check type != null 
+                       }
+               }
+               
+               if (type == null) {
+                       throw EDCDebugger.newCoreException(SymbolsMessages.TypeEngine_CannotResolveType + typeSignature);
+               }
+                       
+               if (typeId.getAbstractDeclarator() instanceof ICPPASTDeclarator) {
+                       ICPPASTDeclarator declarator = (ICPPASTDeclarator) typeId.getAbstractDeclarator();
+                       for (IASTPointerOperator pointer : declarator.getPointerOperators()) {
+                               IType ptr = new PointerType(type.getName()+"*", type.getScope(), getPointerSize(), null); //$NON-NLS-1$
+                               ptr.setType(type);
+                               type = ptr;
+                       }
+                       
+                       if (declarator instanceof ICPPASTArrayDeclarator) {
+                               ICPPASTArrayDeclarator arrayDeclarator = (ICPPASTArrayDeclarator) declarator;
+                               IArrayType arrayType = new ArrayType(type.getName()+"[]", type.getScope(), 0, null); //$NON-NLS-1$
+                               for (IASTArrayModifier arrayMod : arrayDeclarator.getArrayModifiers()) {
+                                       long elementCount = 1;
+                                       if (arrayMod.getConstantExpression() != null) {
+                                               elementCount = getConstantValue(arrayMod.getConstantExpression());
+                                       }
+                                       IArrayBoundType bound = new ArrayBoundType(arrayType.getScope(), elementCount);
+                                       arrayType.addBound(bound);
+                               }
+                               arrayType.setType(type);
+                               type = arrayType;
+                       }
+               }
+               return type;
+       }
+
+       private long getConstantValue(IASTExpression constantExpression) throws CoreException {
+               if (constantExpression instanceof IASTLiteralExpression) {
+                       if (((IASTLiteralExpression) constantExpression).getKind() == IASTLiteralExpression.lk_integer_constant) {
+                               // HACK, use more generic utilities
+                               PushLongOrBigInteger pusher = new PushLongOrBigInteger(constantExpression.toString());
+                               return pusher.getLong();
+                       }
+               }
+               throw EDCDebugger.newCoreException(SymbolsMessages.TypeEngine_ExpectedIntegerConstant + 
+                               ASTSignatureUtil.getExpressionString(constantExpression));
+       }
+
+       private IType getTypeForDeclSpecifier(IASTSimpleDeclSpecifier simpleDeclSpec) throws CoreException {
+               int baseType = 0;
+               int basicType = 0;
+               switch (simpleDeclSpec.getType()) {
+               case IASTSimpleDeclSpecifier.t_bool:
+                       baseType = ICPPBasicType.t_bool;
+                       basicType = TypeUtils.BASIC_TYPE_BOOL;
+                       break;
+               case IASTSimpleDeclSpecifier.t_char:
+                       baseType = ICPPBasicType.t_char; 
+                       basicType = TypeUtils.BASIC_TYPE_CHAR;
+                       break;
+               case IASTSimpleDeclSpecifier.t_wchar_t:
+                       baseType = ICPPBasicType.t_wchar_t; 
+                       basicType = TypeUtils.BASIC_TYPE_WCHAR_T;
+                       break;
+               case IASTSimpleDeclSpecifier.t_double:
+                       baseType = ICPPBasicType.t_double; 
+                       basicType = TypeUtils.BASIC_TYPE_DOUBLE;
+                       break;
+               case IASTSimpleDeclSpecifier.t_float:
+                       baseType = ICPPBasicType.t_float; 
+                       basicType = TypeUtils.BASIC_TYPE_FLOAT;
+                       break;
+               case IASTSimpleDeclSpecifier.t_int:
+                       baseType = ICPPBasicType.t_int;
+                       basicType = TypeUtils.BASIC_TYPE_INT;
+                       break;
+               case IASTSimpleDeclSpecifier.t_void:
+                       baseType = ICPPBasicType.t_void; 
+                       break;
+               case IASTSimpleDeclSpecifier.t_typeof:
+                       // we'd need to parse the subexpression then get its type
+               case IASTSimpleDeclSpecifier.t_decltype:
+                       // not sure about this one
+                       throw EDCDebugger.newCoreException(SymbolsMessages.TypeEngine_NoDecltypeSupport);       
+               case IASTSimpleDeclSpecifier.t_unspecified:
+                       baseType = ICPPBasicType.t_int;
+                       break;
+               default:
+                       throw EDCDebugger.newCoreException(SymbolsMessages.TypeEngine_UnhandledType + simpleDeclSpec);  
+               }
+               
+               int flags = 0;
+               if (simpleDeclSpec.isComplex()) flags |= ICPPBasicType.IS_COMPLEX;
+               if (simpleDeclSpec.isImaginary()) flags |= ICPPBasicType.IS_IMAGINARY;
+               if (simpleDeclSpec.isLong()) {
+                       flags |= ICPPBasicType.IS_LONG;
+                       if (basicType == 0)
+                               basicType = TypeUtils.BASIC_TYPE_LONG;
+               }
+               if (simpleDeclSpec.isLongLong()) {
+                       flags |= ICPPBasicType.IS_LONG_LONG;
+                       if (basicType == 0)
+                               basicType = TypeUtils.BASIC_TYPE_LONG_LONG;
+               }
+               if (simpleDeclSpec.isShort()) {
+                       flags |= ICPPBasicType.IS_SHORT;
+                       if (basicType == 0)
+                               basicType = TypeUtils.BASIC_TYPE_SHORT;
+               }
+               if (simpleDeclSpec.isUnsigned()) flags |= ICPPBasicType.IS_UNSIGNED;
+               if (simpleDeclSpec.isSigned()) flags |= ICPPBasicType.IS_SIGNED;
+               
+               if (!simpleDeclSpec.isUnsigned() && !simpleDeclSpec.isSigned()) {
+                       if (baseType == ICPPBasicType.t_char)
+                               flags |= charIsSigned ? ICPPBasicType.IS_SIGNED : ICPPBasicType.IS_UNSIGNED;
+                       else if (baseType == ICPPBasicType.t_int)
+                               flags |= ICPPBasicType.IS_SIGNED;
+               }
+               
+               int size = getTypeSize(basicType);
+               return getBasicType(baseType, flags, size); 
+       }
+       
+       /**
+        * Convert a given type to an array type
+        * @param exprType
+        * @return array type
+        * @throws CoreException if not a sensible conversion
+        */
+       public IType convertToArrayType(IType type, int count) throws CoreException {
+               String typeSig = getTypeName(type);
+               
+               IArrayType arrayType = typeToArrayTypeMap.get(typeSig);
+               if (arrayType == null) {
+                       type = TypeUtils.getStrippedType(type);
+                       
+                       IType baseType = type;
+                       
+                       if (type instanceof IPointerType || type instanceof IArrayType) {
+                               baseType = type.getType();
+                       }
+       
+                       if (baseType == null)
+                               throw EDCDebugger.newCoreException(SymbolsMessages.TypeEngine_CannotResolveBaseType + typeSig);
+                       
+                       arrayType = new ArrayType(baseType.getName()+"[]", baseType.getScope(),  //$NON-NLS-1$
+                                       baseType.getByteSize() * count, null);
+                       IArrayBoundType bound = new ArrayBoundType(arrayType.getScope(), count);
+                       arrayType.addBound(bound);
+                       arrayType.setType(baseType);
+                       
+                       typeToArrayTypeMap.put(typeSig, arrayType);
+               }
+               
+               return arrayType;
+       }
+
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/TypeUtils.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/TypeUtils.java
new file mode 100644 (file)
index 0000000..9241e81
--- /dev/null
@@ -0,0 +1,307 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions.IArrayDimensionType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IAggregate;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayBoundType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ICompositeType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IConstType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IForwardTypeReference;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IQualifierType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IReferenceType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ISubroutineType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ITypedef;
+
+
+/*
+ * Various utility routines for Type objects
+ */
+public class TypeUtils {
+
+       // type IDs for basic C and C++ types
+       static public final int BASIC_TYPE_CHAR                          = 1;
+       static public final int BASIC_TYPE_CHAR_UNSIGNED         = 2;
+       static public final int BASIC_TYPE_CHAR_SIGNED           = 3;
+       static public final int BASIC_TYPE_SHORT                         = 4;
+       static public final int BASIC_TYPE_SHORT_UNSIGNED        = 5;
+       static public final int BASIC_TYPE_INT                           = 6;
+       static public final int BASIC_TYPE_INT_UNSIGNED          = 7;
+       static public final int BASIC_TYPE_LONG                          = 8;
+       static public final int BASIC_TYPE_LONG_UNSIGNED         = 9;
+       static public final int BASIC_TYPE_LONG_LONG             = 10;
+       static public final int BASIC_TYPE_LONG_LONG_UNSIGNED = 11;
+       static public final int BASIC_TYPE_FLOAT                         = 12;
+       static public final int BASIC_TYPE_FLOAT_COMPLEX         = 13;
+       static public final int BASIC_TYPE_DOUBLE                        = 14;
+       static public final int BASIC_TYPE_DOUBLE_COMPLEX        = 15;
+       static public final int BASIC_TYPE_LONG_DOUBLE           = 16;
+       static public final int BASIC_TYPE_LONG_DOUBLE_COMPLEX = 17;
+       static public final int BASIC_TYPE_BOOL                          = 18;
+       static public final int BASIC_TYPE_BOOL_C9X                      = 19;
+       static public final int BASIC_TYPE_WCHAR_T                       = 20;
+       static public final int BASIC_TYPE_POINTER                       = 21; // not technically a basic type
+
+       // is a type a pointer "*" type?
+       public static boolean isPointerType(IType type) {
+               return getStrippedType(type) instanceof IPointerType;
+       }
+
+       // is a type a reference "&" type?
+       public static boolean isReferenceType(IType type) {
+               return getStrippedType(type) instanceof IReferenceType;
+       }
+
+       // is a type an aggregate (composite or array) type?
+       public static boolean isAggregateType(IType type) {
+               return getStrippedType(type) instanceof IAggregate;
+       }
+
+       // is a type a composite (class, struct, or union) type?
+       public static boolean isCompositeType(IType type) {
+               return getStrippedType(type) instanceof ICompositeType;
+       }
+
+       /**
+        * is a type a constant type?
+        * @since 2.0
+        */
+       public static boolean isConstType(IType type) {
+               if (type instanceof IForwardTypeReference)
+                       type = ((IForwardTypeReference) type).getReferencedType();
+
+               while (   type instanceof ITypedef || type instanceof IQualifierType || type instanceof IReferenceType
+                          || type instanceof IArrayType) {
+                       if (type instanceof IConstType)
+                               return true;
+
+                       type = type.getType();
+
+                       if (type instanceof IForwardTypeReference)
+                               type = ((IForwardTypeReference) type).getReferencedType();
+               }
+
+               return false;
+       }
+
+       // return the type with no typedefs, consts, or volatiles
+       public static IType getStrippedType(IType type) {
+               if (type instanceof IForwardTypeReference)
+                       type = ((IForwardTypeReference) type).getReferencedType();
+               
+               while (type instanceof ITypedef || type instanceof IQualifierType) {
+                       type = type.getType();
+                       
+                       if (type instanceof IForwardTypeReference)
+                               type = ((IForwardTypeReference) type).getReferencedType();
+               }
+
+               return type;
+       }
+
+       /**
+        * Return the type with no typedefs, consts, volatiles, or references
+        * @since 2.0
+        */
+       public static IType getUnRefStrippedType(IType type) {
+               if (type instanceof IForwardTypeReference)
+                       type = ((IForwardTypeReference) type).getReferencedType();
+               
+               while (type instanceof ITypedef || type instanceof IQualifierType || type instanceof IReferenceType) {
+                       type = type.getType();
+                       
+                       if (type instanceof IForwardTypeReference)
+                               type = ((IForwardTypeReference) type).getReferencedType();
+               }
+
+               return type;
+       }
+       
+       // return base type with no typedefs, consts, volatiles, or pointer types
+       // removing array types messes up formatters because they are assumed to act on the array
+       // but code creating expressions ignores the array syntax
+       // unlike with pointer types where -> is used instead of .
+       public static IType getBaseType(Object type) {
+               if (!(type instanceof IType))
+                       return null;
+
+               if (type instanceof IForwardTypeReference)
+                       type = ((IForwardTypeReference) type).getReferencedType();
+               
+               while (type instanceof ITypedef || type instanceof IQualifierType 
+                               || type instanceof IPointerType) {
+                       type = ((IType) type).getType();
+                       
+                       if (type instanceof IForwardTypeReference)
+                               type = ((IForwardTypeReference) type).getReferencedType();
+               }
+
+               return (IType) type;
+       }
+
+       // return base type with no consts, volatiles, pointer types, or array types - but preserving typedefs
+       public static IType getBaseTypePreservingTypedef(IType type) {
+               if (type instanceof IForwardTypeReference)
+                       type = ((IForwardTypeReference) type).getReferencedType();
+               
+               while (type instanceof IQualifierType 
+                               || type instanceof IPointerType || type instanceof IArrayType) {
+                       type = type.getType();
+                       
+                       if (type instanceof IForwardTypeReference)
+                               type = ((IForwardTypeReference) type).getReferencedType();
+               }
+               
+               return type;
+       }
+
+       // shift, mask, and extend an extracted bit-field
+       // NOTE: this may need to be endianness aware
+       public static Number extractBitField(Number value, int byteSize, int bitSize, int bitOffset, boolean isSignedInt) {
+               if (bitSize <= 0 || value == null
+                               || (!(value instanceof Long) && !(value instanceof Integer) && !(value instanceof BigInteger))) {
+                       return value;
+               }
+
+               // TODO: Need to get default type sizes from the ITargetEnvironment
+               // This assumes long and long long are 64 bits, and int is 32 bits
+               if (value instanceof Long) {
+                       long longValue = (Long) value;
+
+                       longValue >>= (byteSize * 8) - (bitOffset + bitSize);
+                       longValue &= (-1) >>> (64 - bitSize);
+
+                       if (isSignedInt) {
+                               if ((longValue & (1 << (bitSize - 1))) != 0) {
+                                       longValue |= ((-1) >>> bitSize) << bitSize;
+                               }
+                       }
+                       return new Long(longValue);
+               }
+
+               if (value instanceof Integer) {
+                       int intValue = (Integer) value;
+
+                       intValue >>= (byteSize * 8) - (bitOffset + bitSize);
+                       intValue &= ((-1) >>> (32 - bitSize));
+
+                       if (isSignedInt) {
+                               if ((intValue & (1 << (bitSize - 1))) != 0) {
+                                       intValue |= ((-1) >>> bitSize) << bitSize;
+                               }
+                       }
+                       return new Integer(intValue);
+               }
+
+               if (value instanceof BigInteger) {
+                       BigInteger bigValue = (BigInteger) value;
+                       bigValue = bigValue.shiftRight((byteSize * 8) - (bitOffset + bitSize));
+                       byte[] bytes = new byte[8];
+                       int mask;
+                       BigInteger bigMask;
+
+                       mask = ((-1) >>> (32 - bitSize));
+                       for (int i = 0; i < 8; i++) {
+                               bytes[i] = (byte) ((mask >>> ((7 - i) * 8)) & 0xff);
+                       }
+
+                       bigMask = new BigInteger(bytes);
+                       bigValue = bigValue.and(bigMask);
+
+                       if (isSignedInt) {
+                               // NOTE: for variable values, we use BigInteger ONLY for
+                               // unsigned numbers
+                               if (bigValue.testBit(bitSize - 1)) {
+                                       mask = (((-1) >>> bitSize) << bitSize);
+                                       for (int i = 0; i < 8; i++) {
+                                               bytes[i] = (byte) ((mask >>> ((7 - i) * 8)) & 0xff);
+                                       }
+
+                                       bigMask = new BigInteger(bytes);
+                                       bigValue = bigValue.or(bigMask);
+                               }
+                       }
+
+                       return bigValue;
+               }
+
+               return value;
+       }
+
+       /**
+        * Get the full name of a type.
+        * 
+        * {@link TypeEngine#getTypeName(IType)} caches the full name returned by this routine and associates it
+        * with the type passed in.
+        *
+        * @param type type whose full name is desired
+        * @return full name of the type, with all qualifiers, array bounds, etc.
+        * 
+        * @since 2.0
+        */
+       public static String getFullTypeName(IType type) {
+               if (type == null)
+                       return ""; //$NON-NLS-1$
+               if (type instanceof IReferenceType)
+                       return getFullTypeName(((IReferenceType) type).getType()) + " &"; //$NON-NLS-1$
+               if (type instanceof IPointerType) {
+                       IType pointedTo = ((IPointerType) type).getType();
+                       if (pointedTo instanceof ISubroutineType)
+                               // TODO: get parameters instead of saying "..."
+                               return "(*)(...)"; //$NON-NLS-1$
+                       else
+                               return getFullTypeName(pointedTo) + " *"; //$NON-NLS-1$
+               }
+               if (type instanceof IArrayType) {
+                       IArrayType arrayType = (IArrayType) type;
+
+                       IType subtype = null;
+                       String dimensions = "";
+                       do {
+                               for (IArrayBoundType bound : arrayType.getBounds())
+                                       dimensions += "[" + bound.getBoundCount() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+                               subtype = TypeUtils.getStrippedType(arrayType.getType());
+                               if (subtype instanceof IArrayType)
+                                       arrayType = (IArrayType)subtype;
+                       } while (subtype instanceof IArrayType);
+
+                       return getFullTypeName(arrayType.getType()) + dimensions;
+               }
+               if (type instanceof IArrayDimensionType) {
+                       IArrayDimensionType arrayDimensionType = (IArrayDimensionType) type;
+                       IArrayType arrayType = arrayDimensionType.getArrayType();
+                       String returnType = getFullTypeName(arrayType.getType());
+
+                       IArrayBoundType[] bounds = arrayType.getBounds();
+                       for (int i = arrayDimensionType.getDimensionCount(); i < arrayType.getBoundsCount(); i++) {
+                               returnType += "[" + bounds[i].getBoundCount() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+                       }
+                       return returnType;
+               }
+               if (type instanceof ITypedef)
+                       return ((ITypedef) type).getName();
+               if (type instanceof ICompositeType)
+                       return ((ICompositeType) type).getName();
+               if (type instanceof IQualifierType)
+                       return ((IQualifierType) type).getName()
+                                       + " " + getFullTypeName(((IQualifierType) type).getType()); //$NON-NLS-1$
+               if (type instanceof ISubroutineType) {
+                       // TODO: real stuff once we parse parameters
+                       return getFullTypeName(((ISubroutineType) type).getType());
+               }
+               return type.getName() + getFullTypeName(type.getType());
+       }
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/VariableLocationFactory.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/VariableLocationFactory.java
new file mode 100644 (file)
index 0000000..18767e2
--- /dev/null
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.edc.symbols;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.debug.edc.internal.symbols.InvalidVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.MemoryVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.RegisterVariableLocation;
+import org.eclipse.cdt.debug.edc.internal.symbols.ValueVariableLocation;
+import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+
+/**
+ * Create {@link IVariableLocation} instances
+ */
+public final class VariableLocationFactory {
+       protected VariableLocationFactory() { }
+       
+       /**
+        * @since 2.0
+        */
+       public static IMemoryVariableLocation createMemoryVariableLocation(EDCServicesTracker tracker, 
+                       IDMContext context, BigInteger addressValue, boolean isRuntimeAddress) {
+               return new MemoryVariableLocation(tracker, context, addressValue, isRuntimeAddress);
+       }
+       
+       /**
+        * @since 2.0
+        */
+       public static IMemoryVariableLocation createMemoryVariableLocation(EDCServicesTracker tracker, 
+                       IDMContext context, BigInteger addressValue) {
+               return new MemoryVariableLocation(tracker, context, addressValue, true);
+       }
+       /**
+        * @since 2.0
+        */
+       public static IMemoryVariableLocation createMemoryVariableLocation(EDCServicesTracker tracker, 
+                       IDMContext context, long addressValue) {
+               return new MemoryVariableLocation(tracker, context, BigInteger.valueOf(addressValue), true);
+       }
+       
+       /**
+        * @since 2.0
+        */
+       public static IMemoryVariableLocation createMemoryVariableLocation(
+                       EDCServicesTracker tracker, IDMContext context,
+                       Number addressValue) {
+               BigInteger addr;
+               if (addressValue instanceof BigInteger)
+                       addr = (BigInteger) addressValue;
+               else
+                       addr = BigInteger.valueOf(addressValue.longValue());
+               return new MemoryVariableLocation(tracker, context, addr, true);
+       }
+
+       /**
+        * @since 2.0
+        */
+       public static IRegisterVariableLocation createRegisterVariableLocation(
+                       EDCServicesTracker tracker,  IDMContext context, String name, int id) {
+               return new RegisterVariableLocation(tracker, context, name, id);
+       }
+       /**
+        * @since 2.0
+        */
+       public static IRegisterVariableLocation createRegisterVariableLocation(
+                       EDCServicesTracker tracker,  IDMContext context, int id) {
+               return new RegisterVariableLocation(tracker, context, null, id);
+       }
+       
+       public static IInvalidVariableLocation createInvalidVariableLocation(String message) {
+               return new InvalidVariableLocation(message);
+       }
+
+       public static IValueVariableLocation createValueVariableLocation(BigInteger value) {
+               return new ValueVariableLocation(value);
+       }
+
+}
index e954630..f5f4f89 100644 (file)
@@ -1,9 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
        <classpathentry exported="true" kind="lib" path="lib/org.eclipse.nebula.widgets.grid_1.0.0.jar"/>
-       <classpathentry exported="true" kind="lib" path="lib/org.eclipse.cdt.core_5.3.1.201109151620.jar"/>
-       <classpathentry exported="true" kind="lib" path="lib/org.eclipse.cdt.debug.edc_2.0.0.201109151658.jar"/>
-       <classpathentry exported="true" kind="lib" path="lib/org.eclipse.cdt.dsf_2.2.0.201109151620.jar"/>
        <classpathentry kind="lib" path="lib/hsqldb.jar"/>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
        <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
index e6882a8..7a6f057 100644 (file)
@@ -11,14 +11,13 @@ Require-Bundle: org.eclipse.ui,
  org.tizen.dynamicanalyzer.common;bundle-version="1.0.0",
  org.tizen.dynamicanalyzer.appearance;bundle-version="1.0.0",
  org.tizen.dynamicanalyzer.widgets;bundle-version="1.0.0",
- org.tizen.dynamicanalyzer.workbench;bundle-version="1.0.0"
+ org.tizen.dynamicanalyzer.workbench;bundle-version="1.0.0",
+ org.eclipse.cdt.debug.edc;bundle-version="1.0.0",
+ org.eclipse.cdt.core;bundle-version="5.3.2"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Bundle-Activator: org.tizen.dynamicanalyzer.common.AnalyzerPlugin
 Bundle-ActivationPolicy: lazy
 Bundle-ClassPath: .,
- lib/org.eclipse.cdt.core_5.3.1.201109151620.jar,
- lib/org.eclipse.cdt.debug.edc_2.0.0.201109151658.jar,
- lib/org.eclipse.cdt.dsf_2.2.0.201109151620.jar,
  lib/org.eclipse.nebula.widgets.grid_1.0.0.jar,
  lib/hsqldb.jar,
  lib/json-simple-1.1.1.jar,
diff --git a/org.tizen.dynamicanalyzer/lib/org.eclipse.cdt.core_5.3.1.201109151620.jar b/org.tizen.dynamicanalyzer/lib/org.eclipse.cdt.core_5.3.1.201109151620.jar
deleted file mode 100644 (file)
index 3748965..0000000
Binary files a/org.tizen.dynamicanalyzer/lib/org.eclipse.cdt.core_5.3.1.201109151620.jar and /dev/null differ
diff --git a/org.tizen.dynamicanalyzer/lib/org.eclipse.cdt.debug.edc_2.0.0.201109151658.jar b/org.tizen.dynamicanalyzer/lib/org.eclipse.cdt.debug.edc_2.0.0.201109151658.jar
deleted file mode 100644 (file)
index d2c0fc1..0000000
Binary files a/org.tizen.dynamicanalyzer/lib/org.eclipse.cdt.debug.edc_2.0.0.201109151658.jar and /dev/null differ