Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkryall2011-10-27 19:18:27 +0000
committerkryall2011-10-27 19:18:27 +0000
commit37db9ebe0d87216e819e31846177a6803d580675 (patch)
treefd8c61dd9c8fd43d4f5d29d63fea2326fdaa2397
parentfd67d64dd8c52d3c667c289b7c4f094d8ff1e39b (diff)
downloadorg.eclipse.cdt.edc-37db9ebe0d87216e819e31846177a6803d580675.tar.gz
org.eclipse.cdt.edc-37db9ebe0d87216e819e31846177a6803d580675.tar.xz
org.eclipse.cdt.edc-37db9ebe0d87216e819e31846177a6803d580675.zip
Add RTTI support. Expand support for watchpoints, beef up unit tests,
improve symbol loading when triggered by stack frames.
-rw-r--r--org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/DisassemblyViewARMBlackFlagRVCT.java135
-rw-r--r--org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ExpressionsCasting2.java164
-rw-r--r--org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ExpressionsServiceInternalsTest.java4
-rw-r--r--org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ModulesTest.java3
-rw-r--r--org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/OpaqueTypeResolving.java27
-rw-r--r--org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RegisterFrameTestsBlackFlag.java259
-rw-r--r--org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RegisterFrameTestsBlackFlagRVCT.java339
-rw-r--r--org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RunControlDMCSubclass.java123
-rw-r--r--org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/SimpleDebuggerTest.java7
-rw-r--r--org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/tests/TestDwarfReader.java5
-rw-r--r--org.eclipse.cdt.debug.edc.x86/src/org/eclipse/cdt/debug/edc/x86/X86Stack.java27
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/EvaluateID.java118
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/eval/ast/engine/instructions/FieldReference.java15
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/BreakpointAttributeTranslator.java230
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Breakpoints.java174
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/EDCServicesMessages.java4
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/EDCServicesMessages.properties4
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Expressions.java3052
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Modules.java2645
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/RunControl.java6188
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Symbols.java822
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/Album.java2665
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/Snapshot.java608
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CompositeType.java926
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ICompositeType.java269
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IPointerType.java38
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IReferenceType.java35
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IRuntimeType.java32
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/LineEntry.java166
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/MemoryVariableLocation.java444
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ModuleLineEntryProvider.java867
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/PointerType.java65
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/ReferenceType.java54
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Scope.java872
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/Variable.java374
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfCompileUnit.java673
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfDebugInfoProvider.java6
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfInfoReader.java58
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/files/ElfExecutableSymbolicsReader.java3
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/EDCServicesTracker.java481
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCModuleDMContext.java92
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Registers.java2478
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/Stack.java3392
-rw-r--r--org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IVariable.java175
44 files changed, 14961 insertions, 14157 deletions
diff --git a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/DisassemblyViewARMBlackFlagRVCT.java b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/DisassemblyViewARMBlackFlagRVCT.java
index 2fd655e..548080b 100644
--- a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/DisassemblyViewARMBlackFlagRVCT.java
+++ b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/DisassemblyViewARMBlackFlagRVCT.java
@@ -111,12 +111,23 @@ public class DisassemblyViewARMBlackFlagRVCT {
@Test
public void testARMDisassembly() throws Exception {
+ if (armAlbum == null) return;
+ if (armAlbum.launch == null) {
+ System.out.println("== testARMDisassemblyGetInstructionsBigInteger() reporting PASSED but will be skipped.");
+ return;
+ }
armAlbum.openSnapshotAndWaitForSuspendedContext(0);
Thread.sleep(2500); // wait a little to allow the view to populate and do work
}
@Test
public void testARMDisassemblyGetInstructionsBigInteger() throws Exception {
+ if (armAlbum == null) return;
+ if (armAlbum.launch == null) {
+ System.out.println("== testARMDisassemblyGetInstructionsBigInteger() reporting PASSED but will be skipped.");
+ return;
+ }
+
// Use a Query to synchronize the downstream calls
Query<IInstruction[]> query = new Query<IInstruction[]>() {
@Override
@@ -170,7 +181,12 @@ public class DisassemblyViewARMBlackFlagRVCT {
}
@Test
- public void testInternalTargetEnvironmentARM() throws Exception {
+ public void testInternalTargetEnvironmentARMevaluateLR() throws Exception {
+ if (armAlbum == null) return;
+ if (armAlbum.launch == null) {
+ System.out.println("== testInternalTargetEnvironmentARMevaluateLR() reporting PASSED but will be skipped.");
+ return;
+ }
armAlbum.openSnapshotAndWaitForSuspendedContext(4);
final TargetEnvironmentARM env
@@ -204,6 +220,11 @@ public class DisassemblyViewARMBlackFlagRVCT {
@Test
public void testInternalTargetEnvironmentARMgetBasicTypeSizes() throws Exception {
+ if (armAlbum == null) return;
+ if (armAlbum.launch == null) {
+ System.out.println("== testInternalTargetEnvironmentARMgetBasicTypeSizes() reporting PASSED but will be skipped.");
+ return;
+ }
armAlbum.openSnapshotAndWaitForSuspendedContext(4);
final TargetEnvironmentARM env
@@ -217,6 +238,11 @@ public class DisassemblyViewARMBlackFlagRVCT {
@Test
public void testInternalTargetEnvironmentARMgetBreapointInstruction() throws Exception {
+ if (armAlbum == null) return;
+ if (armAlbum.launch == null) {
+ System.out.println("== testInternalTargetEnvironmentARMgetBreapointInstruction() reporting PASSED but will be skipped.");
+ return;
+ }
armAlbum.openSnapshotAndWaitForSuspendedContext(4);
final TargetEnvironmentARM env
@@ -228,115 +254,50 @@ public class DisassemblyViewARMBlackFlagRVCT {
}
@Test
- public void testInternalTargetEnvironmentARMgetDisassembler() {
+ public void testInternalTargetEnvironmentARM() {
+ if (armAlbum == null) return;
+ if (armAlbum.launch == null) {
+ System.out.println("== testInternalTargetEnvironmentARM() reporting PASSED but will be skipped.");
+ return;
+ }
+ if (armDisasm == null) return;
TargetEnvironmentARM env
= (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
Assert.assertNotNull(env);
IDisassembler disassembler = env.getDisassembler();
Assert.assertTrue("instanceof check", disassembler instanceof DisassemblerARM);
- }
- @Test
- public void testInternalTargetEnvironmentARMgetEnumSize() {
- TargetEnvironmentARM env
- = (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
- Assert.assertNotNull(env);
-
- int enumSize = env.getEnumSize();
- Assert.assertEquals("Enum Size Test", 4, enumSize);
- }
-
- @Test
- public void testInternalTargetEnvironmentARMgetLongestInstructionLength() {
- TargetEnvironmentARM env
- = (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
- Assert.assertNotNull(env);
int longestInstLength = env.getLongestInstructionLength();
Assert.assertEquals("Longest Instruction Length Test", 4, longestInstLength);
- }
-
- @Test
- public void testInternalTargetEnvironmentARMgetMemoryCacheMinimumBlockSize() {
- TargetEnvironmentARM env
- = (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
- Assert.assertNotNull(env);
int memoryCacheMinimumBlockSize = env.getMemoryCacheMinimumBlockSize();
Assert.assertEquals("Memory Cache Minimum Block Size Test", 64, memoryCacheMinimumBlockSize);
- }
-
- @Test
- public void testInternalTargetEnvironmentARMgetOS() {
- TargetEnvironmentARM env
- = (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
- Assert.assertNotNull(env);
-
- String os = env.getOS();
- Assert.assertEquals("OS Test", ITargetEnvironment.OS_UNKNOWN, os);
- }
-
- @Test
- public void testInternalTargetEnvironmentARMgetPCRegisterID() {
- TargetEnvironmentARM env
- = (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
- Assert.assertNotNull(env);
-
- String pcRegID = env.getPCRegisterID();
- Assert.assertEquals("PC Register ID Test", "PC", pcRegID);
- }
- @Test
- public void testInternalTargetEnvironmentARMgetPointerSize() {
- TargetEnvironmentARM env
- = (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
- Assert.assertNotNull(env);
+ Assert.assertEquals("OS Test", ITargetEnvironment.OS_UNKNOWN, env.getOS());
+ Assert.assertEquals("PC Register ID Test", "PC", env.getPCRegisterID());
+ Assert.assertEquals("Pointer Size Test", 4, env.getPointerSize());
+ Assert.assertEquals("Enum Size Test", 4, env.getEnumSize());
+ Assert.assertFalse("Char Signed Test", env.isCharSigned());
+ Assert.assertTrue("Little Endian Test", env.isLittleEndian(disassemblyDMC));
- int pointerSize = env.getPointerSize();
- Assert.assertEquals("Pointer Size Test", 4, pointerSize);
+ boolean isThumbMode = env.isThumbMode(disassemblyDMC, new Addr32(0x788656e4), false);
+ Assert.assertTrue("Thumb Mode Test", isThumbMode);
}
@Test
public void coverageInternalTargetEnvironmentARMgetProperty() {
+ if (armAlbum == null) return;
+ if (armAlbum.launch == null) {
+ System.out.println("== coverageInternalTargetEnvironmentARMgetProperty() reporting PASSED but will be skipped.");
+ return;
+ }
+ if (armDisasm == null) return;
TargetEnvironmentARM env
= (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
Assert.assertNotNull(env);
Assert.assertNull("Property Test (no properties yet supported)", env.getProperty("x"));
}
-
- @Test
- public void testInternalTargetEnvironmentARMisCharSigned() {
- TargetEnvironmentARM env
- = (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
- Assert.assertNotNull(env);
-
- boolean isCharSigned = env.isCharSigned();
- Assert.assertFalse("Char Signed Test", isCharSigned);
- }
-
- @Test
- public void testInternalTargetEnvironmentARMisLittleEndian() throws Exception {
- armAlbum.openSnapshotAndWaitForSuspendedContext(4);
-
- final TargetEnvironmentARM env
- = (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
- Assert.assertNotNull(env);
-
- boolean isLittleEndian = env.isLittleEndian(disassemblyDMC);
- Assert.assertTrue("Little Endian Test", isLittleEndian);
- }
-
- @Test
- public void testInternalTargetEnvironmentARMisThumbMode() throws Exception {
- armAlbum.openSnapshotAndWaitForSuspendedContext(4);
-
- final TargetEnvironmentARM env
- = (TargetEnvironmentARM)armDisasm.getTargetEnvironmentService();
- Assert.assertNotNull(env);
-
- boolean isThumbMode = env.isThumbMode(disassemblyDMC, new Addr32(0x788656e4), false);
- Assert.assertTrue("Thumb Mode Test", isThumbMode);
- }
}
diff --git a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ExpressionsCasting2.java b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ExpressionsCasting2.java
index edabd11..e3fcd43 100644
--- a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ExpressionsCasting2.java
+++ b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ExpressionsCasting2.java
@@ -1,79 +1,85 @@
-/*******************************************************************************
- * 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.debugger.tests;
-
-import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager;
-import org.eclipse.cdt.dsf.debug.service.IExpressions2.CastInfo;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Tests of expression evaluation using cast operators.
- *
- * Additional checks for code where variables are in registers.
- */
-public class ExpressionsCasting2 extends BaseExpressionTest {
- private static final String YOU_SHOULD_BE_SEEING_THIS_TEXT = "\"You should be seeing this text!\"";
-
- /* (non-Javadoc)
- * @see org.eclipse.cdt.debug.edc.debugger.tests.SimpleDebuggerTest#getRequiredLaunchConfigurationType()
- */
- @Override
- protected String getRequiredLaunchConfigurationType() {
- return "com.nokia.cdt.debug.launch.systemTRKLaunch";
- }
-
-
- boolean formatterSetting;
-
- @Before
- public void turnOnFormatter() {
- formatterSetting = FormatExtensionManager.instance().isEnabled();
- FormatExtensionManager.instance().setEnabled(true);
- }
- @After
- public void restoreFormatter() {
- FormatExtensionManager.instance().setEnabled(formatterSetting);
- }
-
-
- @Test
- public void testCastingRegisters() throws Exception {
- if (launch == null) return;
- openSnapshotAndWaitForSuspendedContext(1);
-
- // these variables are in registers
- checkCastedExpr(null, YOU_SHOULD_BE_SEEING_THIS_TEXT, "aArg2", new CastInfo("TPtr8*"));
- checkCastedExpr(null, YOU_SHOULD_BE_SEEING_THIS_TEXT, "aArg3", new CastInfo("TPtr8*"));
- checkCastedExpr(null, YOU_SHOULD_BE_SEEING_THIS_TEXT, "aArg3", new CastInfo("TPtr8&"));
-
- // cast value in register directly to float, don't complain about "& of register"
- checkCastedExpr(null, "5.962985E-39", "aArg2", new CastInfo("float"));
- }
-
- @Test
- public void testCastingArraysInRegisters() throws Exception {
- if (launch == null) return;
- openSnapshotAndWaitForSuspendedContext(1);
-
- // these variables are in registers, don't complain about "& of register"
- CastInfo arrayCast = new CastInfo("TPtr8*", 0, 2);
- checkCastedChildExpr(null, YOU_SHOULD_BE_SEEING_THIS_TEXT, "aArg3", arrayCast, "aArg3[0]");
-
- }
-
- @Override
- public String getAlbumName() {
- return "RegisterFrameTestsBlackFlagRVCT.dsa";
- }
-
-}
+/*******************************************************************************
+ * 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.debugger.tests;
+
+import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager;
+import org.eclipse.cdt.dsf.debug.service.IExpressions2.CastInfo;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests of expression evaluation using cast operators.
+ *
+ * Additional checks for code where variables are in registers.
+ */
+public class ExpressionsCasting2 extends BaseExpressionTest {
+ private static final String YOU_SHOULD_BE_SEEING_THIS_TEXT = "\"You should be seeing this text!\"";
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.debug.edc.debugger.tests.SimpleDebuggerTest#getRequiredLaunchConfigurationType()
+ */
+ @Override
+ protected String getRequiredLaunchConfigurationType() {
+ return "com.nokia.cdt.debug.launch.systemTRKLaunch";
+ }
+
+
+ boolean formatterSetting;
+
+ @Before
+ public void turnOnFormatter() {
+ formatterSetting = FormatExtensionManager.instance().isEnabled();
+ FormatExtensionManager.instance().setEnabled(true);
+ }
+ @After
+ public void restoreFormatter() {
+ FormatExtensionManager.instance().setEnabled(formatterSetting);
+ }
+
+
+ @Test
+ public void testCastingRegisters() throws Exception {
+ if (launch == null) {
+ System.out.println("== testCastingRegisters() reporting PASSED but will be skipped.");
+ return;
+ }
+ openSnapshotAndWaitForSuspendedContext(1);
+
+ // these variables are in registers
+ checkCastedExpr(null, YOU_SHOULD_BE_SEEING_THIS_TEXT, "aArg2", new CastInfo("TPtr8*"));
+ checkCastedExpr(null, YOU_SHOULD_BE_SEEING_THIS_TEXT, "aArg3", new CastInfo("TPtr8*"));
+ checkCastedExpr(null, YOU_SHOULD_BE_SEEING_THIS_TEXT, "aArg3", new CastInfo("TPtr8&"));
+
+ // cast value in register directly to float, don't complain about "& of register"
+ checkCastedExpr(null, "5.962985E-39", "aArg2", new CastInfo("float"));
+ }
+
+ @Test
+ public void testCastingArraysInRegisters() throws Exception {
+ if (launch == null) {
+ System.out.println("== testCastingArraysInRegisters() reporting PASSED but will be skipped.");
+ return;
+ }
+ openSnapshotAndWaitForSuspendedContext(1);
+
+ // these variables are in registers, don't complain about "& of register"
+ CastInfo arrayCast = new CastInfo("TPtr8*", 0, 2);
+ checkCastedChildExpr(null, YOU_SHOULD_BE_SEEING_THIS_TEXT, "aArg3", arrayCast, "aArg3[0]");
+
+ }
+
+ @Override
+ public String getAlbumName() {
+ return "RegisterFrameTestsBlackFlagRVCT.dsa";
+ }
+
+}
diff --git a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ExpressionsServiceInternalsTest.java b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ExpressionsServiceInternalsTest.java
index 09787a1..a11cd8d 100644
--- a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ExpressionsServiceInternalsTest.java
+++ b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ExpressionsServiceInternalsTest.java
@@ -138,7 +138,7 @@ public class ExpressionsServiceInternalsTest extends SimpleDebuggerTest {
// }
/**
- * TODO method {@link Expressions#getModelData} currently almost nothing
+ * TODO method {@link Expressions#getBaseExpressions} does currently almost nothing
* except setData(new IDCExpression[0]);
* @throws Exception
*/
@@ -199,7 +199,7 @@ public class ExpressionsServiceInternalsTest extends SimpleDebuggerTest {
Expressions expressionsService = TestUtils.getService(session, Expressions.class);
IExpressions.IExpressionDMContext exprDMC = expressionsService.createExpression(frame, "lstruct");
Assert.assertNull(((IEDCExpression)exprDMC).getEvaluatedValue());
- expressionsService.loadExpressionValues(exprDMC, 3);
+ expressionsService.snapshotValues(exprDMC, 3);
// Assert.assertNotNull("lstruct not yet evaluated after loadExpressionValues() depth 3", ((IEDCExpression)exprDMC).getEvaluatedValue());
// Assert.assertEquals(TODO, ((IEDCExpression)exprDMC).getEvaluatedValue().intValue());
// Assert.assertEquals("TODO", ((IEDCExpression)exprDMC).getEvaluatedValueString());
diff --git a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ModulesTest.java b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ModulesTest.java
index 2414eed..9887b85 100644
--- a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ModulesTest.java
+++ b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/ModulesTest.java
@@ -218,8 +218,7 @@ public class ModulesTest {
// TODO Modules.ModuleDMData should return BaseAddress + size
Assert.assertEquals(MODULE_START, moduleDMData.getToAddress());
- // TODO Modules.ModuleDMData.isSymbolsLoaded() always returns false right now
- Assert.assertFalse(moduleDMData.isSymbolsLoaded());
+ Assert.assertTrue(moduleDMData.isSymbolsLoaded());
}
@Test
diff --git a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/OpaqueTypeResolving.java b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/OpaqueTypeResolving.java
index ac7756c..832ee32 100644
--- a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/OpaqueTypeResolving.java
+++ b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/OpaqueTypeResolving.java
@@ -21,6 +21,7 @@ import org.eclipse.cdt.debug.edc.symbols.IType;
import org.eclipse.cdt.debug.edc.tests.TestUtils;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.junit.Assert;
import org.junit.Test;
@@ -45,12 +46,12 @@ public class OpaqueTypeResolving extends SimpleDebuggerTest {
// PrivatePTR opaque_ptr = 0;
//
// At this point, debug session from the snapshot is stopped at
- // a the end of the executable.
+ // the end of the executable.
IEDCExpression exprVal = TestUtils.getExpressionDMC(session, frame, "opaque_ptr");
IType type = exprVal.getEvaluatedType();
- // First ensure if the original type of the var is an opaque type.
+ // First verify that the original type of the var is an opaque type.
//
Assert.assertTrue(type instanceof TypedefType);
type = type.getType(); // de-typedef
@@ -59,35 +60,36 @@ public class OpaqueTypeResolving extends SimpleDebuggerTest {
Assert.assertTrue(type instanceof ICompositeType);
Assert.assertTrue(((ICompositeType)type).isOpaque());
- Assert.assertTrue("Type is not opaque type.", type.getByteSize() == 0);
-
+ Assert.assertTrue("Type is not opaque type while it should be.", type.getByteSize() == 0);
+
// Now resolve the opaque type
//
Symbols symService = TestUtils.getService(session, Symbols.class);
ISymbolDMContext symCtx = DMContexts.getAncestorOfType(exprVal, ISymbolDMContext.class);
- ICompositeType defined = symService.resolveOpaqueType(symCtx, (ICompositeType) type);
+ ICompositeType defined
+ = symService.resolveOpaqueType(symCtx, (ICompositeType) type, new NullProgressMonitor());
Assert.assertFalse(defined.isOpaque());
Assert.assertEquals(type.getName(), defined.getName());
// Resolve one that's not an opaque type, fail.
- type = symService.resolveOpaqueType(symCtx, defined);
+ type = symService.resolveOpaqueType(symCtx, defined, new NullProgressMonitor());
Assert.assertNull(type);
}
-
+
@Test
public void testOpaqueTypeNeverDefined() throws Exception {
- // An opaque type that's never defined anywhere. We can resolve it.
+ // An opaque type that's never defined anywhere. We cannot resolve it.
//
// typedef struct UndefinedStruct* UndefinedPTR;
// UndefinedPTR opaque_ptr_to_undefined;
//
// At this point, debug session from the snapshot is stopped at
- // a the end of the executable.
+ // the end of the executable.
IEDCExpression exprVal = TestUtils.getExpressionDMC(session, frame, "opaque_ptr_to_undefined");
IType type = exprVal.getEvaluatedType();
- // First ensure if the original type of the var is an opaque type.
+ // First verify the original type of the var is an opaque type.
//
Assert.assertTrue(type instanceof TypedefType);
type = type.getType(); // de-typedef
@@ -96,13 +98,14 @@ public class OpaqueTypeResolving extends SimpleDebuggerTest {
Assert.assertTrue(type instanceof ICompositeType);
Assert.assertTrue(((ICompositeType)type).isOpaque());
- Assert.assertTrue("Type is not opaque type.", type.getByteSize() == 0);
+ Assert.assertTrue("Type is not opaque type while it should be.", type.getByteSize() == 0);
// Now try to resolve the opaque type, should fail
//
Symbols symService = TestUtils.getService(session, Symbols.class);
ISymbolDMContext symCtx = DMContexts.getAncestorOfType(exprVal, ISymbolDMContext.class);
- ICompositeType defined = symService.resolveOpaqueType(symCtx, (ICompositeType) type);
+ ICompositeType defined
+ = symService.resolveOpaqueType(symCtx, (ICompositeType) type, new NullProgressMonitor());
Assert.assertNull(defined);
}
}
diff --git a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RegisterFrameTestsBlackFlag.java b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RegisterFrameTestsBlackFlag.java
index 42b5a04..c0b920a 100644
--- a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RegisterFrameTestsBlackFlag.java
+++ b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RegisterFrameTestsBlackFlag.java
@@ -1,125 +1,134 @@
-/*******************************************************************************
- * 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.debugger.tests;
-
-import static org.junit.Assert.*;
-
-import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager;
-import org.eclipse.cdt.debug.edc.tests.TestUtils;
-import org.junit.Test;
-
-/**
- * Test that we can recover expressions from stack frames other than the TOS
- *
- * (actual case in bug 304040)
- */
-public class RegisterFrameTestsBlackFlag extends SimpleDebuggerTest {
- /**
- *
- */
- private static final String YOU_SHOULD_BE_SEEING_THIS_TEXT = "\"You should be seeing this text!\"";
- boolean formatterSetting;
-
- public void setFormatter(boolean enable) {
- formatterSetting = FormatExtensionManager.instance().isEnabled();
- FormatExtensionManager.instance().setEnabled(enable);
- }
- public void restoreFormatter() {
- FormatExtensionManager.instance().setEnabled(formatterSetting);
- }
-
- /** account for patchy decimal vs. hex outputs */
- private void assertNumbersEquals(String exp, String value) {
- try {
- long expl, valuel;
- if (exp.startsWith("0x"))
- expl = Long.valueOf(exp.substring(2), 16);
- else
- expl = Long.valueOf(exp);
- if (value.startsWith("0x"))
- valuel = Long.valueOf(value.substring(2), 16);
- else
- valuel = Long.valueOf(value);
- assertEquals(value, expl, valuel);
- } catch (NumberFormatException e) {
- // fail naturally
- assertEquals(exp, value);
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.cdt.debug.edc.debugger.tests.SimpleDebuggerTest#getRequiredLaunchConfigurationType()
- */
- @Override
- protected String getRequiredLaunchConfigurationType() {
- return "com.nokia.cdt.debug.launch.systemTRKLaunch";
- }
-
- @Test
- public void testLength() throws Exception {
- if (launch == null) return;
- frame = TestUtils.waitForStackFrame(session, threadDMC, 0);
-
- try {
- setFormatter(false);
- assertNumbersEquals("0x7907aee0", getExpressionValue("this"));
- } finally {
- restoreFormatter();
- }
- }
- @Test
- public void testShowConstArguments() throws Exception {
- if (launch == null) return;
- frame = TestUtils.waitForStackFrame(session, threadDMC, 1);
- try {
- // note: formatter was half-showing decimal and hex at this time
- setFormatter(false);
- assertNumbersEquals("0x40ee38", getExpressionValue("aArg1"));
- assertNumbersEquals("0x40ee38", getExpressionValue("aArg2"));
- assertNumbersEquals("0x40ee38", getExpressionValue("aArg3"));
- assertNumbersEquals("0x40ee38", getExpressionValue("aArg4"));
- assertEquals("31", getExpressionValue("length"));
- assertEquals("31", getExpressionValue("length2"));
- assertEquals("31", getExpressionValue("length3"));
- assertEquals("31", getExpressionValue("length4"));
- } finally {
- restoreFormatter();
- }
- }
- @Test
- public void testShowTPtr() throws Exception {
- if (launch == null) return;
- frame = TestUtils.waitForStackFrame(session, threadDMC, 2);
- try {
- setFormatter(true);
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr8"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr16"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC8"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC16"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr8"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr16"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr8p"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr16p"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrp"));
-
- } finally {
- restoreFormatter();
- }
- }
-
- @Override
- public String getAlbumName() {
- return "RegisterFrameTestsBlackFlag.dsa";
- }
-
-}
+/*******************************************************************************
+ * 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.debugger.tests;
+
+import static org.junit.Assert.*;
+
+import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager;
+import org.eclipse.cdt.debug.edc.tests.TestUtils;
+import org.junit.Test;
+
+/**
+ * Test that we can recover expressions from stack frames other than the TOS
+ *
+ * (actual case in bug 304040)
+ */
+public class RegisterFrameTestsBlackFlag extends SimpleDebuggerTest {
+ /**
+ *
+ */
+ private static final String YOU_SHOULD_BE_SEEING_THIS_TEXT = "\"You should be seeing this text!\"";
+ boolean formatterSetting;
+
+ public void setFormatter(boolean enable) {
+ formatterSetting = FormatExtensionManager.instance().isEnabled();
+ FormatExtensionManager.instance().setEnabled(enable);
+ }
+ public void restoreFormatter() {
+ FormatExtensionManager.instance().setEnabled(formatterSetting);
+ }
+
+ /** account for patchy decimal vs. hex outputs */
+ private void assertNumbersEquals(String exp, String value) {
+ try {
+ long expl, valuel;
+ if (exp.startsWith("0x"))
+ expl = Long.valueOf(exp.substring(2), 16);
+ else
+ expl = Long.valueOf(exp);
+ if (value.startsWith("0x"))
+ valuel = Long.valueOf(value.substring(2), 16);
+ else
+ valuel = Long.valueOf(value);
+ assertEquals(value, expl, valuel);
+ } catch (NumberFormatException e) {
+ // fail naturally
+ assertEquals(exp, value);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.debug.edc.debugger.tests.SimpleDebuggerTest#getRequiredLaunchConfigurationType()
+ */
+ @Override
+ protected String getRequiredLaunchConfigurationType() {
+ return "com.nokia.cdt.debug.launch.systemTRKLaunch";
+ }
+
+ @Test
+ public void testLength() throws Exception {
+ if (launch == null) {
+ System.out.println("== testLength() reporting PASSED but will be skipped.");
+ return;
+ }
+ frame = TestUtils.waitForStackFrame(session, threadDMC, 0);
+
+ try {
+ setFormatter(false);
+ assertNumbersEquals("0x7907aee0", getExpressionValue("this"));
+ } finally {
+ restoreFormatter();
+ }
+ }
+ @Test
+ public void testShowConstArguments() throws Exception {
+ if (launch == null) {
+ System.out.println("== testShowConstArguments() reporting PASSED but will be skipped.");
+ return;
+ }
+ frame = TestUtils.waitForStackFrame(session, threadDMC, 1);
+ try {
+ // note: formatter was half-showing decimal and hex at this time
+ setFormatter(false);
+ assertNumbersEquals("0x40ee38", getExpressionValue("aArg1"));
+ assertNumbersEquals("0x40ee38", getExpressionValue("aArg2"));
+ assertNumbersEquals("0x40ee38", getExpressionValue("aArg3"));
+ assertNumbersEquals("0x40ee38", getExpressionValue("aArg4"));
+ assertEquals("31", getExpressionValue("length"));
+ assertEquals("31", getExpressionValue("length2"));
+ assertEquals("31", getExpressionValue("length3"));
+ assertEquals("31", getExpressionValue("length4"));
+ } finally {
+ restoreFormatter();
+ }
+ }
+ @Test
+ public void testShowTPtr() throws Exception {
+ if (launch == null) {
+ System.out.println("== testShowTPtr() reporting PASSED but will be skipped.");
+ return;
+ }
+ frame = TestUtils.waitForStackFrame(session, threadDMC, 2);
+ try {
+ setFormatter(true);
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr8"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr16"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC8"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC16"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr8"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr16"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr8p"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr16p"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrp"));
+
+ } finally {
+ restoreFormatter();
+ }
+ }
+
+ @Override
+ public String getAlbumName() {
+ return "RegisterFrameTestsBlackFlag.dsa";
+ }
+
+}
diff --git a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RegisterFrameTestsBlackFlagRVCT.java b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RegisterFrameTestsBlackFlagRVCT.java
index cd92cb6..295330e 100644
--- a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RegisterFrameTestsBlackFlagRVCT.java
+++ b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RegisterFrameTestsBlackFlagRVCT.java
@@ -1,159 +1,180 @@
-/*******************************************************************************
- * 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.debugger.tests;
-
-import static org.junit.Assert.*;
-
-import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager;
-import org.eclipse.cdt.debug.edc.tests.TestUtils;
-import org.junit.Test;
-
-/**
- * Test that we can recover expressions from stack frames other than the TOS
- *
- * (actual case in bug 304040)
- *
- * Handle broken DWARF frame register format in RVCT
- */
-public class RegisterFrameTestsBlackFlagRVCT extends SimpleDebuggerTest {
- /**
- *
- */
- private static final String YOU_SHOULD_BE_SEEING_THIS_TEXT = "\"You should be seeing this text!\"";
- boolean formatterSetting;
-
- public void setFormatter(boolean enable) {
- formatterSetting = FormatExtensionManager.instance().isEnabled();
- FormatExtensionManager.instance().setEnabled(enable);
- }
- public void restoreFormatter() {
- FormatExtensionManager.instance().setEnabled(formatterSetting);
- }
-
- /** account for patchy decimal vs. hex outputs */
- private void assertNumbersEquals(String exp, String value) {
- try {
- long expl, valuel;
- if (exp.startsWith("0x"))
- expl = Long.valueOf(exp.substring(2), 16);
- else
- expl = Long.valueOf(exp);
- if (value.startsWith("0x"))
- valuel = Long.valueOf(value.substring(2), 16);
- else
- valuel = Long.valueOf(value);
- assertEquals(value, expl, valuel);
- } catch (NumberFormatException e) {
- // fail naturally
- assertEquals(exp, value);
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.cdt.debug.edc.debugger.tests.SimpleDebuggerTest#getRequiredLaunchConfigurationType()
- */
- @Override
- protected String getRequiredLaunchConfigurationType() {
- return "com.nokia.cdt.debug.launch.systemTRKLaunch";
- }
-
- protected void doTestStringFormatting() throws Exception {
- try {
- setFormatter(true);
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr8"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr16"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC8"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC16"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr8"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr16"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr8p"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr16p"));
- assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrp"));
-
- } finally {
- restoreFormatter();
- }
- }
-
- @Test
- public void testBaseFunction() throws Exception {
- if (launch == null) return;
- openSnapshotAndWaitForSuspendedContext(0);
- doTestStringFormatting();
- }
- @Test
- public void testShowConstArguments1() throws Exception {
- if (launch == null) return;
- openSnapshotAndWaitForSuspendedContext(1);
- frame = TestUtils.waitForStackFrame(session, threadDMC, 1);
- doTestStringFormatting();
- }
- @Test
- public void testShowConstArguments2() throws Exception {
- if (launch == null) return;
- openSnapshotAndWaitForSuspendedContext(2);
- frame = TestUtils.waitForStackFrame(session, threadDMC, 1);
- doTestStringFormatting();
-
- }
- @Test
- public void testShowConstArguments3() throws Exception {
- if (launch == null) return;
- openSnapshotAndWaitForSuspendedContext(3);
- frame = TestUtils.waitForStackFrame(session, threadDMC, 1);
- doTestStringFormatting();
- }
-
- @Test
- public void testShowConstArguments4() throws Exception {
- if (launch == null) return;
- openSnapshotAndWaitForSuspendedContext(4);
- frame = TestUtils.waitForStackFrame(session, threadDMC, 1);
- doTestStringFormatting();
- }
-
- @Test
- public void testShowConstArguments5() throws Exception {
- if (launch == null) return;
- openSnapshotAndWaitForSuspendedContext(4);
-
- try {
- setFormatter(false);
- assertNumbersEquals("31", getExpressionValue("length"));
- assertNumbersEquals("31", getExpressionValue("length2"));
- assertNumbersEquals("31", getExpressionValue("length3"));
- assertNumbersEquals("31", getExpressionValue("length4"));
- } finally {
- restoreFormatter();
- }
- }
-
- @Test
- public void testShowE32Main() throws Exception {
- if (launch == null) return;
- openSnapshotAndWaitForSuspendedContext(4);
- frame = TestUtils.waitForStackFrame(session, threadDMC, 5);
- try {
- setFormatter(false);
- assertNumbersEquals("0", getExpressionValue("error"));
- } finally {
- restoreFormatter();
- }
- }
-
- @Override
- public String getAlbumName() {
- return "RegisterFrameTestsBlackFlagRVCT.dsa";
- }
-
-}
+/*******************************************************************************
+ * 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.debugger.tests;
+
+import static org.junit.Assert.*;
+
+import org.eclipse.cdt.debug.edc.internal.formatter.FormatExtensionManager;
+import org.eclipse.cdt.debug.edc.tests.TestUtils;
+import org.junit.Test;
+
+/**
+ * Test that we can recover expressions from stack frames other than the TOS
+ *
+ * (actual case in bug 304040)
+ *
+ * Handle broken DWARF frame register format in RVCT
+ */
+public class RegisterFrameTestsBlackFlagRVCT extends SimpleDebuggerTest {
+ /**
+ *
+ */
+ private static final String YOU_SHOULD_BE_SEEING_THIS_TEXT = "\"You should be seeing this text!\"";
+ boolean formatterSetting;
+
+ public void setFormatter(boolean enable) {
+ formatterSetting = FormatExtensionManager.instance().isEnabled();
+ FormatExtensionManager.instance().setEnabled(enable);
+ }
+ public void restoreFormatter() {
+ FormatExtensionManager.instance().setEnabled(formatterSetting);
+ }
+
+ /** account for patchy decimal vs. hex outputs */
+ private void assertNumbersEquals(String exp, String value) {
+ try {
+ long expl, valuel;
+ if (exp.startsWith("0x"))
+ expl = Long.valueOf(exp.substring(2), 16);
+ else
+ expl = Long.valueOf(exp);
+ if (value.startsWith("0x"))
+ valuel = Long.valueOf(value.substring(2), 16);
+ else
+ valuel = Long.valueOf(value);
+ assertEquals(value, expl, valuel);
+ } catch (NumberFormatException e) {
+ // fail naturally
+ assertEquals(exp, value);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.debug.edc.debugger.tests.SimpleDebuggerTest#getRequiredLaunchConfigurationType()
+ */
+ @Override
+ protected String getRequiredLaunchConfigurationType() {
+ return "com.nokia.cdt.debug.launch.systemTRKLaunch";
+ }
+
+ protected void doTestStringFormatting() throws Exception {
+ try {
+ setFormatter(true);
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr8"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr16"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("cstr"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC8"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC16"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrC"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr8"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr16"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr8p"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptr16p"));
+ assertEquals(YOU_SHOULD_BE_SEEING_THIS_TEXT, getExpressionValue("ptrp"));
+
+ } finally {
+ restoreFormatter();
+ }
+ }
+
+ @Test
+ public void testBaseFunction() throws Exception {
+ if (launch == null) {
+ System.out.println("== testBaseFunction() reporting PASSED but will be skipped.");
+ return;
+ }
+ openSnapshotAndWaitForSuspendedContext(0);
+ doTestStringFormatting();
+ }
+ @Test
+ public void testShowConstArguments1() throws Exception {
+ if (launch == null) {
+ System.out.println("== testShowConstArguments1() reporting PASSED but will be skipped.");
+ return;
+ }
+ openSnapshotAndWaitForSuspendedContext(1);
+ frame = TestUtils.waitForStackFrame(session, threadDMC, 1);
+ doTestStringFormatting();
+ }
+ @Test
+ public void testShowConstArguments2() throws Exception {
+ if (launch == null) {
+ System.out.println("== testShowConstArguments2() reporting PASSED but will be skipped.");
+ return;
+ }
+ openSnapshotAndWaitForSuspendedContext(2);
+ frame = TestUtils.waitForStackFrame(session, threadDMC, 1);
+ doTestStringFormatting();
+
+ }
+ @Test
+ public void testShowConstArguments3() throws Exception {
+ if (launch == null) {
+ System.out.println("== testShowConstArguments3() reporting PASSED but will be skipped.");
+ return;
+ }
+ openSnapshotAndWaitForSuspendedContext(3);
+ frame = TestUtils.waitForStackFrame(session, threadDMC, 1);
+ doTestStringFormatting();
+ }
+
+ @Test
+ public void testShowConstArguments4() throws Exception {
+ if (launch == null) {
+ System.out.println("== testShowConstArguments4() reporting PASSED but will be skipped.");
+ return;
+ }
+ openSnapshotAndWaitForSuspendedContext(4);
+ frame = TestUtils.waitForStackFrame(session, threadDMC, 1);
+ doTestStringFormatting();
+ }
+
+ @Test
+ public void testShowConstArguments5() throws Exception {
+ if (launch == null) {
+ System.out.println("== testShowConstArguments5() reporting PASSED but will be skipped.");
+ return;
+ }
+ openSnapshotAndWaitForSuspendedContext(4);
+
+ try {
+ setFormatter(false);
+ assertNumbersEquals("31", getExpressionValue("length"));
+ assertNumbersEquals("31", getExpressionValue("length2"));
+ assertNumbersEquals("31", getExpressionValue("length3"));
+ assertNumbersEquals("31", getExpressionValue("length4"));
+ } finally {
+ restoreFormatter();
+ }
+ }
+
+ @Test
+ public void testShowE32Main() throws Exception {
+ if (launch == null) {
+ System.out.println("testShowE32Main() reporting PASSED but will be skipped.");
+ return;
+ }
+ openSnapshotAndWaitForSuspendedContext(4);
+ frame = TestUtils.waitForStackFrame(session, threadDMC, 5);
+ try {
+ setFormatter(false);
+ assertNumbersEquals("0", getExpressionValue("error"));
+ } finally {
+ restoreFormatter();
+ }
+ }
+
+ @Override
+ public String getAlbumName() {
+ return "RegisterFrameTestsBlackFlagRVCT.dsa";
+ }
+
+}
diff --git a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RunControlDMCSubclass.java b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RunControlDMCSubclass.java
index a48f69b..5df37fc 100644
--- a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RunControlDMCSubclass.java
+++ b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/RunControlDMCSubclass.java
@@ -10,13 +10,10 @@
*******************************************************************************/
package org.eclipse.cdt.debug.edc.debugger.tests;
-import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import junit.framework.Assert;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -34,8 +31,8 @@ import org.eclipse.cdt.debug.edc.tests.TestUtils;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
-import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.tm.tcf.services.IRunControl;
@@ -79,13 +76,13 @@ public class RunControlDMCSubclass extends BaseLaunchTest {
basicLaunch();
EDCServicesTracker edcTracker
= new EDCServicesTracker(EDCDebugger.getBundleContext(), session.getId());
- Assert.assertNotNull(edcTracker);
+ assertNotNull(edcTracker);
runControlService = edcTracker.getService(RunControl.class);
- Assert.assertNotNull(runControlService);
+ assertNotNull(runControlService);
stackService = edcTracker.getService(Stack.class);
- Assert.assertNotNull(stackService);
+ assertNotNull(stackService);
breakpointsService = edcTracker.getService(Breakpoints.class);
- Assert.assertNotNull(breakpointsService);
+ assertNotNull(breakpointsService);
}
@After
@@ -120,12 +117,12 @@ public class RunControlDMCSubclass extends BaseLaunchTest {
Map<String, Object> cseParams = cse.getParams();
assertNotNull(cseParams);
- Assert.assertEquals(cseProps, cseParams);
+ assertEquals(cseProps, cseParams);
RunControl.IExecutionDMContext[] dmc = cse.getTriggeringContexts();
assertNotNull(dmc);
assertEquals(1, dmc.length);
- Assert.assertEquals(bdeDMC, dmc[0]);
+ assertEquals(bdeDMC, dmc[0]);
// protected DMCResumedEvent createResumedEvent()
RunControl.ContainerResumedEvent cre
@@ -136,52 +133,57 @@ public class RunControlDMCSubclass extends BaseLaunchTest {
dmc = cre.getTriggeringContexts();
assertNotNull(dmc);
assertEquals(1, dmc.length);
- Assert.assertEquals(bdeDMC, dmc[0]);
+ assertEquals(bdeDMC, dmc[0]);
+ }
+
+ @Test
+ public void testRootDMC() {
+ RunControl.RootExecutionDMC rootDMC = runControlService.getRootDMC();
+ assertNotNull(rootDMC);
+ assertNull(rootDMC.getSymbolDMContext());
+ assertFalse(rootDMC.canDetach());
+ assertFalse(rootDMC.canStep());
+ }
+
+ @Test
+ public void testStepIntoOneInstruction() throws Exception {
+ waitRunToLine(runControlService, dbg_derived_types_cpp, 285);
+
+ Query<IStatus> query = new Query<IStatus>() {
+ @Override
+ protected void execute(final DataRequestMonitor<IStatus> drm) {
+ runControlService.step(threadDMC, StepType.INSTRUCTION_STEP_INTO, drm);
+ }
+ };
+
+ session.getExecutor().execute(query);
+
+ query.get(5, TimeUnit.SECONDS);
+ assertTrue(query.isDone());
+
+ updateSuspendedFrame(200);
+ assertControlIsAt("dbg_derived_types.cpp", "structs", 40);
}
@Test
- public void testExecutionDMCStepOut() throws Exception {
- waitRunToLine(runControlService, dbg_derived_types_cpp, 57);
+ public void testStepOut() throws Exception {
+ waitRunToLine(runControlService, dbg_derived_types_cpp, 57, 2000);
+ TestUtils.waitForUIUpdate(4000);
// set this so it stops someplace, even if it's after the expected step out point
setTempBreakpoint(breakpointsService, dbg_derived_types_cpp, 288);
- // public abstract class ExectionDMC { protected void stepOut(RequestMonitor) }
-
- final Class<?>[] stepOutArgClasses = new Class<?>[] {RequestMonitor.class};
Query<IStatus> query = new Query<IStatus>() {
@Override
protected void execute(final DataRequestMonitor<IStatus> drm) {
- ExecutionDMC exeDMC = DMContexts.getAncestorOfType(threadDMC, ExecutionDMC.class);
- Object[] stepOutArgs = new Object[] {drm};
- try {
- TestReflectionHelper.objectFromPrivateFunctionWithArgs(
- exeDMC, ExecutionDMC.class, "stepOut", stepOutArgs, stepOutArgClasses);
- } catch (InvocationTargetException ite) {
- Throwable t = ite.getTargetException();
- if ((t instanceof AssertionError)
- && t.getMessage().equals(RunControl.STEP_RETURN_NOT_SUPPORTED)) {
- drm.setData(new Status(IStatus.INFO, EDCDebugger.PLUGIN_ID,
- RunControl.STEP_RETURN_NOT_SUPPORTED));
- } else {
- drm.setStatus(new Status(IStatus.ERROR, EDCTestPlugin.PLUGIN_ID,
- "InvocationTargetException thrown invoking ExecutionDMC#stepOut() : "//$NON-NLS-1$
- + ite.getLocalizedMessage()));
- }
- drm.done();
- } catch (Exception e) {
- drm.setStatus(new Status(IStatus.ERROR, EDCTestPlugin.PLUGIN_ID,
- "exception thrown invoking ExecutionDMC#stepOut() : "//$NON-NLS-1$
- + e.getLocalizedMessage()));
- drm.done();
- }
+ runControlService.step(threadDMC, StepType.STEP_RETURN, drm);
}
};
try {
session.getExecutor().execute(query);
} catch (Exception e) {
- Assert.fail(e.getLocalizedMessage());
+ fail(e.getLocalizedMessage());
}
IStatus status = query.get(5, TimeUnit.SECONDS);
@@ -195,15 +197,6 @@ public class RunControlDMCSubclass extends BaseLaunchTest {
}
@Test
- public void testRootDMC() {
- RunControl.RootExecutionDMC rootDMC = runControlService.getRootDMC();
- assertNotNull(rootDMC);
- assertNull(rootDMC.getSymbolDMContext());
- assertFalse(rootDMC.canDetach());
- assertFalse(rootDMC.canStep());
- }
-
- @Test
public void testThreadDMC() {
assertFalse(threadDMC.canDetach());
ExecutionDMC exeDMC = null;
@@ -232,38 +225,6 @@ public class RunControlDMCSubclass extends BaseLaunchTest {
}
@Test
- public void unitTestRunControlStepIntoOneInstruction() throws Exception {
- waitRunToLine(runControlService, dbg_derived_types_cpp, 285);
-
- // private void stepOverOneInstruction(ExecutionDMC, IAddress, RequestMonitor)
-
- final Class<?>[] stepIntoArgClasses = new Class<?>[] {ExecutionDMC.class, RequestMonitor.class};
- Query<IStatus> query = new Query<IStatus>() {
- @Override
- protected void execute(final DataRequestMonitor<IStatus> drm) {
- Object[] stepIntoArgs = new Object[] {threadDMC, drm};
- try {
- TestReflectionHelper.objectFromPrivateFunctionWithArgs(
- runControlService, "stepIntoOneInstruction", stepIntoArgs, stepIntoArgClasses);
- } catch (Exception e) {
- drm.setStatus(new Status(IStatus.ERROR, EDCTestPlugin.PLUGIN_ID,
- "exception thrown invoking RunControl#stepIntoOneInstruction()"//$NON-NLS-1$
- + e.getLocalizedMessage()));
- drm.done();
- }
- }
- };
-
- session.getExecutor().execute(query);
-
- query.get(5, TimeUnit.SECONDS);
- assertTrue(query.isDone());
-
- updateSuspendedFrame(200);
- assertControlIsAt("dbg_derived_types.cpp", "structs", 40);
- }
-
- @Test
public void unitTestRunControlStepOverOneInstruction() throws Exception {
waitRunToLine(runControlService, dbg_derived_types_cpp, 285);
diff --git a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/SimpleDebuggerTest.java b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/SimpleDebuggerTest.java
index ed04436..bea6bb6 100644
--- a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/SimpleDebuggerTest.java
+++ b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/debugger/tests/SimpleDebuggerTest.java
@@ -53,12 +53,19 @@ public abstract class SimpleDebuggerTest {
String reqdLauncher = getRequiredLaunchConfigurationType();
if (reqdLauncher != null) {
if (!TestUtils.hasLaunchConfiguationType(reqdLauncher)) {
+ System.out.println("\n== " + getClass().getName()
+ + ":\n== => Required Launcher " + reqdLauncher
+ + " not found for album " + getAlbumName());
return;
}
}
reqdLauncher = getRequiredTCFAgentLauncher();
if (reqdLauncher != null) {
if (!TestUtils.hasTCFAgentLauncher(reqdLauncher)) {
+ System.out.println("\n== " + getClass().getName()
+ + ":\n== => Required TCF Agent Launcher "
+ + reqdLauncher + " not found for album "
+ + getAlbumName());
return;
}
}
diff --git a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/tests/TestDwarfReader.java b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/tests/TestDwarfReader.java
index 6db3025..f21f295 100644
--- a/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/tests/TestDwarfReader.java
+++ b/org.eclipse.cdt.debug.edc.tests/src/org/eclipse/cdt/debug/edc/tests/TestDwarfReader.java
@@ -1446,7 +1446,10 @@ public class TestDwarfReader extends AbstractDwarfReaderTest {
TestUtils.showDebugPerspective();
dwarfAlbum = DwarfFrameRegisterAlbum.openAlbum();
dwarfAlbum.launchAndWaitForSuspendedContext();
- if (dwarfAlbum.getLaunch() == null) return;
+ if (dwarfAlbum.getLaunch() == null) {
+ System.out.println("== testShowTPtr() reporting PASSED but will be skipped.");
+ return;
+ }
edcTracker = new EDCServicesTracker(EDCDebugger.getBundleContext(), dwarfAlbum.getSession().getId());
Assert.assertNotNull(edcTracker);
} catch (Exception e) {
diff --git a/org.eclipse.cdt.debug.edc.x86/src/org/eclipse/cdt/debug/edc/x86/X86Stack.java b/org.eclipse.cdt.debug.edc.x86/src/org/eclipse/cdt/debug/edc/x86/X86Stack.java
index f4669f6..da97ce8 100644
--- a/org.eclipse.cdt.debug.edc.x86/src/org/eclipse/cdt/debug/edc/x86/X86Stack.java
+++ b/org.eclipse.cdt.debug.edc.x86/src/org/eclipse/cdt/debug/edc/x86/X86Stack.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2010 Nokia and others.
+ * Copyright (c) 2009, 2011 Nokia and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -81,7 +81,7 @@ public class X86Stack extends Stack {
long eipValue = Long.valueOf(registersService.getRegisterValue(context, "EIP"), 16);
long espValue = Long.valueOf(registersService.getRegisterValue(context, "ESP"), 16);
long ebpValue = Long.valueOf(registersService.getRegisterValue(context, "EBP"), 16);
-
+
long baseAddress = ebpValue;
long instructionAddress = eipValue;
long returnAddress = 0;
@@ -96,6 +96,11 @@ public class X86Stack extends Stack {
IEDCModuleDMContext module = modules.getModuleByAddress(context.getSymbolDMContext(), new Addr64(Long
.toString(instructionAddress)));
+ if (module != null) {
+ // make sure the symbols are loaded for this module if they exist
+ module.getSymbolReader(true);
+ }
+
boolean isFramePushed = true;
boolean detected = false;
X86PreservedRegisters preserved = new X86PreservedRegisters();
@@ -166,20 +171,20 @@ public class X86Stack extends Stack {
properties.put(StackFrameDMC.PRESERVED_REGISTERS, preserved.getPreservedRegisters());
frames.add(new EdcStackFrame(properties));
- // avoid recursive loop
- if (level > 0 && baseAddress == previousBaseAddress) {
+ if (previousBaseAddress == 0 // Bail out when we hit the top of the stack frame
+
+ // avoid recursive loop
+ || level > 0 && baseAddress == previousBaseAddress
+
+ // no more than requested (well, 1 extra so <...more frames...> works)
+ || endIndex != ALL_FRAMES && level == endIndex) {
+
properties.put(StackFrameDMC.ROOT_FRAME, true);
break;
}
-
+
baseAddress = previousBaseAddress;
instructionAddress = returnAddress;
-
- // Bail out when we hit the top of the stack frame
- if (baseAddress == 0) {
- properties.put(StackFrameDMC.ROOT_FRAME, true);
- break;
- }
}
return frames;
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
index 87a50ce..83ab2e1 100644
--- 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
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
+import java.math.BigInteger;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;
@@ -25,9 +26,24 @@ import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleDMC;
import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ProcessExecutionDMC;
import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ThreadExecutionDMC;
import org.eclipse.cdt.debug.edc.internal.services.dsf.Symbols;
+import org.eclipse.cdt.debug.edc.internal.symbols.ConstType;
+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.IInheritance;
+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.IRuntimeType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ITypedef;
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.PointerType;
+import org.eclipse.cdt.debug.edc.internal.symbols.ReferenceType;
+import org.eclipse.cdt.debug.edc.internal.symbols.TypedefType;
+import org.eclipse.cdt.debug.edc.internal.symbols.VolatileType;
import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
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.Stack;
import org.eclipse.cdt.debug.edc.services.Stack.EnumeratorDMC;
@@ -38,6 +54,7 @@ import org.eclipse.cdt.debug.edc.symbols.IDebugInfoProvider;
import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
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.cdt.debug.edc.symbols.IVariableLocation;
import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
@@ -126,6 +143,7 @@ public class EvaluateID extends SimpleInstruction {
valueLocation = provider.getLocation(servicesTracker, frame, module.toLinkAddress(frame.getInstructionPtrAddress()),
TypeUtils.isConstType(variable.getVariable().getType()));
}
+
if (valueLocation == null) {
// unhandled
valueLocation
@@ -134,6 +152,11 @@ public class EvaluateID extends SimpleInstruction {
variable.getName()));
}
+ // if requested, check for and use RTTI information
+ if (EDCDebugger.getResolveRttiTypes() && !(valueLocation instanceof InvalidVariableLocation)) {
+ handleRTTI(valueLocation, variable, servicesTracker, frame);
+ }
+
// create a VariableWithValue and push on the stack
VariableWithValue varWval = new VariableWithValue(servicesTracker, frame, variable.getVariable());
varWval.setValueLocation(valueLocation);
@@ -160,8 +183,9 @@ public class EvaluateID extends SimpleInstruction {
// first attempt to match against variable names in the module
IEDCSymbolReader reader = module.getSymbolReader();
if (reader instanceof EDCSymbolReader) {
- if (findGlobalVariable(searchName, (EDCSymbolReader)reader, servicesTracker)
- || findLocalVariable(searchName, module, (EDCSymbolReader)reader, servicesTracker))
+ EDCSymbolReader edcReader = (EDCSymbolReader)reader;
+ if (findGlobalVariable(searchName, module, edcReader, servicesTracker)
+ || findLocalVariable(searchName, module, edcReader, servicesTracker))
return;
}
@@ -184,12 +208,96 @@ public class EvaluateID extends SimpleInstruction {
}
/**
+ *
+ * @param valueLocation
+ * @param variable
+ * @param servicesTracker
+ * @param frame
+ * @throws CoreException
+ */
+ private void handleRTTI(IVariableLocation valueLocation, VariableDMC variable,
+ EDCServicesTracker servicesTracker, StackFrameDMC frame) throws CoreException {
+
+ // only check for RTTI when you have a pointer or reference of a composite type
+ // that has RTTI info
+ IType varType = variable.getVariable().getType();
+ boolean pointerType = varType instanceof IPointerType;
+ boolean referenceType = varType instanceof IReferenceType;
+ if (!pointerType && !referenceType)
+ return;
+
+ IType pointedToType = TypeUtils.getStrippedType(varType.getType());
+
+ if (!(pointedToType instanceof ICompositeType)
+ || !((ICompositeType)pointedToType).hasRuntimeTypeInfo())
+ return;
+
+ ICompositeType composite = (ICompositeType)pointedToType;
+
+ // determine the location of the runtime type info
+ long originalAddr = valueLocation.readValue(4).longValue();
+ long runtimeTypeAddr = originalAddr + composite.getRuntimeTypeOffset();
+ MemoryVariableLocation runtimeTypeLocation = new MemoryVariableLocation(
+ servicesTracker, frame, BigInteger.valueOf(runtimeTypeAddr), true);
+
+ // get the runtime type
+ IType runtimeType = composite.getRuntimeType(runtimeTypeLocation);
+
+ if (runtimeType != null && pointedToType != runtimeType) {
+ // the runtime type differs from the original type, so clone the variable,
+ // and make its type has the same qualifiers but with the runtime composite
+ IType subType = varType.getType();
+ IType valueType = varType.getType();
+ if (referenceType)
+ valueType = new ReferenceType("", valueType.getScope(),
+ valueType.getByteSize(), valueType.getProperties());
+ else
+ valueType = new PointerType("", valueType.getScope(),
+ 4, valueType.getProperties());
+
+ // if there are qualifiers, copy them, too
+ IType type = valueType;
+ while (subType instanceof ITypedef || subType instanceof IQualifierType) {
+ IType newSubType = null;
+ if (subType instanceof ITypedef) {
+ ITypedef oldTypedef = (ITypedef)subType;
+ newSubType = new TypedefType(oldTypedef.getName(),
+ oldTypedef.getScope(),oldTypedef.getProperties());
+ } else {
+ IQualifierType oldQualifierType = (IQualifierType)subType;
+ if (subType instanceof IConstType)
+ newSubType = new ConstType(oldQualifierType.getScope(),
+ oldQualifierType.getProperties());
+ else
+ newSubType = new VolatileType(oldQualifierType.getScope(),
+ oldQualifierType.getProperties());
+ }
+ type.setType(newSubType);
+ type = newSubType;
+ subType = subType.getType();
+ }
+ type.setType(runtimeType);
+
+ IVariable variableWithNewType = variable.getVariable().copyWithNewType(type);
+ variable.setVariable(variableWithNewType);
+
+ IInheritance[] inheritances = ((ICompositeType)runtimeType).getInheritances();
+ for (IInheritance inheritance : inheritances) {
+ if (inheritance.getType() == composite) {
+ ((IRuntimeType)valueType).setRuntimeOffset(-inheritance.getFieldsOffset());
+ break;
+ }
+ }
+ }
+ }
+
+ /**
* @param servicesTracker
* @param searchName
* @param idip
* @param baseLinkAddress
*/
- private boolean findGlobalVariable(String searchName,
+ private boolean findGlobalVariable(String searchName, IEDCModuleDMContext module,
EDCSymbolReader reader, EDCServicesTracker servicesTracker) {
IDebugInfoProvider idip = reader.getDebugInfoProvider();
@@ -202,8 +310,10 @@ public class EvaluateID extends SimpleInstruction {
= var.getLocationProvider()
.getLocation(servicesTracker, null, reader.getBaseLinkAddress(),
TypeUtils.isConstType(var.getType()));
- if (loc instanceof InvalidVariableLocation)
+ if (!(loc instanceof MemoryVariableLocation))
continue;
+ MemoryVariableLocation memLoc = (MemoryVariableLocation)loc;
+ memLoc.setModuleContext(module);
VariableWithValue varWval
= new VariableWithValue(servicesTracker, null, var);
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
index fd3daa6..1790a82 100644
--- 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
@@ -22,6 +22,7 @@ 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.internal.symbols.IRuntimeType;
import org.eclipse.cdt.debug.edc.symbols.IType;
import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
@@ -61,16 +62,17 @@ public class FieldReference extends CompoundInstruction {
if (operand == null)
return;
- IType variableType = TypeUtils.getStrippedType(operand.getValueType());
+ IType originalVariableType = TypeUtils.getStrippedType(operand.getValueType());
+ IType variableType = originalVariableType;
IVariableLocation location = null;
boolean referenceType = variableType instanceof IReferenceType;
+ boolean pointerType = variableType instanceof IPointerType;
if (refExpression.isPointerDereference()) {
// '->' operator requires a pointer type
- boolean validPointerType = variableType instanceof IPointerType;
-
- if (!validPointerType) {
+
+ if (!pointerType) {
throw EDCDebugger.newCoreException(ASTEvalMessages.FieldReference_InvalidPointerDeref);
}
@@ -115,7 +117,10 @@ public class FieldReference extends CompoundInstruction {
// pointer with '->' operator, or reference with '.'
location = VariableLocationFactory.createMemoryVariableLocation(
fInterpreter.getServicesTracker(), fInterpreter.getContext(),
- operand.getValue());
+ ((referenceType || pointerType) ?
+ Long.valueOf(operand.getValue().longValue()
+ + ((IRuntimeType)originalVariableType).getRuntimeOffset())
+ : operand.getValue()));
} else {
// '.' operator
location = operand.getValueLocation();
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
index 4c1f78d..258fd42 100644
--- 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
@@ -20,13 +20,16 @@ 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.core.model.ICWatchpoint2;
import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
import org.eclipse.cdt.debug.edc.internal.EDCTrace;
+import org.eclipse.cdt.debug.edc.internal.symbols.IBasicType;
+import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
import org.eclipse.cdt.debug.edc.internal.symbols.InvalidVariableLocation;
-import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
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.symbols.IDebugInfoProvider;
+import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
import org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider.ILineAddresses;
import org.eclipse.cdt.debug.edc.symbols.IType;
import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
@@ -48,6 +51,7 @@ import org.eclipse.cdt.utils.Addr64;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
@@ -68,26 +72,35 @@ public class BreakpointAttributeTranslator implements IBreakpointAttributeTransl
assert targetEnvService != null;
}
+ /**
+ * This method decides whether we need to re-install the breakpoint
+ * based on the attributes change (refer to caller in BreakpointsMediator).
+ * <p>
+ * For EDC, following changed attributes justify re-installation.<br>
+ * - {@link IMarker#LINE_NUMBER}<br>
+ * - {@link IBreakpoint#ENABLED}<br>
+ * - {@link ICLineBreakpoint#FUNCTION}<br>
+ * - {@link ICLineBreakpoint#ADDRESS}<br>
+ * - {@link ICWatchpoint#EXPRESSION}<br>
+ * - {@link ICWatchpoint#READ}<br>
+ * - {@link ICWatchpoint#WRITE}<br>
+ * - {@link ICWatchpoint2#RANGE}<br>
+ */
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
+ 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
+ || 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
+ || delta.containsKey(ICWatchpoint2.RANGE)) { // Watchpoint size
return false;
}
@@ -189,7 +202,89 @@ public class BreakpointAttributeTranslator implements IBreakpointAttributeTransl
return new HashMap<String, Object>(platformBPAttrDelta);
}
- public void resolveBreakpoint(IBreakpointsTargetDMContext context, IBreakpoint breakpoint,
+ private IAddress getWatchpointLocAddress(IVariableLocation wpLoc) {
+ return (wpLoc != null && !(wpLoc instanceof InvalidVariableLocation))
+ ? wpLoc.getAddress() : null;
+ }
+
+ private boolean isValidWatchpointType(IType t) {
+ return t instanceof IPointerType
+ || (t instanceof IBasicType
+ && ((IBasicType)t).getBaseType() == IBasicType.t_int);
+ }
+
+ private String getWatchpointAddressFromValue(IEDCExpression expr, IType exprType) {
+ String result = null;
+ if (isValidWatchpointType(exprType)) {
+ result = expr.getEvaluatedValueString();
+ if (result.startsWith("0x"))
+ result.substring(2);
+ }
+ return result;
+ }
+
+ private Map<String, Object> setWatchpointAttrs(String wpAddr, IType type,
+ Map<String, Object> allAttr) {
+ Map<String,Object> wpAttr = new HashMap<String, Object>(allAttr);
+ wpAttr.put(Breakpoints.RUNTIME_ADDRESS, wpAddr);
+ Object range = wpAttr.get(CWatchpoint.RANGE);
+ if (range instanceof String) {
+ range = new Integer((String)range);
+ wpAttr.put(CWatchpoint.RANGE, range); // even if 0, avoid classCastException later
+ }
+ if (type != null && (range == null
+ || (range instanceof Number && ((Number)range).equals(0)))) {
+ wpAttr.put(CWatchpoint.RANGE, type.getByteSize());
+ }
+ return wpAttr;
+ }
+
+ private static IStatus warningStatus(String format, Object ... arguments) {
+ return new Status(IStatus.WARNING, EDCDebugger.PLUGIN_ID,
+ MessageFormat.format(format, arguments));
+ }
+
+ /**
+ * if the module's symbolReader is an EDCSymbolReader, and points
+ * to a debugInfoProvider that will give us files to compare to,
+ * see if the file of interest is in the given module context,
+ * and set a breakpoint problem marker if so.
+ * @param icBP should be a CLineBreakpoint
+ * @param context should be a Module-context
+ * @param bpFile full-path to file CLineBreakpoint occurs in
+ * @param statusMessage the warning message for the marker
+ */
+ private void addBreakpointProblemMarker(final ICBreakpoint icBP,
+ final IBreakpointsTargetDMContext context, final String bpFile,
+ final String statusMessage) {
+ Modules.ModuleDMC module = (Modules.ModuleDMC)context;
+ IEDCSymbolReader reader = module.getSymbolReader();
+ if (! (reader instanceof EDCSymbolReader))
+ return;
+
+ IDebugInfoProvider debugInfoProvider
+ = ((EDCSymbolReader)reader).getDebugInfoProvider();
+ if (debugInfoProvider == null)
+ return;
+
+ String[] sourceFiles = debugInfoProvider.getSourceFiles(new NullProgressMonitor());
+ if (sourceFiles == null)
+ return;
+
+ for (String file : sourceFiles) {
+ if (file.equals(bpFile)) {
+ Breakpoints bkptService
+ = dsfServicesTracker.getService(Breakpoints.class);
+ IBreakpointDMContext targetBP
+ = bkptService.getTargetBreakpoint(icBP, context);
+ bkptService.addBreakpointProblemMarker(targetBP, statusMessage,
+ IMarker.SEVERITY_WARNING, icBP);
+ return;
+ }
+ }
+ }
+
+ public void resolveBreakpoint(final IBreakpointsTargetDMContext context, final 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);
@@ -218,53 +313,43 @@ public class BreakpointAttributeTranslator implements IBreakpointAttributeTransl
EDCServicesMessages
.BPAttrTranslator_WatchptNoExprService,
wpExpr)));
- drm.done();
} else {
IEDCExpression exprDMC
= (IEDCExpression)expressions.createExpression(module, wpExpr);
exprDMC.evaluateExpression();
+
+ /*
+ * first, try to get the address as a variable location;
+ * if that fails, try to evaluate it as a value to be
+ * used as an address at which to set the watchpoint.
+ */
+
IVariableLocation varLoc = exprDMC.getEvaluatedLocation();
- IAddress wpAddr;
- if (varLoc == null || varLoc instanceof InvalidVariableLocation
- || (wpAddr = varLoc.getAddress()) == null) {
- drm.setStatus(
- new Status(IStatus.WARNING, EDCDebugger.PLUGIN_ID,
- MessageFormat.format(
- EDCServicesMessages
- .BPAttrTranslator_WatchptLocationInvalid,
- wpExpr, module.getName())));
+ IAddress wpAddr = getWatchpointLocAddress(varLoc);
+ IType wpType = TypeUtils.getStrippedType(exprDMC.getEvaluatedType());
+
+ String wpAddrString;
+ if (wpAddr != null) {
+ wpAddrString = wpAddr.toString(16);
} else {
- boolean wpValidForModule = module.containsAddress(wpAddr);
- if (!wpValidForModule
- && varLoc.getContext() instanceof Stack.StackFrameDMC) {
- Stack.StackFrameDMC frame
- = (Stack.StackFrameDMC)varLoc.getContext();
- wpValidForModule = module == frame.getModule();
+ wpAddrString = getWatchpointAddressFromValue(exprDMC, wpType);
+ if (wpAddrString != null) {
+ wpAddr = new Addr64(wpAddrString);
+ if (wpAddr != null) // guarantees value was well-formed addr
+ wpAddrString = wpAddr.toString(16); // guarantees base16
}
+ }
- String wpAddrString = wpAddr.toString(16);
- // used in both parts of "if (...) {...} else {...}" below
-
- if (wpValidForModule) {
- IType exprType
- = TypeUtils.getStrippedType(exprDMC.getEvaluatedType());
- Map<String,Object> wpAttr
- = new HashMap<String, Object>(attributes);
- wpAttr.put(Breakpoints.RUNTIME_ADDRESS, wpAddrString);
- wpAttr.put(CWatchpoint.RANGE, exprType.getByteSize());
- targetBPAttrs.add(wpAttr);
- drm.setData(targetBPAttrs);
- } else {
- drm.setStatus(
- new Status(IStatus.WARNING, EDCDebugger.PLUGIN_ID,
- MessageFormat.format(
- EDCServicesMessages
- .BPAttrTranslator_WatchptNotInModule,
- wpExpr, wpAddrString, module.getName())));
- }
+ if (wpAddr != null) {
+ targetBPAttrs.add(setWatchpointAttrs(wpAddrString, wpType, attributes));
+ drm.setData(targetBPAttrs);
+ } else {
+ drm.setStatus(
+ warningStatus(EDCServicesMessages.BPAttrTranslator_WatchptLocationInvalid,
+ wpExpr, module.getName()));
}
- drm.done();
}
+ drm.done();
} else {
String bpType = (String)attributes.get(Breakpoints.BREAKPOINT_SUBTYPE);
if (bpType.equals(Breakpoints.ADDRESS_BREAKPOINT)) {
@@ -284,10 +369,8 @@ public class BreakpointAttributeTranslator implements IBreakpointAttributeTransl
drm.setData(targetBPAttrs);
} else {
drm.setStatus(
- new Status(IStatus.WARNING, EDCDebugger.PLUGIN_ID,
- MessageFormat.format(
- EDCServicesMessages.BPAttrTranslator_BkptAddressNotInModule,
- addr, module.getName())));
+ warningStatus(EDCServicesMessages.BPAttrTranslator_BkptAddressNotInModule,
+ addr, module.getName()));
}
drm.done();
@@ -322,20 +405,19 @@ public class BreakpointAttributeTranslator implements IBreakpointAttributeTransl
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,
+ modulesService.findClosestLineWithCode(sym_dmc, bpFile, line, 5,
new DataRequestMonitor<ILineAddresses>(dsfSession.getExecutor(), drm) {
@Override
protected void handleCompleted() {
if (! isSuccess()) {
- drm.setStatus(getStatus());
+ final IStatus status = getStatus();
+ addBreakpointProblemMarker(icBP, context, bpFile, status.getMessage());
+ drm.setStatus(status);
drm.done();
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null,
"findClosestLineWithCode failed: " + drm.getStatus()); }
@@ -361,12 +443,10 @@ public class BreakpointAttributeTranslator implements IBreakpointAttributeTransl
}
drm.setData(targetBPAttrs);
-
+
int actualCodeLine = codeLine.getLineNumber();
- if (actualCodeLine == line)
- drm.done();
- else {
+ if (actualCodeLine != line) {
// 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.
@@ -402,12 +482,11 @@ public class BreakpointAttributeTranslator implements IBreakpointAttributeTransl
// 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();
}
}
+ drm.done();
}
});
}
@@ -489,14 +568,14 @@ public class BreakpointAttributeTranslator implements IBreakpointAttributeTransl
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.
- */
+ /**
+ * 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();
@@ -529,4 +608,3 @@ public class BreakpointAttributeTranslator implements IBreakpointAttributeTransl
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
index a41918a..561ee12 100644
--- 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
@@ -12,6 +12,7 @@ package org.eclipse.cdt.debug.edc.internal.services.dsf;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.IllegalFormatException;
@@ -43,6 +44,7 @@ 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.debug.internal.core.breakpoints.CWatchpoint;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Immutable;
@@ -52,7 +54,6 @@ 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;
@@ -152,7 +153,51 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
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>();
+ private final Map<IBreakpointDMContext, BreakpointDMData> userBreakpoints
+ = Collections.synchronizedMap(new HashMap<IBreakpointDMContext, BreakpointDMData>());
+
+ private static class RuntimeWatchpoint {
+ final IExecutionDMContext context;
+ final String address;
+ final Number size;
+ RuntimeWatchpoint(IExecutionDMContext exeDMC, String addr, Number range) {
+ context = exeDMC;
+ address = addr;
+ size = range;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + context.hashCode();
+ result = prime * result + address.hashCode();
+ result = prime * result + size.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ RuntimeWatchpoint other = (RuntimeWatchpoint) obj;
+ if (!context.equals(other.context))
+ return false;
+ if (!address.equals(other.address))
+ return false;
+ if (!size.equals(other.size))
+ return false;
+ return true;
+ }
+ }
+
+ /** a map of breakpoints to enabled watchpoints */
+ private final Map<IBreakpointDMContext, RuntimeWatchpoint> enabledWatchpoints
+ = Collections.synchronizedMap(new HashMap<IBreakpointDMContext, RuntimeWatchpoint>());
/**
* Internal temporary breakpoints set by debugger for stepping.
@@ -362,16 +407,21 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
@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;
+ String s = getBreakpointType();
+ boolean w = s.equals(WATCHPOINT);
+ String e = w ? getExpression() : null;
+ String f = getFileName();
+ if (f == null && e == null) // address breakpoint/watchpoint
+ s += "@" + getAddresses()[0].toHexAddressString();
+ else if (w)
+ s += ": expression \"" + e
+ + ((f != null ) ? "\"; File: " + f : "\"");
+ else if (getFunctionName() != null)
+ s += "@" + f + ": " + getFunctionName();
+ else
+ s += "@" + f + ":line " + getLineNumber();
+
+ return s;
}
public void incrementHitCount() {
@@ -534,6 +584,9 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
return;
for (BreakpointDMData edcBp : userBreakpoints.values()) {
+ String bpType = edcBp.getBreakpointType();
+ if (bpType != null && bpType.equals(WATCHPOINT))
+ continue;
// TODO: bail out if the bp is not software breakpoint.
IAddress bpAddr = edcBp.getAddresses()[0];
@@ -648,10 +701,15 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
IExecutionDMContext exe_dmc = DMContexts.getAncestorOfType(context, IExecutionDMContext.class);
String bpAddr = (String)attributes.get(RUNTIME_ADDRESS);
+ Number range = (Number)attributes.get(CWatchpoint.RANGE);
assert exe_dmc != null : "DMContext is unknown in addWatchpoint().";
assert bpAddr != null;
-
+
+ final RuntimeWatchpoint newWatchpoint = new RuntimeWatchpoint(exe_dmc, bpAddr, range);
+ if (enabledWatchpoints.containsValue(newWatchpoint))
+ return;
+
createWatchpoint(exe_dmc, new Addr64(bpAddr, 16), attributes, new DataRequestMonitor<BreakpointDMData>(
getExecutor(), drm) {
@@ -668,6 +726,7 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
// Remember this in our global list.
userBreakpoints.put(bp_dmc, bpd);
+ enabledWatchpoints.put(bp_dmc, newWatchpoint);
drm.done();
}
@@ -831,16 +890,16 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
private void createWatchpoint(final IDMContext dmc, final IAddress address,
final Map<String, Object> allProps,
final DataRequestMonitor<BreakpointDMData> drm) {
- asyncExec(new Runnable() {
- public void run() {
- final long id = getNewBreakpointID();
- final IBreakpointDMContext bp_dmc
- = new BreakpointDMContext(getSession().getId(),
- new IDMContext[] { dmc },
- id);
- final IAddress[] bp_addrs = new IAddress[] { address };
+ if (hasTCFWatchpointSupport()) {
+ asyncExec(new Runnable() {
+ public void run() {
+ final long id = getNewBreakpointID();
+ final IBreakpointDMContext bp_dmc
+ = new BreakpointDMContext(getSession().getId(),
+ new IDMContext[] { dmc },
+ id);
+ final IAddress[] bp_addrs = new IAddress[] { address };
- if (hasTCFWatchpointSupport()) {
final Map<String, Object> tcfProperties = new HashMap<String, Object>();
tcfProperties.put(TCF_BP_ID, Long.toString(id));
tcfProperties.put(TCF_BP_ENABLED, true);
@@ -868,13 +927,15 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
allProps.put(TCF_PROPERTIES, tcfProperties);
drm.setData(new BreakpointDMData(id, bp_dmc, bp_addrs, allProps));
- } else { // generic software watchpoint? i don't think so, tim!
- drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
- "Watchpoints not supported for this system", null));
- }
- drm.done();
- }
- }, drm);
+ drm.done();
+
+ }}, drm);
+
+ } else { // generic software watchpoint? i don't think so, tim!
+ drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
+ "Watchpoints not supported for this system", null));
+ drm.done();
+ }
}
@@ -1025,6 +1086,7 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
// Remove it from our record.
userBreakpoints.remove(dmc);
+ enabledWatchpoints.remove(dmc);
// Remove problem marker if any.
// Note this may be called when the debug session is shut down.
@@ -1069,20 +1131,23 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
}
+ /**
+ * 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 {@link BreakpointAttributeTranslator#canUpdateAttributes(IBreakpoints.IBreakpointDMContext, Map)}
+ */
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())
+ for (String key : delta.keySet()) {
existingProps.put(key, delta.get(key));
+ if (key.equals(ICBreakpoint.CONDITION))
+ removeBreakpointProblemMarker(dmc);
+ }
}
rm.done();
}
@@ -1315,25 +1380,39 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
BreakpointsMediator2 bmService = getService(BreakpointsMediator2.class);
if (bmService == null)
return;
-
+
final IBreakpoint breakpoint = bmService.getPlatformBreakpoint(null, targetBP);
if (breakpoint == null)
return;
+ addBreakpointProblemMarker(targetBP, description, severity, breakpoint);
+ }
+
+ protected IBreakpointDMContext getTargetBreakpoint(final IBreakpoint breakpoint,
+ IBreakpointsTargetDMContext bkptTargetDMC) {
+ BreakpointsMediator2 bpm2 = getService(BreakpointsMediator2.class);
+ BreakpointsMediator2.ITargetBreakpointInfo[] targetBPs = bpm2.getTargetBreakpoints(bkptTargetDMC, breakpoint);
+ assert targetBPs == null || targetBPs.length <= 1 : "too many target-breakpoints for platform breakpoint";
+ return targetBPs != null ? targetBPs[0].getTargetBreakpoint() : null;
+ }
+
+ protected void addBreakpointProblemMarker(final IBreakpointDMContext targetBP,
+ final String description, final int severity, final IBreakpoint breakpoint) {
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(targetBP);
- if (marker != null) {
- try {
- marker.delete();
- } catch (CoreException e) {
- }
+ if (targetBP != null) {
+ IMarker marker = fBreakpointMarkers.remove(targetBP);
+ if (marker != null) {
+ try {
+ marker.delete();
+ } catch (CoreException e) {
+ }
+ }
}
ICLineBreakpoint lineBreakpoint = (ICLineBreakpoint) breakpoint;
@@ -1350,8 +1429,8 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
problem_marker.setAttribute(IMarker.SEVERITY, severity);
problem_marker.setAttribute(IMarker.LINE_NUMBER, line_number);
- // And save the baby
- fBreakpointMarkers.put(targetBP, problem_marker);
+ if (targetBP != null)
+ fBreakpointMarkers.put(targetBP, problem_marker);
} catch (CoreException e) {
}
@@ -1359,7 +1438,7 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
}
}.schedule();
}
-
+
/**
* Remove problem marker added for the given target breakpoint.
* Note this may be called when debug session is shutdown.
@@ -1406,6 +1485,7 @@ public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDS
public void evaluateBreakpointCondition(IExecutionDMContext context, final BreakpointDMData bp, final DataRequestMonitor<Object> drm) {
final String expr = bp.getCondition();
if (expr == null || expr.length() == 0) {
+ removeBreakpointProblemMarker(bp.getContext());
bp.incrementHitCount();
drm.setData(bp.getHitCount() > bp.getIgnoreCount() ? bp : false);
drm.done();
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
index 52d1e35..a53d21d 100644
--- 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
@@ -39,7 +39,9 @@ public class EDCServicesMessages extends NLS {
public static String BPAttrTranslator_WatchptNoExprService;
- public static String BPAttrTranslator_WatchptNotInModule;
+ public static String Modules_CannotMoveBreakpoint;
+
+ public static String Modules_CannotFindBreakpointSource;
static {
// initialize resource bundle
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
index 29f43cd..1c1c9f3 100644
--- 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
@@ -21,4 +21,6 @@ BPAttrTranslator_BkptAddressNotInModule=Address breakpoint at {0} does not fall
BPAttrTranslator_WatchptLocationInvalid=Cannot get address for expression "{0}" in module [{1}].
BPAttrTranslator_WatchptNoContext=Cannot evaluate expression "{0}"; context unavailable.
BPAttrTranslator_WatchptNoExprService=Cannot evaluate expression "{0}"; EDC Expression service unavailable.
-BPAttrTranslator_WatchptNotInModule=Watchpoint for expression "{0}" at address {1} does not fall in the module [{2}].
+
+Modules_CannotMoveBreakpoint=Unable to find address within {0} source lines of breakpoint in file {1} at line {2}
+Modules_CannotFindBreakpointSource=Unable to find address for source in file {0} at line {1}
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
index 2e9319a..7853025 100644
--- 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
@@ -1,1502 +1,1550 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2010, 2011 Nokia and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, 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.services.dsf.Modules.ModuleDMC;
-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.IDebugInfoProvider;
-import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
-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.TypeEngine;
-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.IModules.IModuleDMContext;
-import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
-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.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
-
-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) {
- // use the full expression in the id as their hashcode is based on
- // id, so they must be unique
- super(Expressions.this, new IDMContext[] { parent }, name,
- ((IEDCDMContext)parent).getID() + '.' + expression);
- this.expression = expression;
- frame = DMContexts.getAncestorOfType(parent, StackFrameDMC.class);
- engine = initEngine(parent);
- }
-
- private ASTEvaluationEngine initEngine(IDMContext parent) {
- if (frame != null)
- return new ASTEvaluationEngine(getEDCServicesTracker(), frame,
- frame.getTypeEngine());
-
- if (parent instanceof ModuleDMC) {
- IEDCSymbolReader edcSymbolReader = ((ModuleDMC)parent).getSymbolReader();
- if (edcSymbolReader instanceof EDCSymbolReader) {
- IDebugInfoProvider debugInfoProvider
- = ((EDCSymbolReader)edcSymbolReader).getDebugInfoProvider();
- TypeEngine typeEngine
- = new TypeEngine(getTargetEnvironmentService(), debugInfoProvider);
- return new ASTEvaluationEngine(getEDCServicesTracker(), parent, typeEngine);
- }
- }
-
- return null;
- }
-
- 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);
- } else if (context instanceof IModuleDMContext) {
- return new ExpressionDMC(context, 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());
-
- // Try to resolve opaque pointer.
- // Note this may take some time depending on symbol file size.
- // ........05/19/11
- //
- if (TypeUtils.isOpaqueType(typePointedTo)) {
- final Symbols symService = getService(Symbols.class);
- assert symService != null;
-
- final ISymbolDMContext symCtx = DMContexts.getAncestorOfType(expr, ISymbolDMContext.class);
- if (symCtx != null) {
- final ICompositeType[] resolved = {null};
- final IType original = typePointedTo;
- Job j = new Job("Resolving opaque type" + original.getName()) {
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- monitor.beginTask("Resolving opaque type: " + original.getName(), IProgressMonitor.UNKNOWN);
- resolved[0] = symService.resolveOpaqueType(symCtx, (ICompositeType)original);
- monitor.done();
- return Status.OK_STATUS;
- }};
-
- j.schedule();
- try {
- j.join();
- } catch (InterruptedException e) {
- // ignore
- }
-
- if (resolved[0] != null) {
- typePointedTo = resolved[0];
-
- // Make the pointer type points to the resolved type
- // so that we won't need to resolve the opaque type again
- // and again.
- exprType.setType(resolved[0]);
- }
- }
- }
-
- // 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 (CoreException e) {
- // Checked exception like failure in reading memory. just re-throw
- // it so it shows up in the variables view.
- throw e;
- } catch (Throwable t) {
- // 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);
- }
- }});
- }
- }
-}
+/*******************************************************************************
+ * Copyright (c) 2009, 2010, 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, 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.services.dsf.Modules.ModuleDMC;
+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.IRuntimeType;
+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.IDebugInfoProvider;
+import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
+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.TypeEngine;
+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.IModules.IModuleDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+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.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+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) {
+ // use the full expression in the id as their hashcode is based on
+ // id, so they must be unique
+ super(Expressions.this, new IDMContext[] { parent }, name,
+ ((IEDCDMContext)parent).getID() + '.' + expression);
+ this.expression = expression;
+ frame = DMContexts.getAncestorOfType(parent, StackFrameDMC.class);
+ engine = initEngine(parent);
+ }
+
+ private ASTEvaluationEngine initEngine(IDMContext parent) {
+ if (frame != null)
+ return new ASTEvaluationEngine(getEDCServicesTracker(), frame,
+ frame.getTypeEngine());
+
+ if (parent instanceof ModuleDMC) {
+ IEDCSymbolReader edcSymbolReader = ((ModuleDMC)parent).getSymbolReader();
+ if (edcSymbolReader instanceof EDCSymbolReader) {
+ IDebugInfoProvider debugInfoProvider
+ = ((EDCSymbolReader)edcSymbolReader).getDebugInfoProvider();
+ TypeEngine typeEngine
+ = new TypeEngine(getTargetEnvironmentService(), debugInfoProvider);
+ return new ASTEvaluationEngine(getEDCServicesTracker(), parent, typeEngine);
+ }
+ }
+
+ return null;
+ }
+
+ 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();
+
+ // if the location is invalid, 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;
+ }
+
+ try {
+ value = variableValue.getValue();
+ valueString = variableValue.getStringValue();
+ } catch (CoreException e1) {
+ value = null;
+ valueError = e1.getStatus();
+ return;
+ }
+
+ valueType = variableValue.getValueType();
+
+ // 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;
+ } else if (valueType instanceof IRuntimeType
+ && valueLocation != null
+ && EDCDebugger.getResolveRttiTypes()) {
+ value = Long.valueOf(value.longValue() + ((IRuntimeType)valueType).getRuntimeOffset());
+ }
+ }
+
+ /* (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);
+ } else if (context instanceof IModuleDMContext) {
+ return new ExpressionDMC(context, 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) {
+
+ if ( !(exprContext instanceof IEDCExpression)) {
+ rm.setData(0);
+ rm.done();
+ return;
+ }
+
+ asyncExec(new Runnable() {
+ public void run() {
+ final IEDCExpression expr = (IEDCExpression) exprContext;
+
+ // handle array casts
+ CastInfo cast = null;
+ if ((cast = expr.getCastInfo()) != null) {
+ if (cast.getArrayCount() > 0) {
+ if (expr.getEvaluationError() != null) {
+ rm.setData(0);
+ rm.done();
+ return;
+ }
+ rm.setData(cast.getArrayCount());
+ rm.done();
+ return;
+ }
+ }
+
+ // 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) {
+
+ if (!(exprContext instanceof IEDCExpression)
+ || ((IEDCExpression) exprContext).getFrame() == null) {
+ rm.setData(new IEDCExpression[0]);
+ rm.done();
+ return;
+ }
+
+ asyncExec(new Runnable() {
+ public void run() {
+
+ final 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());
+
+ // Try to resolve opaque pointer.
+ // Note this may take some time depending on symbol file size.
+ // ........05/19/11
+ //
+ if (TypeUtils.isOpaqueType(typePointedTo) && resolveOpaqueType(expr)) {
+ final Symbols symService = getService(Symbols.class);
+ assert symService != null;
+
+ final ISymbolDMContext symCtx = DMContexts.getAncestorOfType(expr, ISymbolDMContext.class);
+ if (symCtx != null) {
+ final ICompositeType[] resolved = {null};
+ final IType original = typePointedTo;
+ Job j = new Job("Resolving opaque type: " + original.getName()
+ + " for expression " + exprName) {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ monitor.beginTask("Resolving opaque type: " + original.getName(), IProgressMonitor.UNKNOWN);
+ resolved[0] = symService.resolveOpaqueType(symCtx, (ICompositeType)original, monitor);
+ monitor.done();
+ return Status.OK_STATUS;
+ }};
+
+ j.schedule();
+ try {
+ j.join();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
+ if (resolved[0] != null) {
+ typePointedTo = resolved[0];
+
+ // Make the pointer type points to the resolved type
+ // so that we won't need to resolve the opaque type again
+ // and again.
+ exprType.setType(resolved[0]);
+ }
+ }
+ }
+
+ // 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 = null;
+ 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) {
+ IDMContext idmContext = formattedDataContext.getParents()[0];
+
+ if (! (idmContext instanceof IEDCExpression)) {
+ rm.setData(new FormattedValueDMData("")); //$NON-NLS-1$)
+ rm.done();
+ return;
+ }
+
+ asyncExec(new Runnable() {
+ public void run() {
+ try {
+ rm.setData(getFormattedExpressionValue(formattedDataContext));
+ rm.done();
+ } catch (CoreException ce) {
+ rm.setStatus(ce.getStatus());
+ rm.done();
+ }
+ }
+ }, rm);
+ }
+
+ public String getExpressionValueString(IExpressionDMContext expression, String format) throws CoreException {
+ FormattedValueDMContext formattedDataContext = getFormattedValueContext(expression, format);
+ FormattedValueDMData formattedValue = getFormattedExpressionValue(formattedDataContext);
+
+ return formattedValue != null ? formattedValue.getFormattedValue() : "";
+ }
+
+ private 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 (CoreException e) {
+ // Checked exception like failure in reading memory. just re-throw
+ // it so it shows up in the variables view.
+ throw e;
+ } catch (Throwable t) {
+ // 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) {
+ }
+
+// TODO for separate pref for snapshots 2 functions and their uses in snapshotValues() below
+// private static void addSnapshotProperties(IExpressionDMContext expr) {
+// if (expr instanceof IEDCExpression)
+// ((IEDCExpression)expr).setProperty(Album.PREF_RESOLVE_OPAQUE_TYPE,
+// new Boolean(Album.getResolveOpaqueType()));
+// }
+//
+// private static void removeSnapshotProperties(IExpressionDMContext expr) {
+// if (expr instanceof IEDCExpression) {
+// Map<String, Object> props = ((IEDCExpression)expr).getProperties();
+// if (props != null)
+// props.remove(Album.PREF_RESOLVE_OPAQUE_TYPE);
+// }
+// }
+
+ /**
+ * @param expr ignored for now
+ * @return true if the user has set the pref in the EDC Debugger pref panel
+ */
+ private static boolean resolveOpaqueType(IExpressionDMContext expr) {
+// TODO for separate pref for snapshots, uncomment the following
+// if (EDCDebugger.getResolveOpaqueType())
+// return true;
+// if (! (expr instanceof IEDCExpression) )
+// return false;
+// Object snapshotOpaquePointerDereference
+// = ((IEDCExpression)expr).getProperty(Album.PREF_RESOLVE_OPAQUE_TYPE);
+// if (! (snapshotOpaquePointerDereference instanceof Boolean))
+// return false;
+// return (Boolean)snapshotOpaquePointerDereference;
+ return EDCDebugger.getResolveOpaqueTypes();
+ }
+
+ private String snapshotValue(final IExpressionDMContext expr) {
+ final StringBuffer holder = new StringBuffer();
+ FormattedValueDMContext snapshotValueContext
+ = getFormattedValueContext(expr, IFormattedValues.NATURAL_FORMAT);
+ getFormattedExpressionValue(snapshotValueContext,
+ new DataRequestMonitor<FormattedValueDMData>(
+ ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess())
+ holder.append(this.getData().getFormattedValue());
+
+ // RequestMonitor would, by default, log any error if it's not
+ // explicitly handled. But during snapshot creation, we don't
+ // want to have to log those expected errors (checked exceptions)
+ // so, if (!isSuccess), do nothing.
+ }
+ });
+ return holder.toString();
+ }
+
+ public void snapshotValues(IExpressionDMContext expression, int depth) {
+ snapshotValues(expression, new Integer[] {depth});
+ }
+
+ private void snapshotValues(final IExpressionDMContext expression,
+ final Integer[] depth) {
+// addSnapshotProperties(expression); // TODO for separate pref for snapshots
+ snapshotValue(expression);
+ if (depth[0] <= 0)
+ return;
+
+ getSubExpressions(expression, new DataRequestMonitor<IExpressions.IExpressionDMContext[]>(
+ ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleSuccess() {
+ --depth[0];
+ if (isSuccess()) {
+ IExpressionDMContext[] subExpressions = getData();
+ for (IExpressionDMContext iExpressionDMContext : subExpressions)
+ snapshotValues(iExpressionDMContext, depth);
+ }
+ }});
+// removeSnapshotProperties(expression); // TODO for separate pref for snapshots
+ }
+}
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
index 4e0fa7b..d5a055c 100644
--- 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
@@ -1,1219 +1,1426 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2010, 2011 Nokia and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Nokia - Initial API and implementation
- * Broadcom - Process physical address in RuntimeSection for snapshots
- *******************************************************************************/
-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.EDCServicesTracker;
-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;
-
- 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 }, getModuleID(props), props);
- this.symbolContext = symbolContext;
-
- String filename = "";
- if (props.containsKey(IModuleProperty.PROP_FILE))
- filename = (String) props.get(IModuleProperty.PROP_FILE);
-
- hostFilePath = locateModuleFileOnHost(filename);
- }
-
- public EDCServicesTracker getEDCServicesTracker() {
- return Modules.this.getEDCServicesTracker();
- }
-
- 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));
- String physicalAddressString = sectionElement.getAttribute(ISection.PROPERTY_PHYSICAL_ADDRESS);
- IAddress physicalAddress;
- if (physicalAddressString != null && physicalAddressString.length() > 0) {
- physicalAddress = new Addr64(physicalAddressString);
- } else {
- physicalAddress = null;
- }
- 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, physicalAddress, 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());
- IAddress physicalAddress = s.getPhysicalAddress();
- if (physicalAddress != null) {
- sectionElement.setAttribute(ISection.PROPERTY_PHYSICAL_ADDRESS, physicalAddress.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) {
- moduleList.remove(module);
- }
- }
- }
- }
-
- /*
- * 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()]);
- }
- }
-
- 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) {
- String moduleID = getModuleID(moduleProps); // the moduleProps comes from agent.
- ModuleDMC module = getModuleByID(symbolContext, moduleID);
- if (module == null) {
- EDCDebugger.getMessageLogger().logError("Unexpected unload of module: " + moduleProps, null);
- return;
- }
- System.out.println("module: " + module.toString());
- 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);
-
- }
-
- private static String getModuleID(Map<String, Object> props) {
- if (props.containsKey(IEDCDMContext.PROP_ID))
- return props.get(IEDCDMContext.PROP_ID).toString();
- if (props.containsKey(IModuleProperty.PROP_FILE))
- return props.get(IModuleProperty.PROP_FILE).toString();
- if (props.containsKey(IEDCDMContext.PROP_NAME))
- return props.get(IEDCDMContext.PROP_NAME).toString();
- assert(false); // One of these is required
- return "";
- }
-
- /**
- * 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;
- }
-
- private ModuleDMC getModuleByID(ISymbolDMContext symCtx, String id) {
- ModuleDMC module = null;
- synchronized (modules) {
- List<ModuleDMC> moduleList = modules.get(((IEDCDMContext) symCtx).getID());
- if (moduleList != null) {
- for (ModuleDMC moduleDMC : moduleList) {
- if ((moduleDMC.getID().compareToIgnoreCase(id)) == 0 ) {
- module = moduleDMC;
- break;
- }
- }
- }
- }
- return module;
- }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009, 2010, 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ * Broadcom - Process physical address in RuntimeSection for snapshots
+ *******************************************************************************/
+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.PersistentCache;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ThreadExecutionDMC;
+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.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.EDCServicesTracker;
+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.Stack;
+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.debug.edc.symbols.IEDCSymbolReader;
+import org.eclipse.cdt.debug.edc.symbols.ILineEntryProvider.ILineAddresses;
+import org.eclipse.cdt.debug.edc.symbols.IModuleLineEntryProvider;
+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.debug.service.IStack;
+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.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";
+
+ private static final String PROP_SYMBOLS_LOADED = "PROP_SYMBOLS_LOADED";
+
+ /**
+ * 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;
+
+ /**
+ * Report problems loading symbols for modules by default, but allow subclasses
+ * to override this.
+ */
+ protected boolean reportReaderProblems = true;
+
+
+ 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;
+ }
+
+ // necessary so we can perform meaningful .contains() checks on lists of ranges
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null)
+ return false;
+ if (getClass() != o.getClass())
+ return false;
+ EDCAddressRange other = (EDCAddressRange)o;
+ return startAddr.equals(other.startAddr) && endAddr.equals(other.endAddr);
+ }
+ }
+
+ 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 }, getModuleID(props), props);
+ this.symbolContext = symbolContext;
+
+ String filename = "";
+ if (props.containsKey(IModuleProperty.PROP_FILE))
+ filename = (String) props.get(IModuleProperty.PROP_FILE);
+
+ hostFilePath = locateModuleFileOnHost(filename);
+ }
+
+ public EDCServicesTracker getEDCServicesTracker() {
+ return Modules.this.getEDCServicesTracker();
+ }
+
+ public ISymbolDMContext getSymbolContext() {
+ return symbolContext;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.debug.edc.services.IEDCModuleDMContext#getSymbolReader()
+ */
+ public IEDCSymbolReader getSymbolReader() {
+ return symReader;
+ }
+
+ public IEDCSymbolReader getSymbolReader(boolean create) {
+ if (symReader == null && create) {
+ // clear any dummy sections and relocate
+ runtimeSections.clear();
+ relocateSections(properties, true);
+ }
+ 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));
+ String physicalAddressString = sectionElement.getAttribute(ISection.PROPERTY_PHYSICAL_ADDRESS);
+ IAddress physicalAddress;
+ if (physicalAddressString != null && physicalAddressString.length() > 0) {
+ physicalAddress = new Addr64(physicalAddressString);
+ } else {
+ physicalAddress = null;
+ }
+ 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, physicalAddress, 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());
+ IAddress physicalAddress = s.getPhysicalAddress();
+ if (physicalAddress != null) {
+ sectionElement.setAttribute(ISection.PROPERTY_PHYSICAL_ADDRESS, physicalAddress.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);
+ }
+ 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, boolean loadSymbols) {
+
+ if (loadSymbols) {
+ 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) {
+ if (reportReaderProblems) {
+ EDCDebugger.getMessageLogger().log(IStatus.WARNING,
+ MessageFormat.format("''{0}'' has no recognized file format.",
+ hostFilePath), null);
+ }
+ } else if (! symReader.hasRecognizedDebugInformation()) {
+ if (reportReaderProblems) {
+ // Log as INFO, not ERROR.
+ EDCDebugger.getMessageLogger().log(IStatus.INFO,
+ MessageFormat.format("''{0}'' has no recognized symbolics.",
+ hostFilePath), null);
+ }
+ } else {
+ // set property that symbols are loaded
+ properties.put(PROP_SYMBOLS_LOADED, Boolean.TRUE);
+ }
+ } else {
+ // Binary file not on host. Do we want to prompt user for one ?
+
+ if (reportReaderProblems) {
+ // 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;
+ }
+
+ public IPath getHostFilePath() {
+ return hostFilePath;
+ }
+ }
+
+ 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() {
+ Object loaded = properties.get(PROP_SYMBOLS_LOADED);
+ if (loaded != null && loaded instanceof Boolean) {
+ return ((Boolean) loaded).booleanValue();
+ }
+
+ 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;
+ }
+
+ protected 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) {
+ moduleList.remove(module);
+ }
+ }
+ }
+ }
+
+ /**
+ * The result AddressRange[] will contain absolute runtime addresses. And
+ * the "symCtx" can be a process or a module.
+ */
+ 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;
+ }
+
+ if (!calcAddressRanges(moduleList, file, line, true, rm)) {
+ /*
+ * 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(
+ EDCServicesMessages.Modules_CannotFindBreakpointSource,
+ file, line), null));
+ }
+ }
+
+ /**
+ * for use with runToLine/resumeAtLine/moveToLine ... in most cases (and in all
+ * cases for the last two) the location has to be on the stack already,
+ * and since we have the thread-context passed to us, make use of it
+ * @param threadDMC
+ * @param file
+ * @param line
+ * @param col
+ * @param rm
+ */
+ private void calcAddressInfo(ThreadExecutionDMC threadDMC, String file,
+ int line, int col, DataRequestMonitor<AddressRange[]> rm) {
+ // create a set with the modules from the stack on the front
+ Stack stackService = getService(Stack.class);
+ List<IEDCModuleDMContext> framesList
+ = new ArrayList<IEDCModuleDMContext>();
+ IFrameDMContext[] frames = null;
+ try {
+ frames = stackService.getFramesForDMC(threadDMC, 0, IStack.ALL_FRAMES);
+ } catch (CoreException e) {
+ }
+ boolean success = false;
+ IModuleDMContext[] moduleList;
+ if (frames != null && frames.length > 0) {
+ for (IFrameDMContext frame : frames) {
+ if (frame instanceof StackFrameDMC) {
+ IEDCModuleDMContext frameModule
+ = ((StackFrameDMC)frame).getModule();
+ if (!framesList.contains(frameModule))
+ framesList.add(frameModule);
+ }
+ }
+ moduleList = framesList.toArray(new IModuleDMContext[framesList.size()]);
+
+ // 4th arg == false means don't get "all address ranges" for line
+ success = calcAddressRanges(moduleList, file, line, false, rm);
+ // sets rm.done() if returning true
+
+ if (!success)
+ // set a warning, but try other modules
+ rm.setStatus(new Status(IStatus.WARNING, EDCDebugger.PLUGIN_ID,
+ MessageFormat.format(
+ EDCServicesMessages.Modules_CannotFindBreakpointSource,
+ file, line), null));
+ }
+
+ if (!success) {
+ // for runToLine, we still need to get test all addresses in all modules;
+ // so sort the rest for whatever's not on the stack and add them to the end
+ // of the list.
+ ISymbolDMContext symCtx = DMContexts.getAncestorOfType(threadDMC, ISymbolDMContext.class);
+ String symContextID = ((IEDCDMContext) symCtx).getID();
+ List<ModuleDMC> allModulesList = modules.get(symContextID);
+ if (allModulesList != null && allModulesList.size() > 0) {
+ for (int i = allModulesList.size(); i > 0;) {
+ ModuleDMC testModule = allModulesList.get(--i);
+ if (framesList.contains(testModule)
+ || null == testModule.getSymbolReader())
+ allModulesList.remove(i);
+ }
+ moduleList = allModulesList.toArray(new IModuleDMContext[allModulesList.size()]);
+
+ // 4th arg == false means don't get "all address ranges" for line
+ success = calcAddressRanges(moduleList, file, line, false, rm);
+ // sets rm.done() if returning true
+ }
+
+ if (!success) {
+ rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
+ MessageFormat.format(
+ EDCServicesMessages.Modules_CannotFindBreakpointSource,
+ file, line), null));
+ }
+ rm.done();
+ }
+ }
+
+ /**
+ * used by both {@link #calcAddressInfo(IModules.ISymbolDMContext, String, int, int, DataRequestMonitor)}
+ * and {@link #calcAddressInfo(ThreadExecutionDMC, String, int, int, DataRequestMonitor)}
+ * to compute the ranges once the list of modules to search has been determined
+ * @param file
+ * @param line
+ * @param moduleList
+ * @return true if any addresses were calculated
+ */
+ private boolean calcAddressRanges(IModuleDMContext[] moduleList, String file, int line,
+ boolean getAllAddressRanges, DataRequestMonitor<AddressRange[]> rm) {
+
+ List<EDCAddressRange> addrRanges = new ArrayList<EDCAddressRange>(1);
+ IPath originalPath = null, compilationPath = null;
+ for (IModuleDMContext module : moduleList) {
+ ModuleDMC mdmc = (ModuleDMC) module;
+ IEDCSymbolReader reader = mdmc.getSymbolReader();
+
+ if (reader == null)
+ continue;
+
+ 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;
+
+ @SuppressWarnings("unchecked")
+ 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.
+
+ Collection<AddressRange> linkAddressRanges = null;
+
+ @SuppressWarnings("unchecked")
+ Map<String, Collection<AddressRange>> cachedData
+ = EDCDebugger.getDefault().getCache().getCachedData(cacheKey, Map.class, reader.getModificationDate());
+
+ if (cachedData != null) {
+ cachedRanges = cachedData;
+ linkAddressRanges = cachedRanges.get(file + line);
+ }
+
+ IModuleLineEntryProvider lineEntryProvider;
+ if (linkAddressRanges == null) {
+ lineEntryProvider = reader.getModuleScope().getModuleLineEntryProvider();
+
+ // always try the compilationPath first; this mimics the
+ // pre-2011.09.17 behavior, where this was passed in
+ // from getAddressForLine() .
+ if (compilationPath == null)
+ compilationPath
+ = PathUtils.createPath(
+ EDCLaunch.getLaunchForSession(
+ getSession().getId())
+ .getCompilationPath(file));
+ linkAddressRanges
+ = LineEntryMapper.getAddressRangesAtSource(lineEntryProvider,
+ compilationPath, line);
+
+ // if using the compilation path didn't work, try the source-path;
+ // sometimes, that is what gets stuffed in the executable instead
+ // for runToLine/resumeAtLine/moveToLine
+ if (originalPath == null)
+ originalPath = PathUtils.createPath(file);
+ if (linkAddressRanges == null && compilationPath != originalPath) {
+ linkAddressRanges
+ = LineEntryMapper.getAddressRangesAtSource(lineEntryProvider,
+ originalPath, 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()));
+ if (!addrRanges.contains(addrRange)) {
+ addrRanges.add(addrRange);
+ if (!getAllAddressRanges)
+ break;
+ }
+ }
+ }
+
+ if (addrRanges.size() > 0) {
+ AddressRange[] ar = addrRanges.toArray(new AddressRange[addrRanges.size()]);
+ rm.setData(ar);
+ rm.done();
+ return true;
+ }
+
+ return false;
+ }
+
+ 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 bpPath
+ * 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.
+ */
+ /* package private */ // used only by BreakpointAttributeTranslator#resolveBreakpoint
+ void findClosestLineWithCode(ISymbolDMContext symCtx, String bpPath,
+ 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) + " original file: " + bpPath + " 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;
+ }
+
+ String compilationPath = EDCLaunch.getLaunchForSession(getSession().getId()).getCompilationPath(bpPath);
+ if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null,
+ "BP file: " + bpPath + " Compile file: " + compilationPath); }
+
+ EDCLineAddresses result = null;
+ PersistentCache pCache = EDCDebugger.getDefault().getCache();
+ 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;
+
+ long readerModDate = reader.getModificationDate();
+
+ List<ILineAddresses> codeLines = null;
+
+ Map<String, List<ILineAddresses>> cache = new HashMap<String, List<ILineAddresses>>();
+
+ // Check the persistent cache
+ String symFile = reader.getSymbolFile().toOSString();
+ String cacheKey = symFile + LINE_ADDRESSES_CACHE;
+ String noFileCacheKey = symFile + NO_FILE_CACHE;
+
+ @SuppressWarnings("unchecked")
+ Set<String> noFileCachedData
+ = pCache.getCachedData(noFileCacheKey, Set.class, readerModDate);
+ if (noFileCachedData != null && noFileCachedData.contains(compilationPath)
+ && noFileCachedData.contains(bpPath)) {
+ 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
+ = pCache.getCachedData(cacheKey, Map.class, readerModDate);
+ if (cachedData != null) {
+ cache = cachedData;
+ // cache is always stored based on compilation path below,
+ // even if the path passed was the original file location path
+ codeLines = cachedData.get(compilationPath + anchor);
+ }
+
+ if (codeLines == null) { // cache missed
+ IModuleLineEntryProvider lnt = reader.getModuleScope().getModuleLineEntryProvider();
+
+ // try compilationPath first
+ if (lnt.hasSourceFile(PathUtils.createPath(compilationPath))) {
+ codeLines = lnt.findClosestLineWithCode(PathUtils.createPath(compilationPath), anchor, neighbor_limit);
+ } else {
+ // 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(compilationPath);
+ pCache.putCachedData(noFileCacheKey, (Serializable) noFileCachedData, readerModDate);
+
+ // sometimes eclipse core passes the original file path instead
+ if (lnt.hasSourceFile(PathUtils.createPath(bpPath))) {
+ codeLines = lnt.findClosestLineWithCode(PathUtils.createPath(bpPath), anchor, neighbor_limit);
+ } else {
+ // same with the original bpPath
+ noFileCachedData.add(bpPath);
+ pCache.putCachedData(noFileCacheKey, (Serializable) noFileCachedData, readerModDate);
+ if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, "File not used by module"); }
+ continue; // nothing else here to check, move on to next module
+ }
+ }
+
+ if (codeLines == null) {
+ if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, "codeLines == null"); }
+ continue; // should not happen ... except if bp set in comments or whitespace ... right?
+ }
+
+ // Cache code lines (with their link addresses), whether we find it or not,
+ // and always cache based on compilationPath, even if found using original bpPath
+ cache.put(compilationPath + anchor, codeLines);
+ pCache.putCachedData(cacheKey, (Serializable) cache, readerModDate);
+ 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(EDCServicesMessages.Modules_CannotMoveBreakpoint,
+ neighbor_limit, compilationPath, 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;
+ }
+
+ // this calculation is now pushed all the way down to calcAddressRanges()
+// ISymbolDMContext symCtx = DMContexts.getAncestorOfType(context, ISymbolDMContext.class);
+
+ // establish this here so it can be used in either call below.
+ DataRequestMonitor<AddressRange[]> calcAddressDRM
+ = new DataRequestMonitor<AddressRange[]>(getExecutor(), drm) {
+
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ AddressRange[] addr_ranges = getData();
+
+ for (AddressRange range : addr_ranges) {
+ IAddress a = range.getStartAddress(); // this is runtime address
+ addrs.add(a);
+ }
+
+ drm.setData(addrs);
+ } else {
+ drm.setStatus(getStatus());
+ }
+ drm.done();
+ }
+ };
+
+ if (context instanceof RunControl.ThreadExecutionDMC) {
+ RunControl.ThreadExecutionDMC threadDMC = (RunControl.ThreadExecutionDMC)context;
+ calcAddressInfo(threadDMC, sourceFile, lineNumber, 0, calcAddressDRM);
+ } else {
+ ISymbolDMContext symCtx = DMContexts.getAncestorOfType(context, ISymbolDMContext.class);
+ calcAddressInfo(symCtx, sourceFile, lineNumber, 0, calcAddressDRM);
+ }
+ }
+
+ 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()]);
+ }
+ }
+
+ public void moduleLoaded(ISymbolDMContext symbolContext, IExecutionDMContext executionDMC, Map<String, Object> moduleProps) {
+ ModuleDMC module = new ModuleDMC(symbolContext, moduleProps);
+ module.relocateSections(moduleProps, true);
+ addModule(module);
+ getSession().dispatchEvent(new ModuleLoadedEvent(symbolContext, executionDMC, module),
+ Modules.this.getProperties());
+ }
+
+ public void moduleUnloaded(ISymbolDMContext symbolContext, IExecutionDMContext executionDMC,
+ Map<String, Object> moduleProps) {
+ String moduleID = getModuleID(moduleProps); // the moduleProps comes from agent.
+ ModuleDMC module = getModuleByID(symbolContext, moduleID);
+ if (module == null) {
+ EDCDebugger.getMessageLogger().logError("Unexpected unload of module: " + moduleProps, null);
+ return;
+ }
+
+ Object requireResumeValue = moduleProps.get(IModuleProperty.PROP_RESUME);
+ if (requireResumeValue != null && requireResumeValue instanceof Boolean)
+ module.setProperty(IModuleProperty.PROP_RESUME, 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);
+
+ }
+
+ private static String getModuleID(Map<String, Object> props) {
+ if (props.containsKey(IEDCDMContext.PROP_ID))
+ return props.get(IEDCDMContext.PROP_ID).toString();
+ if (props.containsKey(IModuleProperty.PROP_FILE))
+ return props.get(IModuleProperty.PROP_FILE).toString();
+ if (props.containsKey(IEDCDMContext.PROP_NAME))
+ return props.get(IEDCDMContext.PROP_NAME).toString();
+ assert(false); // One of these is required
+ return "";
+ }
+
+ /**
+ * 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;
+ }
+
+ private ModuleDMC getModuleByID(ISymbolDMContext symCtx, String id) {
+ ModuleDMC module = null;
+ synchronized (modules) {
+ List<ModuleDMC> moduleList = modules.get(((IEDCDMContext) symCtx).getID());
+ if (moduleList != null) {
+ for (ModuleDMC moduleDMC : moduleList) {
+ if ((moduleDMC.getID().compareToIgnoreCase(id)) == 0 ) {
+ module = moduleDMC;
+ break;
+ }
+ }
+ }
+ }
+ return module;
+ }
+
+}
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
index fe65b9a..881c196 100644
--- 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
@@ -1,3081 +1,3107 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2011 Nokia and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, 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.core.breakpointactions.ILogActionEnabler;
-import org.eclipse.cdt.debug.core.breakpointactions.IResumeActionEnabler;
-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.breakpointactions.EDCLogActionEnabler;
-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.concurrent.RequestMonitorWithProgress;
-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.IFormattedValues;
-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.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.NullProgressMonitor;
-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";
-
- public static final String STEP_RETURN_NOT_SUPPORTED
- = "the current Execution context does not support StepType.STEP_RETURN"; //$NON-NLS-1$
-
- /*
- * 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 Map<String, StateChangeReason> reasons;
- private static StateChangeReason toDsfStateChangeReason(String tcfReason) {
- if (tcfReason == null)
- return StateChangeReason.UNKNOWN;
- if (reasons == null)
- reasons = new HashMap<String, IRunControl.StateChangeReason>();
- StateChangeReason reason = reasons.get(tcfReason);
- if (reason == null) {
-
- if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_USER_REQUEST))
- reason = StateChangeReason.USER_REQUEST;
- else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_STEP))
- reason = StateChangeReason.STEP;
- else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_BREAKPOINT))
- reason = StateChangeReason.BREAKPOINT;
- else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_EXCEPTION))
- reason = StateChangeReason.EXCEPTION;
- else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_CONTAINER))
- reason = StateChangeReason.CONTAINER;
- else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_WATCHPOINT))
- reason = StateChangeReason.WATCHPOINT;
- else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_SIGNAL))
- reason = StateChangeReason.SIGNAL;
- else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_SHAREDLIB))
- reason = StateChangeReason.SHAREDLIB;
- else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_ERROR))
- reason = StateChangeReason.ERROR;
- else
- reason = StateChangeReason.UNKNOWN;
- reasons.put(tcfReason, reason);
- }
- return reason;
- }
-
- @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;
- /**
- * Hex string without "0x".
- */
- private String latestPC = null;
- private RequestMonitor steppingRM = null;
- private boolean isStepping = false;
- private RequestMonitorWithProgress bpActionRM = null;
-
- // See where this is used for more.
- private int countOfScheduledNotifications = 0 ;
-
- /**
- * Whether user chose to "terminate" or "disconnect" the context.
- */
- private boolean isTerminatingThanDisconnecting = false;
-
- /**
- * Code ranges to step outside of.
- *
- * Certain source line may have two separate sections of
- * . For instance, the following lines <pre>
- * for (i=0; i<3; i++)
- * k *= k;
- * </pre>
- * will have such code generated by MinGW GCC compiler:
- * <pre>
- 184 for (i=0; i<3; i++)
- 00000000004017f7: movl $0x0,-0x8(%ebp)
- 00000000004017fe: jmp 0x40180d
- 185 k *= k;
- 0000000000401800: mov -0x10(%ebp),%eax
- 0000000000401803: imul -0x10(%ebp),%eax
- 0000000000401807: mov %eax,-0x10(%ebp)
- 184 for (i=0; i<3; i++)
- 000000000040180a: incl -0x8(%ebp)
- 000000000040180d: cmpl $0x2,-0x8(%ebp)
- 0000000000401811: setle %al
- 0000000000401814: test %al,%al
- 0000000000401816: jne 0x401800
- </pre>
- * To step over the above "for()" statement, we need
- * to make sure stepping does not stop in its second
- * code section.
- */
- private List<EDCAddressRange> stepRanges = Collections.synchronizedList(new ArrayList<EDCAddressRange>());
-
- private boolean suspendEventsEnabled = true;
- private DMCSuspendedEvent cachedSuspendedEvent = null;
-
- /**
- * All possible function call destination addresses when we perform a
- * StepIn.<br>
- * This is to help auto-step through glue code in a function call (e.g.
- * the jmp instruction in a jump table for calling a Win32 DLL).
- */
- private List<IAddress> functionCallDestinations = Collections.synchronizedList(new ArrayList<IAddress>());
-
- 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;
- }
-
- protected void setStateChangeDetails(String newStateChangeDetails) {
- stateChangeDetails = newStateChangeDetails;
- }
-
- 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<Object> preprocessDrm = new DataRequestMonitor<Object>(getExecutor(), null) {
- @Override
- protected void handleCompleted() {
- Boolean honorSuspend;
- Breakpoints.BreakpointDMData bp;
- Object drmData = getData();
- if (drmData instanceof Breakpoints.BreakpointDMData) {
- bp = (Breakpoints.BreakpointDMData)drmData;
- honorSuspend = true;
- } else {
- bp = null;
- honorSuspend = (drmData instanceof Boolean) ? (Boolean)getData() : true;
- }
-
- if (honorSuspend!=null && honorSuspend) { // do suspend
-
- // All the following must be done in DSF dispatch
- // thread to ensure data integrity.
-
- // see if there are any actions, and perform them if so
- if (bp != null && bp.hasActions()) {
- bp.executeActions(ExecutionDMC.this, newBreakpointActionRM());
- }
-
- // Mark done of the single step RM, if any pending.
- if (steppingRM != null) {
- if (bp == null) {
- stateChangeReason = StateChangeReason.STEP;
- stateChangeDetails = 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));
-
- /*
- * Don't report suspendedEvent to upper layer
- * resulting from prepareToRun() to avoid
- * unnecessary suspend-handling. But we need to
- * fire the event if the stepping is finished after
- * prepareToRun(). So remember it.
- */
- DMCSuspendedEvent e = dmc.createSuspendedEvent(stateChangeReason, params);
- if (dmc.suspendEventsEnabled())
- getSession().dispatchEvent(e, RunControl.this.getProperties());
- else
- dmc.cacheSuspendedEvent(e);
- } 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); }
- }
-
- void clearBreakpointActionRM() {
- synchronized (this) {
- if (bpActionRM != null) {
- if (!bpActionRM.getSubmitted()) {
- bpActionRM.cancel();
- }
- IProgressMonitor progress = bpActionRM.getProgressMonitor();
- if (progress != null && !progress.isCanceled()) {
- progress.setCanceled(true);
- }
- bpActionRM = null;
- }
- }
- }
-
- public RequestMonitorWithProgress getBreakpointActionRM() {
- return bpActionRM;
- }
-
- RequestMonitorWithProgress newBreakpointActionRM() {
- clearBreakpointActionRM();
- bpActionRM = new RequestMonitorWithProgress(getExecutor(), new NullProgressMonitor()) {
- @Override
- public void handleCompleted() {
- super.handleCompleted();
- clearBreakpointActionRM();
- }
- };
- return bpActionRM;
- }
-
- protected boolean suspendEventsEnabled() {
- return suspendEventsEnabled ;
- }
-
- protected void setSuspendEventsEnabled(boolean enabled)
- {
- suspendEventsEnabled = enabled;
- }
-
- /**
- * 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;
-
- clearBreakpointActionRM();
-
- 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) {
- assert supportsStepMode(StepType.STEP_RETURN) : STEP_RETURN_NOT_SUPPORTED;
-
- 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;
- }
-
- private void addStepRange(IAddress lowAddress, IAddress highAddress) {
- stepRanges.add(new EDCAddressRange(lowAddress, highAddress));
- }
-
- /**
- * Check if the give address is in current step ranges, if yes, return
- * the range that contains it.
- *
- * @param address
- * @return null if not found.
- */
- private EDCAddressRange findStepRange(IAddress address) {
- for (EDCAddressRange r : stepRanges) {
- if (r.contains(address))
- return r;
- }
- return null;
- }
-
- private void clearStepRanges() {
- stepRanges.clear();
- }
-
- protected DMCSuspendedEvent createSuspendedEvent(StateChangeReason reason, Map<String, Object> properties) {
- return new SuspendedEvent(this, reason, properties);
- }
-
- /**
- * Cache a suspendedEvent for this context. Note only one
- * event will be cached at a time.
- *
- * @param e
- * The event to cache.
- */
- private void cacheSuspendedEvent(DMCSuspendedEvent e) {
- cachedSuspendedEvent = e;
- }
-
- /**
- * The event should be used only once, thus this will clear
- * the cache for that sake.
- * @return
- */
- private DMCSuspendedEvent getCachedSuspendedEvent() {
- DMCSuspendedEvent e = cachedSuspendedEvent;
- cachedSuspendedEvent = null;
- return e;
- }
-
- protected DMCResumedEvent createResumedEvent() {
- return new ResumedEvent(this);
- }
-
- public RunControlContext getTCFContext() {
- return tcfContext;
- }
-
- public boolean hasTCFContext() {
- return tcfContext != null;
- }
-
- @Override
- public Object getAdapter(@SuppressWarnings("rawtypes") Class adapterType) {
- if (adapterType.equals(ILogActionEnabler.class)) {
- Stack stackService = getService(Stack.class);
- IFrameDMContext[] frames;
- try {
- frames = stackService.getFramesForDMC(this, 0, 0);
- Expressions exprService = getService(Expressions.class);
- return new EDCLogActionEnabler(exprService, frames[0]);
- } catch (CoreException e) {
- return null;
- }
- }
- if (adapterType.equals(IResumeActionEnabler.class)) {
- RunControl.ThreadExecutionDMC threadDMC
- = DMContexts.getAncestorOfType(this, RunControl.ThreadExecutionDMC.class);
- return new ResumeActionEnabler(threadDMC);
- }
- if (adapterType.equals(AbstractEDCService.class)) {
- return RunControl.this;
- }
- return super.getAdapter(adapterType);
- }
-
- private void addFunctionCallDestination(IAddress addr) {
- functionCallDestinations.add(addr);
- }
-
- private void clearFunctionCallDestinations() {
- functionCallDestinations.clear();
- }
-
- private boolean isFunctionCallDestination(IAddress addr) {
- return functionCallDestinations.contains(addr);
- }
- }
-
- 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;
- }
- }
-
- public class ResumeActionEnabler implements IResumeActionEnabler {
-
- ExecutionDMC executionDMC;
-
- public ResumeActionEnabler(final ExecutionDMC exeDMC) {
- executionDMC = exeDMC;
- }
-
- public void resume() throws Exception {
- RunControl.this.resume(executionDMC, new RequestMonitor(getExecutor(), null));
- }
-
- }
-
- 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<Object> 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.
-
- StateChangeReason stateChangeReason = dmc.getStateChangeReason();
- if (stateChangeReason != StateChangeReason.BREAKPOINT
- && stateChangeReason != StateChangeReason.WATCHPOINT) {
- drm.setData(true);
- drm.done();
- return;
- }
-
- BreakpointDMData bp;
- if (!bpService.usesTCFBreakpointService()) {
- // generic software breakpoint is used.
- // We need to move PC back to the breakpoint
- // instruction.
-
- long pcValue
- = Long.valueOf(pcString, 16)
- - getTargetEnvironmentService()
- .getBreakpointInstruction(dmc, new Addr64(pcString, 16))
- .length;
- pcString = Long.toHexString(pcValue);
-
- bp = bpService.findBreakpoint(new Addr64(pcString, 16));
-
- // Stopped but not due to breakpoint set by debugger.
- // For instance, some Windows DLL has "int 3"
- // instructions in it.
- if (bp != null) {
- // Now adjust PC register.
- regService.writeRegister(dmc, getTargetEnvironmentService().getPCRegisterID(), pcString);
- dmc.setPC(pcString);
- }
- } else {
- if (stateChangeReason == StateChangeReason.BREAKPOINT)
- bp = bpService.findUserBreakpoint(new Addr64(pcString, 16));
- else {// condition above means this is a StateChangeReason.WATCHPOINT
- bp = bpService.findUserBreakpoint(new Addr64(dmc.getStateChangeDetails(), 16));
- if (bp != null)
- dmc.setStateChangeDetails("[" + bp.getExpression() + "]");
- }
- }
-
- // check if a conditional breakpoint (must be a user bp) is hit
- //
- 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 are actions associated with the last breakpoint,
- // cancel the RM (and the action list for them) and resume
- dmc.clearBreakpointActionRM();
-
- // If there is breakpoint at current PC, remove it => Single step =>
- // Restore it.
-
- final Breakpoints bpService = getService(Breakpoints.class);
- if (bpService.usesTCFBreakpointService()) {
- // It's currently required that the agent can single-step past a breakpoint
- // if it offers TCF breakpoints service. It's not a solid requirement but just
- // nice for the sake of stepping performance.
- 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) {
- /*
- * Step from current PC in "context"
- */
- 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);
- dmc.clearFunctionCallDestinations();
-
- 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 = getAddressForNextLine(dmc, pcAddress, module,
- linkAddress, lineEntryProvider, line,
- stepType == StepType.STEP_OVER);
-
- dmc.clearStepRanges();
-
- // If the line has two or more code ranges, record them
- //
- Collection<ILineEntry> ranges
- = lineEntryProvider.getLineEntriesForLines(line.getFilePath(),
- line.getLineNumber(),
- line.getLineNumber());
- if (ranges.size() > 1)
- {
- for (ILineEntry iLineEntry : ranges) {
- dmc.addStepRange(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). We just parse and step past
- * instructions within [pcAddr, endAddr) instead
- * of all those within [startAddr, endAddr). One
- * possible problem with the solution is when
- * control jumps from a point within [pcAddress,
- * endAddr) to a point within [startAddr,
- * pcAddress), the stepping would stop within
- * 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
- */
- final boolean stepIn = stepType == StepType.STEP_INTO;
- stepAddressRange(dmc, stepIn, pcAddress, endAddr, new RequestMonitor(getExecutor(), rm) {
- @Override
- protected void handleSuccess() {
- handleStepAddressRangeDone(stepIn, dmc, 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)
- // Note when do StepIn at instruction level, we
- // don't bother checking and stepping past glue code.
- //
- 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 handleStepAddressRangeDone(final boolean stepIn, final ExecutionDMC dmc, final RequestMonitor rm) {
- IAddress newPC = new Addr64(dmc.getPC(), 16);
-
- boolean done = false;
- EDCAddressRange r = dmc.findStepRange(newPC);
-
- if (r == null)
- // PC is out of line code ranges, done
- done = true;
- else {
- Breakpoints bpService = getService(Breakpoints.class);
- if (bpService.findUserBreakpoint(newPC) != null)
- // hit a user breakpoint
- done = true;
- }
-
- if (done) {
- if (stepIn) {
- // Only when we step into a function (not jump to some place)
- // do we check if there is glue code and step past it if any
- // ...........................08/07/11
- if (dmc.isFunctionCallDestination(newPC))
- stepPastGlueCode(dmc, newPC, rm);
- else
- rm.done();
- }
- else
- rm.done();
- }
- else if (r != null)
- // Still in a code range of the line, keep going by recursive call.
- stepAddressRange(dmc, stepIn, newPC, r.getEndAddress(), new RequestMonitor(getExecutor(), rm) {
- @Override
- protected void handleSuccess() {
- // recursive
- handleStepAddressRangeDone(stepIn, dmc, rm);
- }});
- }
-
- /**
- * If instructions at PC are glue code (e.g. jump table for call to function in DLL),
- * step past them. Otherwise just do nothing.
- *
- * @param dmc the execution context, usually a thread.
- * @param pc program counter.
- * @param rm
- */
- private void stepPastGlueCode(ExecutionDMC dmc, IAddress pc,
- RequestMonitor rm) {
- // Glue code is totally processor specific. So
- // let TargetEnvironment service handle it.
- ITargetEnvironment te = getService(ITargetEnvironment.class);
- te.stepPastGlueCode(dmc, pc, 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 {
- // Stepping finished after prepareToRun().
- DMCSuspendedEvent e = dmc.getCachedSuspendedEvent();
- if (e != null)
- getSession().dispatchEvent(e, RunControl.this.getProperties());
-
- 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 translateMemoryBytes()
- }
-
- 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())); }
-
- int memSize = startAddr.distanceTo(endAddr).intValue();
- if (memSize < 0) { // endAddr < startAddr
- rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID,
- MessageFormat.format(
- "Invalid arguments for StepAddressRange(): ending address {0} is smaller than start address {1}.",
- endAddr.toHexAddressString(), startAddr.toHexAddressString())));
- rm.done();
- return;
- }
-
- 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);
-
- 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) // not control-change instruction, ignore.
- 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;
- }
-
- if (!jta.isSubroutineAddress() || stepIn)
- {
- // evaluate the address expression
- 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);
-
- if (jta.isSubroutineAddress()) // step-in a function
- dmc.addFunctionCallDestination(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);
-
- dmc.addFunctionCallDestination(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...
- *
- * TODO: we could solve it by keeping stepping till we are out
- * of the range. Do it when really needed in practice (namely
- * when the following warning is seen).
- */
- // Log a 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)) {
- // done with the stepping
- doneWithStepping = true;
- break;
- }
-
- Breakpoints bpService = getService(Breakpoints.class);
- if (bpService.findUserBreakpoint(newPC) != null) {
- // hit a user bp
- 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 bp 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 {
- // Stepping finished after prepareToRun().
- DMCSuspendedEvent e = dmc.getCachedSuspendedEvent();
- if (e != null)
- getSession().dispatchEvent(e, RunControl.this.getProperties());
- 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 */) {
- // Stepping finished after prepareToRun().
- DMCSuspendedEvent e = dmc.getCachedSuspendedEvent();
- if (e != null)
- getSession().dispatchEvent(e, RunControl.this.getProperties());
- 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) {
-
- assert(context instanceof ExecutionDMC);
- final ExecutionDMC dmc = (ExecutionDMC)context;
-
- String newPC = address.toString(16);
-
- if (! newPC.equals(dmc.getPC())) {
- Registers regService = getService(Registers.class);
-
- 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 if (rm == dmc.getBreakpointActionRM()) {
- // if resume is false and our request monitor is
- // THE breakpointActionRM, then the caller (currently
- // only SkipAction) expects to stop at that bkpt.
- // but that bkpt may have actions to be executed.
- Breakpoints bpService = getService(Breakpoints.class);
- final Breakpoints.BreakpointDMData bp = bpService.findUserBreakpoint(address);
- if (bp.hasActions()) {
- bp.executeActions(dmc, dmc.getBreakpointActionRM());
- } else
- rm.done();
- } 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()]);
- }
-
- public IAddress getAddressForNextLine(final ExecutionDMC dmc, IAddress pcAddress,
- IEDCModuleDMContext module, IAddress linkAddress,
- IModuleLineEntryProvider lineEntryProvider, ILineEntry line,
- boolean treatAsStepOver) {
- 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),
- treatAsStepOver);
- 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 (treatAsStepOver) {
- while (functionScope != null
- && functionScope.getParent() instanceof IFunctionScope) {
- functionScope = (IFunctionScope)functionScope.getParent();
- }
- }
- if (functionScope != null)
- endAddr = module.toRuntimeAddress(functionScope.getHighAddress());
- }
- return endAddr;
- }
-
- /**
- * 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);
- }
-}
+/*******************************************************************************
+ * Copyright (c) 2009, 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, 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.core.breakpointactions.ILogActionEnabler;
+import org.eclipse.cdt.debug.core.breakpointactions.IResumeActionEnabler;
+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.breakpointactions.EDCLogActionEnabler;
+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.concurrent.RequestMonitorWithProgress;
+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.IFormattedValues;
+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.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.NullProgressMonitor;
+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";
+
+ public static final String STEP_RETURN_NOT_SUPPORTED
+ = "the current Execution context does not support StepType.STEP_RETURN"; //$NON-NLS-1$
+
+ final private boolean DEBUG_STEPPING = false;
+
+ /*
+ * 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 Map<String, StateChangeReason> reasons;
+ private static StateChangeReason toDsfStateChangeReason(String tcfReason) {
+ if (tcfReason == null)
+ return StateChangeReason.UNKNOWN;
+ if (reasons == null)
+ reasons = new HashMap<String, IRunControl.StateChangeReason>();
+ StateChangeReason reason = reasons.get(tcfReason);
+ if (reason == null) {
+
+ if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_USER_REQUEST))
+ reason = StateChangeReason.USER_REQUEST;
+ else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_STEP))
+ reason = StateChangeReason.STEP;
+ else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_BREAKPOINT))
+ reason = StateChangeReason.BREAKPOINT;
+ else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_EXCEPTION))
+ reason = StateChangeReason.EXCEPTION;
+ else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_CONTAINER))
+ reason = StateChangeReason.CONTAINER;
+ else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_WATCHPOINT))
+ reason = StateChangeReason.WATCHPOINT;
+ else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_SIGNAL))
+ reason = StateChangeReason.SIGNAL;
+ else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_SHAREDLIB))
+ reason = StateChangeReason.SHAREDLIB;
+ else if (tcfReason.equals(org.eclipse.tm.tcf.services.IRunControl.REASON_ERROR))
+ reason = StateChangeReason.ERROR;
+ else
+ reason = StateChangeReason.UNKNOWN;
+ reasons.put(tcfReason, reason);
+ }
+ return reason;
+ }
+
+ @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;
+ /**
+ * Hex string without "0x".
+ */
+ private String latestPC = null;
+ private RequestMonitor resumeForSteppingRM = null;
+ private boolean isStepping = false;
+ private RequestMonitorWithProgress bpActionRM = null;
+
+ // See where this is used for more.
+ private int countOfScheduledNotifications = 0 ;
+
+ /**
+ * Whether user chose to "terminate" or "disconnect" the context.
+ */
+ private boolean isTerminatingThanDisconnecting = false;
+
+ /**
+ * Code ranges to step outside of.
+ *
+ * Certain source line may have two separate sections of
+ * . For instance, the following lines <pre>
+ * for (i=0; i<3; i++)
+ * k *= k;
+ * </pre>
+ * will have such code generated by MinGW GCC compiler:
+ * <pre>
+ 184 for (i=0; i<3; i++)
+ 00000000004017f7: movl $0x0,-0x8(%ebp)
+ 00000000004017fe: jmp 0x40180d
+ 185 k *= k;
+ 0000000000401800: mov -0x10(%ebp),%eax
+ 0000000000401803: imul -0x10(%ebp),%eax
+ 0000000000401807: mov %eax,-0x10(%ebp)
+ 184 for (i=0; i<3; i++)
+ 000000000040180a: incl -0x8(%ebp)
+ 000000000040180d: cmpl $0x2,-0x8(%ebp)
+ 0000000000401811: setle %al
+ 0000000000401814: test %al,%al
+ 0000000000401816: jne 0x401800
+ </pre>
+ * To step over the above "for()" statement, we need
+ * to make sure stepping does not stop in its second
+ * code section.
+ */
+ private List<EDCAddressRange> stepRanges = Collections.synchronizedList(new ArrayList<EDCAddressRange>());
+
+ private DMCSuspendedEvent cachedSuspendedEvent = null;
+
+ /**
+ * All possible function call destination addresses when we perform a
+ * StepIn.<br>
+ * This is to help auto-step through glue code in a function call (e.g.
+ * the jmp instruction in a jump table for calling a Win32 DLL).
+ */
+ private List<IAddress> functionCallDestinations = Collections.synchronizedList(new ArrayList<IAddress>());
+
+ 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;
+ }
+
+ protected void setStateChangeDetails(String newStateChangeDetails) {
+ stateChangeDetails = newStateChangeDetails;
+ }
+
+ 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.
+
+ // negative values are most likely 32-bit numbers;
+ // don't interpret as long since this will result in unsigned 64-bit values
+ if (pc.length() > 0 && pc.charAt(0) == '-') {
+ try {
+ pc = Integer.toHexString(Integer.parseInt(pc));
+ } catch (NumberFormatException e) {
+ // sent also for out-of-range
+ pc = Long.toHexString(Long.parseLong(pc));
+ }
+ }
+ else
+ pc = Long.toHexString(Long.parseLong(pc));
+ }
+
+ latestPC = pc;
+
+ synchronized (properties) {
+ properties.put(PROP_MESSAGE, reason);
+ properties.put(PROP_SUSPEND_PC, pc);
+ }
+ stateChangeReason = toDsfStateChangeReason(reason);
+
+ if (stateChangeReason == StateChangeReason.SHAREDLIB) {
+ // mark the thread as suspended if we're required to resume it
+ boolean requireResume = true;
+ Object propvalue = params.get(IModuleProperty.PROP_RESUME);
+ if (propvalue != null)
+ if (propvalue instanceof Boolean)
+ requireResume = (Boolean) propvalue;
+
+ setIsSuspended(requireResume);
+
+ handleModuleEvent(this, params);
+ } else {
+ setIsSuspended(true);
+
+ 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<Object> preprocessDrm = new DataRequestMonitor<Object>(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ Boolean honorSuspend;
+ Breakpoints.BreakpointDMData bp;
+ Object drmData = getData();
+ if (drmData instanceof Breakpoints.BreakpointDMData) {
+ bp = (Breakpoints.BreakpointDMData)drmData;
+ honorSuspend = true;
+ } else {
+ bp = null;
+ honorSuspend = (drmData instanceof Boolean) ? (Boolean)getData() : true;
+ }
+
+ if (honorSuspend!=null && honorSuspend) { // do suspend
+
+ // All the following must be done in DSF dispatch
+ // thread to ensure data integrity.
+
+ // see if there are any actions, and perform them if so
+ if (bp != null && bp.hasActions()) {
+ bp.executeActions(ExecutionDMC.this, newBreakpointActionRM());
+ }
+
+ // change the reason to STEP.
+ if (resumeForSteppingRM != null && bp == null
+ && stateChangeReason == StateChangeReason.BREAKPOINT) {
+ stateChangeReason = StateChangeReason.STEP;
+ stateChangeDetails = null;
+ }
+
+ /*
+ * 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) {
+ @Override
+ protected void handleCompleted() {
+ // Mark done of the resumeForStepping RM, if any pending.
+ if (resumeForSteppingRM != null) {
+ resumeForSteppingRM.done();
+ resumeForSteppingRM = null;
+ }
+
+ /*
+ * Don't report interim suspendedEvent during stepping to upper layer
+ * (e.g. the one resulted from prepareToRun()) to avoid unnecessary
+ * suspend-handling. Just remember it. We'll fire the last such event
+ * when the stepping is finished.
+ */
+ DMCSuspendedEvent e = dmc.createSuspendedEvent(stateChangeReason, params);
+ if (! dmc.isStepping())
+ getSession().dispatchEvent(e, RunControl.this.getProperties());
+ else
+ dmc.cacheSuspendedEvent(e);
+
+ super.handleCompleted();
+ }});
+
+ } 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); }
+ }
+
+ void clearBreakpointActionRM() {
+ synchronized (this) {
+ if (bpActionRM != null) {
+ if (!bpActionRM.getSubmitted()) {
+ bpActionRM.cancel();
+ }
+ IProgressMonitor progress = bpActionRM.getProgressMonitor();
+ if (progress != null && !progress.isCanceled()) {
+ progress.setCanceled(true);
+ }
+ bpActionRM = null;
+ }
+ }
+ }
+
+ public RequestMonitorWithProgress getBreakpointActionRM() {
+ return bpActionRM;
+ }
+
+ RequestMonitorWithProgress newBreakpointActionRM() {
+ clearBreakpointActionRM();
+ bpActionRM = new RequestMonitorWithProgress(getExecutor(), new NullProgressMonitor()) {
+ @Override
+ public void handleCompleted() {
+ super.handleCompleted();
+ clearBreakpointActionRM();
+ }
+ };
+ return bpActionRM;
+ }
+
+ /**
+ * 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)); }
+
+ 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 resumeForSteppingRM == null;
+ resumeForSteppingRM = rm;
+ } else {
+ msg += " failed.";
+ if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().trace(null, msg); }
+
+ 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;
+
+ clearBreakpointActionRM();
+
+ 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())); }
+
+ 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) {
+ assert supportsStepMode(StepType.STEP_RETURN) : STEP_RETURN_NOT_SUPPORTED;
+
+ if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(this.getName())); }
+
+ 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())); }
+
+ 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;
+ }
+
+ private void addStepRange(IAddress lowAddress, IAddress highAddress) {
+ stepRanges.add(new EDCAddressRange(lowAddress, highAddress));
+ }
+
+ /**
+ * Check if the give address is in current step ranges, if yes, return
+ * the range that contains it.
+ *
+ * @param address
+ * @return null if not found.
+ */
+ private EDCAddressRange findStepRange(IAddress address) {
+ for (EDCAddressRange r : stepRanges) {
+ if (r.contains(address))
+ return r;
+ }
+ return null;
+ }
+
+ private void clearStepRanges() {
+ stepRanges.clear();
+ }
+
+ protected DMCSuspendedEvent createSuspendedEvent(StateChangeReason reason, Map<String, Object> properties) {
+ return new SuspendedEvent(this, reason, properties);
+ }
+
+ /**
+ * Cache a suspendedEvent for this context. Note only one
+ * event will be cached at a time.
+ *
+ * @param e
+ * The event to cache.
+ */
+ private void cacheSuspendedEvent(DMCSuspendedEvent e) {
+ if (DEBUG_STEPPING) System.out.println("Cache interim SuspendedEvent: " + e);
+ cachedSuspendedEvent = e;
+ }
+
+ /**
+ * The event should be used only once, thus this will clear
+ * the cache for that sake.
+ * @return
+ */
+ private DMCSuspendedEvent getCachedSuspendedEvent() {
+ DMCSuspendedEvent e = cachedSuspendedEvent;
+ if (DEBUG_STEPPING) System.out.println("Get cached SuspendedEvent: " + e);
+ cachedSuspendedEvent = null;
+ return e;
+ }
+
+ protected DMCResumedEvent createResumedEvent() {
+ return new ResumedEvent(this);
+ }
+
+ public RunControlContext getTCFContext() {
+ return tcfContext;
+ }
+
+ public boolean hasTCFContext() {
+ return tcfContext != null;
+ }
+
+ @Override
+ public Object getAdapter(@SuppressWarnings("rawtypes") Class adapterType) {
+ if (adapterType.equals(ILogActionEnabler.class)) {
+ Stack stackService = getService(Stack.class);
+ IFrameDMContext[] frames;
+ try {
+ frames = stackService.getFramesForDMC(this, 0, 0);
+ Expressions exprService = getService(Expressions.class);
+ return new EDCLogActionEnabler(exprService, frames[0]);
+ } catch (CoreException e) {
+ return null;
+ }
+ }
+ if (adapterType.equals(IResumeActionEnabler.class)) {
+ RunControl.ThreadExecutionDMC threadDMC
+ = DMContexts.getAncestorOfType(this, RunControl.ThreadExecutionDMC.class);
+ return new ResumeActionEnabler(threadDMC);
+ }
+ if (adapterType.equals(AbstractEDCService.class)) {
+ return RunControl.this;
+ }
+ return super.getAdapter(adapterType);
+ }
+
+ private void addFunctionCallDestination(IAddress addr) {
+ functionCallDestinations.add(addr);
+ }
+
+ private void clearFunctionCallDestinations() {
+ functionCallDestinations.clear();
+ }
+
+ private boolean isFunctionCallDestination(IAddress addr) {
+ return functionCallDestinations.contains(addr);
+ }
+ }
+
+ 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);
+ if (this.isSuspended())
+ {
+ 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));
+ if (this.isSuspended())
+ {
+ 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.snapshotValues(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;
+ }
+ }
+
+ public class ResumeActionEnabler implements IResumeActionEnabler {
+
+ ExecutionDMC executionDMC;
+
+ public ResumeActionEnabler(final ExecutionDMC exeDMC) {
+ executionDMC = exeDMC;
+ }
+
+ public void resume() throws Exception {
+ RunControl.this.resume(executionDMC, new RequestMonitor(getExecutor(), null));
+ }
+
+ }
+
+ 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<Object> 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.
+
+ StateChangeReason stateChangeReason = dmc.getStateChangeReason();
+ if (stateChangeReason != StateChangeReason.BREAKPOINT
+ && stateChangeReason != StateChangeReason.WATCHPOINT) {
+ drm.setData(true);
+ drm.done();
+ return;
+ }
+
+ BreakpointDMData bp;
+ if (!bpService.usesTCFBreakpointService()) {
+ // generic software breakpoint is used.
+ // We need to move PC back to the breakpoint
+ // instruction.
+
+ long pcValue
+ = Long.valueOf(pcString, 16)
+ - getTargetEnvironmentService()
+ .getBreakpointInstruction(dmc, new Addr64(pcString, 16))
+ .length;
+ pcString = Long.toHexString(pcValue);
+
+ bp = bpService.findBreakpoint(new Addr64(pcString, 16));
+
+ // Stopped but not due to breakpoint set by debugger.
+ // For instance, some Windows DLL has "int 3"
+ // instructions in it.
+ if (bp != null) {
+ // Now adjust PC register.
+ regService.writeRegister(dmc, getTargetEnvironmentService().getPCRegisterID(), pcString);
+ dmc.setPC(pcString);
+ }
+ } else {
+ if (stateChangeReason == StateChangeReason.BREAKPOINT)
+ bp = bpService.findUserBreakpoint(new Addr64(pcString, 16));
+ else {// condition above means this is a StateChangeReason.WATCHPOINT
+ bp = bpService.findUserBreakpoint(new Addr64(dmc.getStateChangeDetails(), 16));
+ if (bp != null)
+ dmc.setStateChangeDetails("[" + bp.getExpression() + "]");
+ }
+ }
+
+ // check if a conditional breakpoint (must be a user bp) is hit
+ //
+ 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 are actions associated with the last breakpoint,
+ // cancel the RM (and the action list for them) and resume
+ dmc.clearBreakpointActionRM();
+
+ // If there is breakpoint at current PC, remove it => Single step =>
+ // Restore it.
+
+ final Breakpoints bpService = getService(Breakpoints.class);
+ if (bpService.usesTCFBreakpointService()) {
+ // It's currently required that the agent can single-step past a breakpoint
+ // if it offers TCF breakpoints service. It's not a solid requirement but just
+ // nice for the sake of stepping performance.
+ 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.singleStep(true, new RequestMonitor(getExecutor(), drm) {
+ @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) {
+ if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(MessageFormat.format("{0} context {1}", outerStepType, 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;
+
+ if (DEBUG_STEPPING)
+ System.out.println("isStepping: " + dmc.isStepping() + " -- Thread: " + Thread.currentThread().getName());
+
+ /*
+ * This "Step()" method is mostly called by DSF (namely initiated by
+ * user issuing "Step" command). But it may also be called by EDC as
+ * part of stepping handling. This is to differentiate the two cases.
+ */
+ final boolean steppingByUser = ! dmc.isStepping();
+ if (steppingByUser)
+ dmc.setStepping(true);
+
+ /*
+ * Step from current PC in "context"
+ */
+ asyncExec(new Runnable() {
+ public void run() {
+ doStep(dmc, outerStepType, new RequestMonitor(getExecutor(), rm) {
+
+ @Override
+ protected void handleSuccess() {
+ if (steppingByUser) {
+ dmc.setStepping(false);
+ DMCSuspendedEvent e = dmc.getCachedSuspendedEvent();
+ if (e != null)
+ getSession().dispatchEvent(e, RunControl.this.getProperties());
+ else {
+ // should not happen
+ assert(false);
+ }
+ }
+
+ rm.done();
+ }});
+ }
+ }, rm);
+ }
+
+ private void doStep(final ExecutionDMC dmc, StepType stepType, final RequestMonitor rm) {
+ if (timeStepping())
+ steppingStartTime = System.currentTimeMillis();
+
+ dmc.clearFunctionCallDestinations();
+
+ 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(dmc, 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 = getAddressForNextLine(dmc, pcAddress, module,
+ linkAddress, lineEntryProvider, line,
+ stepType == StepType.STEP_OVER);
+
+ dmc.clearStepRanges();
+
+ // If the line has two or more code ranges, record them
+ //
+ Collection<ILineEntry> ranges
+ = lineEntryProvider.getLineEntriesForLines(line.getFilePath(),
+ line.getLineNumber(),
+ line.getLineNumber());
+ if (ranges.size() > 1)
+ {
+ for (ILineEntry iLineEntry : ranges) {
+ dmc.addStepRange(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). We just parse and step past
+ * instructions within [pcAddr, endAddr) instead
+ * of all those within [startAddr, endAddr). One
+ * possible problem with the solution is when
+ * control jumps from a point within [pcAddress,
+ * endAddr) to a point within [startAddr,
+ * pcAddress), the stepping would stop within
+ * 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
+ */
+ final boolean stepIn = stepType == StepType.STEP_INTO;
+ stepAddressRange(dmc, stepIn, pcAddress, endAddr, new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ handleStepAddressRangeDone(stepIn, dmc, 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)
+ // Note when do StepIn at instruction level, we
+ // don't bother checking and stepping past glue code.
+ //
+ stepIntoOneInstruction(dmc, rm);
+ else if (stepType == StepType.INSTRUCTION_STEP_RETURN)
+ stepOut(dmc, pcAddress, rm);
+
+ if (EDCTrace.RUN_CONTROL_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
+ }
+
+ private void handleStepAddressRangeDone(final boolean stepIn, final ExecutionDMC dmc, final RequestMonitor rm) {
+ IAddress newPC = new Addr64(dmc.getPC(), 16);
+
+ boolean done = false;
+ EDCAddressRange r = dmc.findStepRange(newPC);
+
+ if (r == null)
+ // PC is out of line code ranges, done
+ done = true;
+ else {
+ Breakpoints bpService = getService(Breakpoints.class);
+ if (bpService.findUserBreakpoint(newPC) != null)
+ // hit a user breakpoint
+ done = true;
+ }
+
+ if (done) {
+ if (stepIn) {
+ // Only when we step into a function (not jump to some place)
+ // do we check if there is glue code and step past it if any
+ // ...........................08/07/11
+ if (dmc.isFunctionCallDestination(newPC))
+ stepPastGlueCode(dmc, newPC, rm);
+ else
+ rm.done();
+ }
+ else
+ rm.done();
+ }
+ else if (r != null)
+ // Still in a code range of the line, keep going by recursive call.
+ stepAddressRange(dmc, stepIn, newPC, r.getEndAddress(), new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ // recursive
+ handleStepAddressRangeDone(stepIn, dmc, rm);
+ }});
+ }
+
+ /**
+ * If instructions at PC are glue code (e.g. jump table for call to function in DLL),
+ * step past them. Otherwise just do nothing.
+ *
+ * @param dmc the execution context, usually a thread.
+ * @param pc program counter.
+ * @param rm
+ */
+ private void stepPastGlueCode(ExecutionDMC dmc, IAddress pc,
+ RequestMonitor rm) {
+ // Glue code is totally processor specific. So
+ // let TargetEnvironment service handle it.
+ ITargetEnvironment te = getService(ITargetEnvironment.class);
+ te.stepPastGlueCode(dmc, pc, 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 {
+ // Stepping finished after prepareToRun().
+ 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 translateMemoryBytes()
+ }
+
+ 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())); }
+
+ int memSize = startAddr.distanceTo(endAddr).intValue();
+ if (memSize < 0) { // endAddr < startAddr
+ rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID,
+ MessageFormat.format(
+ "Invalid arguments for StepAddressRange(): ending address {0} is smaller than start address {1}.",
+ endAddr.toHexAddressString(), startAddr.toHexAddressString())));
+ rm.done();
+ return;
+ }
+
+ 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);
+
+ 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) // not control-change instruction, ignore.
+ 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;
+ }
+
+ if (!jta.isSubroutineAddress() || stepIn)
+ {
+ // evaluate the address expression
+ 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);
+
+ if (jta.isSubroutineAddress()) // step-in a function
+ dmc.addFunctionCallDestination(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);
+
+ dmc.addFunctionCallDestination(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...
+ *
+ * TODO: we could solve it by keeping stepping till we are out
+ * of the range. Do it when really needed in practice (namely
+ * when the following warning is seen).
+ */
+ // Log a 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)) {
+ // done with the stepping
+ doneWithStepping = true;
+ break;
+ }
+
+ Breakpoints bpService = getService(Breakpoints.class);
+ if (bpService.findUserBreakpoint(newPC) != null) {
+ // hit a user bp
+ 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 bp 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 {
+ // Stepping finished after prepareToRun().
+ 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 */) {
+ // Stepping finished after prepareToRun().
+ 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) {
+
+ assert(context instanceof ExecutionDMC);
+ final ExecutionDMC dmc = (ExecutionDMC)context;
+
+ String newPC = address.toString(16);
+
+ if (! newPC.equals(dmc.getPC())) {
+ Registers regService = getService(Registers.class);
+
+ 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 if (rm == dmc.getBreakpointActionRM()) {
+ // if resume is false and our request monitor is
+ // THE breakpointActionRM, then the caller (currently
+ // only SkipAction) expects to stop at that bkpt.
+ // but that bkpt may have actions to be executed.
+ Breakpoints bpService = getService(Breakpoints.class);
+ final Breakpoints.BreakpointDMData bp = bpService.findUserBreakpoint(address);
+ if (bp.hasActions()) {
+ bp.executeActions(dmc, dmc.getBreakpointActionRM());
+ } else
+ rm.done();
+ } 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()]);
+ }
+
+ public IAddress getAddressForNextLine(final ExecutionDMC dmc, IAddress pcAddress,
+ IEDCModuleDMContext module, IAddress linkAddress,
+ IModuleLineEntryProvider lineEntryProvider, ILineEntry line,
+ boolean treatAsStepOver) {
+ 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),
+ treatAsStepOver);
+ 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 (treatAsStepOver) {
+ while (functionScope != null
+ && functionScope.getParent() instanceof IFunctionScope) {
+ functionScope = (IFunctionScope)functionScope.getParent();
+ }
+ }
+ if (functionScope != null)
+ endAddr = module.toRuntimeAddress(functionScope.getHighAddress());
+ }
+ return endAddr;
+ }
+
+ /**
+ * 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/Symbols.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/services/dsf/Symbols.java
index c563f11..1e8b6b3 100644
--- 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
@@ -1,402 +1,420 @@
-/*******************************************************************************
- * 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.text.MessageFormat;
-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.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.symbols.ICompositeType;
-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.internal.symbols.files.PEFileExecutableSymbolicsReader;
-import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
-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.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.debug.edc.symbols.IType;
-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.IModuleDMContext;
-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.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-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();
- }
-
- /**
- * Given an opaque composite type, search the symbol context for definition
- * of the type.
- *
- * A C/C++ opaque type is usually used in opaque pointer, e.g.
- *
- * <pre>
- * typedef class PrivateType* OpaquePTR;
- * </pre>
- *
- * The actual definition of the "PrivateType" is usually in another
- * library/DLL with or without debug info.<br>
- * <br>
- * This method will search all modules loaded in the symbol context (usually
- * a process) until it finds a non-opaque type with the same name as the
- * given opaque type. If a loaded module has no debug info, it will just be
- * skipped.
- *
- * @param symCtx
- * the symbol context (usually a process)
- * @param type
- * the opaque composite type
- * @return a defined type; null if no defined type is found or the given
- * type is not opaque.
- */
- public ICompositeType resolveOpaqueType(ISymbolDMContext symCtx, ICompositeType type) {
- ICompositeType result = null;
- if (type == null || ! type.isOpaque()) {
- return result;
- }
-
- if (EDCTrace.SYMBOL_READER_TRACE_ON) {
- EDCTrace.getTrace().traceEntry(null, "Resolve opaque type \"" + type.getName() + "\" in " + EDCTrace.fixArg(symCtx));
- }
-
- IModuleDMContext[] moduleList = null;
-
- Modules modulesService = getService(Modules.class);
- assert(modulesService != null);
-
- if (symCtx instanceof IEDCExecutionDMC) {
- String symContextID = ((IEDCDMContext) symCtx).getID();
- moduleList = modulesService.getModulesForContext(symContextID);
- } else if (symCtx instanceof IModuleDMContext) {
- moduleList = new IModuleDMContext[1];
- moduleList[0] = (IModuleDMContext) symCtx;
- } else {
- // should not happen
- Status s = new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, MessageFormat.format(
- "Unknown class implementing ISymbolDMContext : {0}", symCtx.getClass().getName()), null);
-
- if (EDCTrace.SYMBOL_READER_TRACE_ON)
- EDCTrace.getTrace().traceExit(null, s);
- return result;
- }
-
- for (IModuleDMContext module : moduleList) {
- ModuleDMC mdmc = (ModuleDMC) module;
- EDCSymbolReader reader = (EDCSymbolReader)mdmc.getSymbolReader();
-
- if (reader == null || reader.getDebugInfoProvider() == null) // no debug info
- continue;
-
- Collection<IType> types = reader.getDebugInfoProvider().getTypesByName(type.getName());
- if (types == null)
- return result;
-
- for (IType t : types) {
- if (t instanceof ICompositeType && ! ((ICompositeType)t).isOpaque()) {
- result = (ICompositeType)t;
- break;
- }
- }
-
- }
-
- return result;
- }
-
- /**
- * A wrapper method that calls into symbol reader to get runtime address(es)
- * for a given function name.
- * For executables that are not PE-COFF, this method only uses the symbol table instead of
- * also debug info (e.g. Dwarf3) 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 gigabytes of
- // memory required in parsing a 180M ELF 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(functionName);
-// 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);
- }
-
- if (symbols.isEmpty() && symReader.getSymbolicsReader() instanceof PEFileExecutableSymbolicsReader) {
- // for PE-COFF files, if the name is not in the symbol list, search the debug info
- IFunctionScope function = symReader.getModuleScope().getFunctionByName(functionName);
- if (function != null)
- ret.add(function.getLowAddress());
- } else 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;
- }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009, 2010, 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, 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.text.MessageFormat;
+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.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.symbols.ICompositeType;
+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.internal.symbols.files.PEFileExecutableSymbolicsReader;
+import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
+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.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.debug.edc.symbols.IType;
+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.IModuleDMContext;
+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.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.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();
+ }
+
+ /**
+ * Given an opaque composite type, search the symbol context for definition
+ * of the type.
+ *
+ * A C/C++ opaque type is usually used in opaque pointer, e.g.
+ *
+ * <pre>
+ * typedef class PrivateType* OpaquePTR;
+ * </pre>
+ *
+ * The actual definition of the "PrivateType" is usually in another
+ * library/DLL with or without debug info.<br>
+ * <br>
+ * This method will search all modules loaded in the symbol context (usually
+ * a process) until it finds a non-opaque type with the same name as the
+ * given opaque type. If a loaded module has no debug info, it will just be
+ * skipped.
+ *
+ * @param symCtx
+ * the symbol context (usually a process)
+ * @param type
+ * the opaque composite type
+ * @return a defined type; null if no defined type is found or the given
+ * type is not opaque.
+ */
+ public ICompositeType resolveOpaqueType(ISymbolDMContext symCtx, ICompositeType type,
+ IProgressMonitor monitor) {
+ if (type == null || ! type.isOpaque())
+ return null;
+
+ if (EDCTrace.SYMBOL_READER_TRACE_ON) {
+ EDCTrace.getTrace().traceEntry(null, "Resolve opaque type \"" + type.getName() + "\" in " + EDCTrace.fixArg(symCtx));
+ }
+
+ IModuleDMContext[] moduleList = null;
+
+ Modules modulesService = getService(Modules.class);
+ assert(modulesService != null);
+
+ if (symCtx instanceof IEDCExecutionDMC) {
+ String symContextID = ((IEDCDMContext) symCtx).getID();
+ moduleList = modulesService.getModulesForContext(symContextID);
+ } else if (symCtx instanceof IModuleDMContext) {
+ moduleList = new IModuleDMContext[1];
+ moduleList[0] = (IModuleDMContext) symCtx;
+ } else {
+ // should not happen
+ Status s = new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, MessageFormat.format(
+ "Unknown class implementing ISymbolDMContext : {0}", symCtx.getClass().getName()), null);
+
+ if (EDCTrace.SYMBOL_READER_TRACE_ON)
+ EDCTrace.getTrace().traceExit(null, s);
+ return null;
+ }
+
+ SubMonitor searchMonitor = SubMonitor.convert(monitor, moduleList.length);
+ searchMonitor.subTask("Searching modules list: 0/" + String.valueOf(moduleList.length));
+ int count = 0;
+ for (IModuleDMContext module : moduleList) {
+ ModuleDMC mdmc = (ModuleDMC) module;
+
+ searchMonitor.worked(1);
+ searchMonitor.subTask("Searching modules list: " + String.valueOf(++count)
+ + "/" + String.valueOf(moduleList.length));
+
+ EDCSymbolReader reader = (EDCSymbolReader)mdmc.getSymbolReader();
+ if (reader == null)
+ continue;
+ searchMonitor.subTask("Searching modules list: " + String.valueOf(count)
+ + "/" + String.valueOf(moduleList.length) + " "
+ + reader.getSymbolFile().toOSString());
+ IDebugInfoProvider provider = reader.getDebugInfoProvider();
+ if (provider == null)
+ continue;
+
+ searchMonitor.subTask("Searching modules list: " + String.valueOf(count)
+ + "/" + String.valueOf(moduleList.length) + " "
+ + provider.getSymbolFile().toOSString());
+
+ Collection<IType> types = provider.getTypesByName(type.getName());
+
+ if (types == null)
+ continue;
+
+ for (IType t : types)
+ if (t instanceof ICompositeType && ! ((ICompositeType)t).isOpaque())
+ // return immediately as soon as we have something useful
+ return (ICompositeType)t;
+ if (searchMonitor.isCanceled())
+ break;
+ }
+
+ return null;
+ }
+
+ /**
+ * A wrapper method that calls into symbol reader to get runtime address(es)
+ * for a given function name.
+ * For executables that are not PE-COFF, this method only uses the symbol table instead of
+ * also debug info (e.g. Dwarf3) 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 gigabytes of
+ // memory required in parsing a 180M ELF 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(functionName);
+// 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);
+ }
+
+ if (symbols.isEmpty() && symReader.getSymbolicsReader() instanceof PEFileExecutableSymbolicsReader) {
+ // for PE-COFF files, if the name is not in the symbol list, search the debug info
+ IFunctionScope function = symReader.getModuleScope().getFunctionByName(functionName);
+ if (function != null)
+ ret.add(function.getLowAddress());
+ } else 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
index 41bac9e..0c015ab 100644
--- 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
@@ -1,1326 +1,1339 @@
-/*******************************************************************************
- * 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.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());
- InputSource inputSource = new InputSource(stream);
- inputSource.setSystemId(albumFile.toURI().toString()); // avoid NPE inside XML parser
- setDocument(parser.parse(inputSource));
-
- 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 = EDCDebugger.getPrefs(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 = EDCDebugger.getPrefs(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 = EDCDebugger.getPrefs(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.
- }
-
-}
+/*******************************************************************************
+ * 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.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_RESOLVE_OPAQUE_TYPE = "resolve_opaque_type";
+ 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());
+ InputSource inputSource = new InputSource(stream);
+ inputSource.setSystemId(albumFile.toURI().toString()); // avoid NPE inside XML parser
+ setDocument(parser.parse(inputSource));
+
+ 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 setResolveOpaqueType(boolean newSetting) {
+ IEclipsePreferences scope = EDCDebugger.getPrefs(EDCDebugger.PLUGIN_ID);
+ scope.putBoolean(PREF_RESOLVE_OPAQUE_TYPE, newSetting);
+ try {
+ scope.flush();
+ } catch (BackingStoreException e) {
+ EDCDebugger.getMessageLogger().logError(null, e);
+ }
+ }
+
+ public static boolean getResolveOpaqueType() {
+ return Platform.getPreferencesService().getBoolean(EDCDebugger.PLUGIN_ID,
+ PREF_RESOLVE_OPAQUE_TYPE, false, null);
+ }
+
+ public static void setVariableCaptureDepth(int newSetting) {
+ IEclipsePreferences scope = EDCDebugger.getPrefs(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 = EDCDebugger.getPrefs(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 = EDCDebugger.getPrefs(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/Snapshot.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/snapshot/Snapshot.java
index 2b44aa4..d73b1c2 100644
--- 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
@@ -1,305 +1,303 @@
-/*******************************************************************************
- * 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;
- }
-
-}
+/*******************************************************************************
+ * 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", "rawtypes", "unchecked" })
+
+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();
+ }
+
+ }
+
+ @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$
+ }
+
+ 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.
+ */
+ 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/symbols/CompositeType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/CompositeType.java
index 739390f..f4d28a4 100644
--- 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
@@ -1,453 +1,473 @@
-/*******************************************************************************
- * 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.Collections;
-import java.util.Map;
-import java.util.StringTokenizer;
-
-import java.util.Comparator;
-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>();
- private boolean fieldsSorted = false;
-
- // classes inherited from
- protected ArrayList<IInheritance> inheritances = null;
- private boolean inheritancesSorted = false;
-
- // 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();
- if (fields.size() > 1 && !fieldsSorted) {
- Collections.sort(fields, new Comparator<IField>() {
- public int compare(IField f1, IField f2) {
- return (int)(f1.getFieldOffset() - f2.getFieldOffset());
- }
- });
- fieldsSorted = true;
- }
-
- 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];
-
- if (inheritances.size() > 1 && !inheritancesSorted) {
- Collections.sort(inheritances, new Comparator<IInheritance>() {
- public int compare(IInheritance i1, IInheritance i2) {
- return (int)(i1.getFieldsOffset() - i2.getFieldsOffset());
- }
- });
- inheritancesSorted = true;
- }
-
- 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;
- }
-
- public boolean isOpaque() {
- /*
- * Opaque pointer:
- * - Source:
- struct PrivateStruct* struct_op;
- * -- Dwarf from GNU C++ 3.4.5 (mingw-vista special r3):
- <1><654>: Abbrev Number: 6 (DW_TAG_structure_type)
- <655> DW_AT_name : PrivateStruct
- <663> DW_AT_declaration : 1
- * RVCT Dwarf for an opaque type:
- 454f6b: 62 = 0x13 (DW_TAG_structure_type)
- 454f6c: DW_AT_name PrivateStruct
-
- *
- * Intentional empty structure/class:
- * Source:
- class EmptyClass {
- };
- * -- Dwarf from GNU C++ 3.4.5 (mingw-vista special r3):
- * Note the non-zero bype_size:
- <1><172>: Abbrev Number: 13 (DW_TAG_structure_type)
- <173> DW_AT_sibling : <0x1da>
- <177> DW_AT_name : (indirect string, offset: 0x23): EmptyStruct
- <17b> DW_AT_byte_size : 1
- <17c> DW_AT_decl_file : 1
- <17d> DW_AT_decl_line : 22
- ...
- *
- */
- return getByteSize() <= 0;
- }
-}
+/*******************************************************************************
+ * 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.Collections;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IType;
+
+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>();
+ private boolean fieldsSorted = false;
+
+ // classes inherited from
+ protected ArrayList<IInheritance> inheritances = null;
+ private boolean inheritancesSorted = false;
+
+ // template parameters
+ protected ArrayList<ITemplateParam> templateParams = null;
+ boolean nameIncludesTemplateParams;
+
+ // runtime type info offset - non-negative offset means RTTI may be possible
+ protected long runtimeTypeOffset = -1;
+
+ /**
+ * 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();
+ if (fields.size() > 1 && !fieldsSorted) {
+ Collections.sort(fields, new Comparator<IField>() {
+ public int compare(IField f1, IField f2) {
+ return (int)(f1.getFieldOffset() - f2.getFieldOffset());
+ }
+ });
+ fieldsSorted = true;
+ }
+
+ 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];
+
+ if (inheritances.size() > 1 && !inheritancesSorted) {
+ Collections.sort(inheritances, new Comparator<IInheritance>() {
+ public int compare(IInheritance i1, IInheritance i2) {
+ return (int)(i1.getFieldsOffset() - i2.getFieldsOffset());
+ }
+ });
+ inheritancesSorted = true;
+ }
+
+ 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;
+ }
+
+ public boolean isOpaque() {
+ /*
+ * Opaque pointer:
+ * - Source:
+ struct PrivateStruct* struct_op;
+ * -- Dwarf from GNU C++ 3.4.5 (mingw-vista special r3):
+ <1><654>: Abbrev Number: 6 (DW_TAG_structure_type)
+ <655> DW_AT_name : PrivateStruct
+ <663> DW_AT_declaration : 1
+ * RVCT Dwarf for an opaque type:
+ 454f6b: 62 = 0x13 (DW_TAG_structure_type)
+ 454f6c: DW_AT_name PrivateStruct
+
+ *
+ * Intentional empty structure/class:
+ * Source:
+ class EmptyClass {
+ };
+ * -- Dwarf from GNU C++ 3.4.5 (mingw-vista special r3):
+ * Note the non-zero byte_size:
+ <1><172>: Abbrev Number: 13 (DW_TAG_structure_type)
+ <173> DW_AT_sibling : <0x1da>
+ <177> DW_AT_name : (indirect string, offset: 0x23): EmptyStruct
+ <17b> DW_AT_byte_size : 1
+ <17c> DW_AT_decl_file : 1
+ <17d> DW_AT_decl_line : 22
+ ...
+ *
+ */
+ return getByteSize() <= 0;
+ }
+
+ public boolean hasRuntimeTypeInfo() {
+ return false;
+ }
+
+ public void setRuntimeTypeOffset(long runtimeTypeOffset) {
+ this.runtimeTypeOffset = runtimeTypeOffset;
+ }
+
+ public long getRuntimeTypeOffset() {
+ return runtimeTypeOffset;
+ }
+
+ public IType getRuntimeType(MemoryVariableLocation address) {
+ return getType();
+ }
+}
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
index 9cdfe3b..60e13a0 100644
--- 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
@@ -1,122 +1,147 @@
-/*******************************************************************************
- * 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();
-
- /**
- * Is this an opaque type ?
- * @return true or false
- */
- public boolean isOpaque();
-}
+/*******************************************************************************
+ * 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();
+
+ /**
+ * Is this an opaque type?
+ * @return true or false
+ */
+ public boolean isOpaque();
+
+ /**
+ * Does this composite type have runtime type info?
+ * @return true or false
+ */
+ public boolean hasRuntimeTypeInfo();
+
+ /**
+ * Set the offset to info that can be used to determine the runtime type (-1 if no info)
+ * @param runtimeTypeOffset
+ */
+ public void setRuntimeTypeOffset(long runtimeTypeOffset);
+
+ /**
+ * Get the offset to info that can be used to determine the runtime type (-1 if no info)
+ * @return runtime type info offset
+ */
+ public long getRuntimeTypeOffset();
+
+ /**
+ * Get runtime type
+ * @param address of start of runtime type info
+ * @return runtime type
+ */
+ public IType getRuntimeType(MemoryVariableLocation address);
+}
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
index 119982f..a15b5b0 100644
--- 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
@@ -1,20 +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
- *******************************************************************************/
-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 {
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009, 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, 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 for pointer types
+ */
+public interface IPointerType extends IRuntimeType {
+
+}
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
index beea795..96ba494 100644
--- 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
@@ -1,17 +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
- *******************************************************************************/
-package org.eclipse.cdt.debug.edc.internal.symbols;
-
-import org.eclipse.cdt.debug.edc.symbols.IType;
-
-public interface IReferenceType extends IType {
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009, 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, 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 for reference types
+ */
+public interface IReferenceType extends IRuntimeType {
+
+}
diff --git a/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IRuntimeType.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IRuntimeType.java
new file mode 100644
index 0000000..9a1866e
--- /dev/null
+++ b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/IRuntimeType.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, 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;
+
+/**
+ * For a pointer or reference type, allow access to RTTI-determined offset
+ */
+public interface IRuntimeType extends IType {
+
+ /**
+ * Get offset from variable's apparent address in memory to its real address when
+ * using RTTI
+ */
+ public long getRuntimeOffset();
+
+ /**
+ * Set offset from variable's apparent address in memory to its real address when
+ * using RTTI
+ * @param runtimeOffset offset from apparent object address to real address when using RTTI
+ */
+ public void setRuntimeOffset(long runtimeOffset);
+}
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
index efdc4b2..1dca869 100644
--- 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
@@ -1,83 +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$
- }
-}
+/*******************************************************************************
+ * 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=" //$NON-NLS-1$
+ + (lowAddress != null ? lowAddress.toHexAddressString() : "null") //$NON-NLS-1$
+ + ", highAddress=" //$NON-NLS-1$
+ + (highAddress != null ? highAddress.toHexAddressString() : "null") //$NON-NLS-1$
+ + ((filePath != null) ? ", path=" + filePath.toOSString() : "") //$NON-NLS-1$//$NON-NLS-2$
+ + ", line=" + lineNumber + ", column=" + columnNumber //$NON-NLS-1$//$NON-NLS-2$
+ + "]" ; //$NON-NLS-1$
+ }
+}
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
index 0418415..88310f6 100644
--- 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
@@ -1,217 +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.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;
- }
-}
+/*******************************************************************************
+ * 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.IEDCModuleDMContext;
+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) {
+ IEDCModuleDMContext module
+ = DMContexts.getAncestorOfType(context, IEDCModuleDMContext.class);
+ if (module == null) {
+ StackFrameDMC frame = DMContexts.getAncestorOfType(context, StackFrameDMC.class);
+ if (frame == null)
+ throw EDCDebugger.newCoreException(SymbolsMessages.MemoryVariableLocation_CannotFindFrame);
+ module = frame.getModule();
+ }
+ theAddress = module.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 void setModuleContext(IEDCModuleDMContext ctx) {
+ context = ctx;
+ }
+
+ 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
index a8c94a4..34bd5dc 100644
--- 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
@@ -1,434 +1,433 @@
-/**
- * Copyright (c) 2010, 2011 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
- * refactoring of FileLineEntryProvider to separate class
- *
- * Contributors:
- * Broadcom - convert private class extensions to final
- *
- */
-
-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 static 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 static 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();
- }
-
-}
+/**
+ * Copyright (c) 2010, 2011 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
+ * refactoring of FileLineEntryProvider to separate class
+ *
+ * Contributors:
+ * Broadcom - convert private class extensions to final
+ *
+ */
+
+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 static 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 static 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
index 4ba1294..5c952dc 100644
--- 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
@@ -1,28 +1,37 @@
-/*******************************************************************************
- * 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$
- }
-
-}
+/*******************************************************************************
+ * 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 {
+ protected long runtimeOffset = 0;
+
+ 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$
+ }
+
+ public long getRuntimeOffset() {
+ return runtimeOffset;
+ }
+
+ public void setRuntimeOffset(long runtimeOffset) {
+ this.runtimeOffset = runtimeOffset;
+ }
+
+}
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
index ce308d5..cbe9cc7 100644
--- 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
@@ -1,22 +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.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);
- }
-}
+/*******************************************************************************
+ * 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 {
+ protected long runtimeOffset = 0;
+
+ public ReferenceType(String name, IScope scope, int byteSize, Map<Object, Object> properties) {
+ super(name, scope, byteSize, properties);
+ }
+
+ public long getRuntimeOffset() {
+ return runtimeOffset;
+ }
+
+ public void setRuntimeOffset(long runtimeOffset) {
+ this.runtimeOffset = runtimeOffset;
+ }
+
+}
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
index 2b030fa..cc207f1 100644
--- 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
@@ -1,435 +1,437 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2010, 2011 Nokia and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, 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;
-
-/**
- * abstract implementation of {@link IScope},
- * optionally containing a name, low & high addresses, IScope parent,
- * children, variables, enumerators, et al
- *
- */
-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
- || lowAddress.equals(highAddress);
- }
-
- /**
- * 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)
- addressToScopeMap = new TreeMap<Entry, IScope>();
- 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);
- }
-
- /** Scope specific compareTo() based upon<br>
- * 1) if object to compare is IScope, comparison of lowAddress, then highAddress<br>
- * 2) if object to compare is IAddress, compare address to this lowAddress<br>
- * @see java.lang.Comparable#compareTo(java.lang.Object)
- */
- public int compareTo(Object o) {
- if (o instanceof IScope) {
- IScope io = (IScope) o;
- int comparison = lowAddress.compareTo(io.getLowAddress());
- if (comparison == 0) {
- comparison = highAddress.compareTo(io.getHighAddress());
- }
- return comparison;
- } else if (o instanceof IAddress) {
- return lowAddress.compareTo(o);
- }
- return 0;
- }
-
- /**
- * Scope specific version of toString():<br>
- * <code>
- * [ranges=, lowAddress=, highAddress=, name=]
- * </code>
- * @see java.lang.Object#toString()
- */
- @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();
- }
-
- /**
- * deal with incorrectly generated ranges by the compiler
- * that may not work together properly with ranges of children
- * @param baseAddress
- */
- 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;
- IRangeList newRangeList = new RangeList();
- 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) {
- IRangeList kidRanges = kid.getRangeList();
- if (kidRanges == null){// If it didn't have ranges it still has one range
- kidRanges = new RangeList();
- ((RangeList)kidRanges).addRange(kid.getLowAddress().getValue().longValue(),kid.getHighAddress().getValue().longValue());
- }
- newRangeList = RangeList.mergeRangeLists(newRangeList,kidRanges);
-
- 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;
- int entryCount = 0;
- for (@SuppressWarnings("unused") IRangeList.Entry entry : newRangeList){
- ++entryCount;
- }
- rangeList = (entryCount > 1) ? newRangeList : 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) {
- rangeList = RangeList.mergeRangeLists(rangeList,scope.getRangeList());
- } 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) {
- rangeList = RangeList.mergeRangeLists(rangeList,scope.getRangeList());
- } else {
- ((RangeList)rangeList).addHighRange(scope.getHighAddress().getValue().longValue());
- }
- }
- highAddress = scope.getHighAddress();
- }
- }
- }
-
- /**
- * @param scope
- */
- 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;
- }
-
- /**
- * there are not enough non-mutable members with which
- * to provide a proper hashCode() for Scope, and we
- * cannot provide equals() if we cannot guarantee
- * hashCode() ... but at least we can make comparison
- * of different Scope objects a little easier for
- * situations where we want to claim to Scope objects
- * have the same contents.
- * <br>
- * in this case, content equality is based upon the
- * following criteria<br>
- * 1) same children<br>
- * 2) same highAddress<br>
- * 3) same lowAddress<br>
- * 4) same name<br>
- * 5) same rangeList<br>
- */
- public boolean contentsEquals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Scope other = (Scope) obj;
- if (children == null) {
- if (other.children != null)
- return false;
- } else if (!children.equals(other.children))
- return false;
- if (highAddress == null) {
- if (other.highAddress != null)
- return false;
- } else if (!highAddress.equals(other.highAddress))
- return false;
- if (lowAddress == null) {
- if (other.lowAddress != null)
- return false;
- } else if (!lowAddress.equals(other.lowAddress))
- return false;
- if (name == null) {
- if (other.name != null)
- return false;
- } else if (!name.equals(other.name))
- return false;
- if (rangeList == null) {
- if (other.rangeList != null)
- return false;
- } else if (!rangeList.equals(other.rangeList))
- return false;
- return true;
- }
-}
+/*******************************************************************************
+ * Copyright (c) 2009, 2010, 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, 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.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+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.IRangeList.Entry;
+import org.eclipse.cdt.debug.edc.symbols.IScope;
+import org.eclipse.cdt.debug.edc.symbols.IVariable;
+import org.eclipse.cdt.utils.Addr32;
+import org.eclipse.cdt.utils.Addr64;
+
+/**
+ * abstract implementation of {@link IScope},
+ * optionally containing a name, low & high addresses, IScope parent,
+ * children, variables, enumerators, et al
+ *
+ */
+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 Map<String, IVariable> variables = new LinkedHashMap<String, 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
+ || lowAddress.equals(highAddress);
+ }
+
+ /**
+ * 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.values());
+ }
+
+ 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)
+ addressToScopeMap = new TreeMap<Entry, IScope>();
+ addScopeRange(scope);
+ }
+
+ /**
+ * Adds the given variable to this scope
+ *
+ * @param variable
+ */
+ public void addVariable(IVariable variable) {
+ variables.put(variable.getName(), variable);
+ }
+
+ /**
+ * Adds the given variable to this scope
+ *
+ * @param variable
+ */
+ public void addEnumerator(IEnumerator enumerator) {
+ enumerators.add(enumerator);
+ }
+
+ /** Scope specific compareTo() based upon<br>
+ * 1) if object to compare is IScope, comparison of lowAddress, then highAddress<br>
+ * 2) if object to compare is IAddress, compare address to this lowAddress<br>
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(Object o) {
+ if (o instanceof IScope) {
+ IScope io = (IScope) o;
+ int comparison = lowAddress.compareTo(io.getLowAddress());
+ if (comparison == 0) {
+ comparison = highAddress.compareTo(io.getHighAddress());
+ }
+ return comparison;
+ } else if (o instanceof IAddress) {
+ return lowAddress.compareTo(o);
+ }
+ return 0;
+ }
+
+ /**
+ * Scope specific version of toString():<br>
+ * <code>
+ * [ranges=, lowAddress=, highAddress=, name=]
+ * </code>
+ * @see java.lang.Object#toString()
+ */
+ @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();
+ }
+
+ /**
+ * deal with incorrectly generated ranges by the compiler
+ * that may not work together properly with ranges of children
+ * @param baseAddress
+ */
+ 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;
+ IRangeList newRangeList = new RangeList();
+ 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) {
+ IRangeList kidRanges = kid.getRangeList();
+ if (kidRanges == null){// If it didn't have ranges it still has one range
+ kidRanges = new RangeList();
+ ((RangeList)kidRanges).addRange(kid.getLowAddress().getValue().longValue(),kid.getHighAddress().getValue().longValue());
+ }
+ newRangeList = RangeList.mergeRangeLists(newRangeList,kidRanges);
+
+ 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;
+ int entryCount = 0;
+ for (@SuppressWarnings("unused") IRangeList.Entry entry : newRangeList){
+ ++entryCount;
+ }
+ rangeList = (entryCount > 1) ? newRangeList : 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) {
+ rangeList = RangeList.mergeRangeLists(rangeList,scope.getRangeList());
+ } 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) {
+ rangeList = RangeList.mergeRangeLists(rangeList,scope.getRangeList());
+ } else {
+ ((RangeList)rangeList).addHighRange(scope.getHighAddress().getValue().longValue());
+ }
+ }
+ highAddress = scope.getHighAddress();
+ }
+ }
+ }
+
+ /**
+ * @param scope
+ */
+ 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.values())
+ var.dispose();
+ variables.clear();
+ enumerators.clear();
+ if (addressToScopeMap != null)
+ addressToScopeMap.clear();
+ rangeList = null;
+ }
+
+ /**
+ * there are not enough non-mutable members with which
+ * to provide a proper hashCode() for Scope, and we
+ * cannot provide equals() if we cannot guarantee
+ * hashCode() ... but at least we can make comparison
+ * of different Scope objects a little easier for
+ * situations where we want to claim to Scope objects
+ * have the same contents.
+ * <br>
+ * in this case, content equality is based upon the
+ * following criteria<br>
+ * 1) same children<br>
+ * 2) same highAddress<br>
+ * 3) same lowAddress<br>
+ * 4) same name<br>
+ * 5) same rangeList<br>
+ */
+ public boolean contentsEquals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Scope other = (Scope) obj;
+ if (children == null) {
+ if (other.children != null)
+ return false;
+ } else if (!children.equals(other.children))
+ return false;
+ if (highAddress == null) {
+ if (other.highAddress != null)
+ return false;
+ } else if (!highAddress.equals(other.highAddress))
+ return false;
+ if (lowAddress == null) {
+ if (other.lowAddress != null)
+ return false;
+ } else if (!lowAddress.equals(other.lowAddress))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (rangeList == null) {
+ if (other.rangeList != null)
+ return false;
+ } else if (!rangeList.equals(other.rangeList))
+ return false;
+ return true;
+ }
+}
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
index a2faabd..902aaf4 100644
--- 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
@@ -1,184 +1,190 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2011 Nokia and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Nokia - Initial API and implementation
- * Broadcom - added hashCode() and equals() implementations
- *******************************************************************************/
-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$
- String sname = scope.getName();
- if (sname.length() == 0) {
- for (IScope parent = scope.getParent()
- ; parent != null
- ; parent = parent.getParent())
- if ((sname = parent.getName()).length() != 0)
- break;
- if (sname.length() != 0) {
- sname += "()"; //$NON-NLS-1$
- if (scope instanceof LexicalBlockScope)
- sname += "{.lexBlk.}"; //$NON-NLS-1$
- } else
- sname = "{." + scope.getClass().getSimpleName() + ".}";
- }
- builder.append(sname);
- }
- builder.append("]"); //$NON-NLS-1$
- return builder.toString();
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((definingFile == null) ? 0 : definingFile.hashCode());
- result = prime * result + (isDeclared ? 1231 : 1237);
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- result = prime * result + ((scope == null) ? 0 : scope.hashCode());
- result = prime * result + (int) (startScope ^ (startScope >>> 32));
- result = prime * result + ((type == null) ? 0 : type.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Variable other = (Variable) obj;
- if (definingFile == null) {
- if (other.definingFile != null)
- return false;
- } else if (!definingFile.equals(other.definingFile))
- return false;
- if (isDeclared != other.isDeclared)
- return false;
- if (name == null) {
- if (other.name != null)
- return false;
- } else if (!name.equals(other.name))
- return false;
- if (scope == null) {
- if (other.scope != null)
- return false;
- } else if (!scope.equals(other.scope))
- return false;
- if (startScope != other.startScope)
- return false;
- if (type == null) {
- if (other.type != null)
- return false;
- } else if (!type.equals(other.type))
- return false;
- return true;
- }
-}
+/*******************************************************************************
+ * Copyright (c) 2009, 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ * Broadcom - added hashCode() and equals() implementations
+ *******************************************************************************/
+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$
+ String sname = scope.getName();
+ if (sname.length() == 0) {
+ for (IScope parent = scope.getParent()
+ ; parent != null
+ ; parent = parent.getParent())
+ if ((sname = parent.getName()).length() != 0)
+ break;
+ if (sname.length() != 0) {
+ sname += "()"; //$NON-NLS-1$
+ if (scope instanceof LexicalBlockScope)
+ sname += "{.lexBlk.}"; //$NON-NLS-1$
+ } else
+ sname = "{." + scope.getClass().getSimpleName() + ".}";
+ }
+ builder.append(sname);
+ }
+ builder.append("]"); //$NON-NLS-1$
+ return builder.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((definingFile == null) ? 0 : definingFile.hashCode());
+ result = prime * result + (isDeclared ? 1231 : 1237);
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((scope == null) ? 0 : scope.hashCode());
+ result = prime * result + (int) (startScope ^ (startScope >>> 32));
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Variable other = (Variable) obj;
+ if (definingFile == null) {
+ if (other.definingFile != null)
+ return false;
+ } else if (!definingFile.equals(other.definingFile))
+ return false;
+ if (isDeclared != other.isDeclared)
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (scope == null) {
+ if (other.scope != null)
+ return false;
+ } else if (!scope.equals(other.scope))
+ return false;
+ if (startScope != other.startScope)
+ return false;
+ if (type == null) {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
+ return true;
+ }
+
+ public IVariable copyWithNewType(IType newType) {
+ Variable variable = new Variable(name, scope, newType, locationProvider, isDeclared, definingFile);
+ variable.startScope = startScope;
+ return variable;
+ }
+}
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
index 6409810..0dd95f5 100644
--- 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
@@ -1,337 +1,336 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2010, 2011 Nokia and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Nokia - Initial API and implementation
- * Broadcom - remove duplicate child methods (repeating super methods from Scope)
- *******************************************************************************/
-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;
-
-/**
- * extension of CompileUnitScope that holds<br>
- * 1) DWARF specific debug info provider<br>
- * 2) DWARF specific attributes<br>
- * 3) DWARF sepcific compile unit header<br>
- * 4) cache flags for previously parsed variables, addresses & types
- *
- */
-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;
-
-
- /**
- * DwarfCompileUnit holds the provider, attributes and DWARF header
- * in addition to other member variables of its super,
- * {@link CompileUnitScope#CompileUnitScope(IPath, IModuleScope, IAddress, IAddress)}
- * @param provider
- * @param parent
- * @param filePath
- * @param lowAddress
- * @param highAddress
- * @param header
- * @param hasChildren
- * @param attributes
- */
- 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;
- }
- }
-
- /**
- * called by {@link CompileUnitScope#hashCode()}.
- * this implementation further distinguishes the hash-code
- * by adding the following to the caller hashCode as follows:
- * <br><code>
- * (prime+header.debugInfoOffset)*prime+provider.symbolfFile.hashCode()
- * </code>
- * @see CompileUnitScope#cuScopeHashCode()
- */
- protected int cuScopeHashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + header.debugInfoOffset;
- result = prime * result + provider.getSymbolFile().hashCode();
- return result;
- }
-
- /**
- * called by {@link CompileUnitScope#equals(Object)}.
- * caller will guarantee objects are not identical, non-null,
- * of same class, with the same scope name.
- * This implementation further guarantees equality:
- * <br>(1) if and only if debugInfoOffset values are equal
- * <br>(2) if and only if provider symbol file values are equal
- * @see CompileUnitScope#cuScopeEquals(java.lang.Object)
- */
- protected boolean cuScopeEquals(Object obj) {
- DwarfCompileUnit other = (DwarfCompileUnit) obj;
- if (header.debugInfoOffset != other.header.debugInfoOffset)
- return false;
- if (!provider.getSymbolFile().equals(other.provider.getSymbolFile()))
- return false;
- return true;
- }
-
- /**
- * @return attributes of this DwarfCompileUnit
- */
- public AttributeList getAttributeList() {
- return attributes;
- }
-
- /**
- * utilize DwarfInfoReader to implement abstract declaration in
- * {@link CompileUnitScope#parseLineTable()}
- */
- protected Collection<ILineEntry> parseLineTable() {
- DwarfInfoReader reader = new DwarfInfoReader(provider);
- fileList = new ArrayList<IPath>();
- return reader.parseLineTable(this, attributes, fileList);
- }
-
- /** fixup ranges and ensure parsed for addresses before calling
- * super.getFunctionAtAddress()
- * @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);
- }
-
- /** ensure parsed for addresses before calling super.getChildren
- * @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;
- }
-
- /** ensure parsed for addresses before calling super.getChildren()
- * @return children of this compile unit after it has been parsed for addresses
- */
- @Override
- public Collection<IScope> getChildren() {
- ensureParsedForAddresses();
- return super.getChildren();
- }
-
- /**
- * allow the caller to establish an attribute list
- */
- public void setAttributes(AttributeList attributes) {
- this.attributes = attributes;
- }
-
- /**
- * @return whether or not this DwarfCompileUnit has been parsed for addresses
- */
- public boolean isParsedForAddresses() {
- return parsedForVarsAndAddresses;
- }
-
- /**
- * @return whether or not this DwarfCompileUnit has been parsed for variables
- */
- public boolean isParsedForVariables() {
- return parsedForVarsAndAddresses;
- }
-
- /**
- * @return whether or not this DwarfCompileUnit has been parsed for types
- */
- public boolean isParsedForTypes() {
- return parsedForTypes;
- }
-
- /** ensure first parsed for variables before calling
- * {@link CompileUnitScope#getVariables()}
- * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getVariables()
- */
- @Override
- public Collection<IVariable> getVariables() {
- ensureParsedForVariables();
- return super.getVariables();
- }
-
- /**
- * allow caller to set this DwarfCompileUnit's parsedForVarsAndAddresses flag true
- * @param parsedForAddresses
- */
- public void setParsedForAddresses(boolean parsedForAddresses) {
- this.parsedForVarsAndAddresses = parsedForAddresses;
- }
-
- /**
- * allow caller to set this DwarfCompileUnit's parsedForVarsAndAddresses flag true
- * @param parsedForVariables
- */
- public void setParsedForVariables(boolean parsedForVariables) {
- this.parsedForVarsAndAddresses = parsedForVariables;
- }
-
- /**
- * allow caller to set this DwarfCompileUnit's parsedForTypes flag true
- * @param parsedForTypes
- */
- public void setParsedForTypes(boolean parsedForTypes) {
- this.parsedForTypes = parsedForTypes;
- }
-
- private void ensureParsedForAddresses() {
- if (!parsedForVarsAndAddresses) {
- DwarfInfoReader reader = new DwarfInfoReader(provider);
- reader.parseCompilationUnitForAddresses(this);
- fixupRanges();
- }
- }
-
- /**
- * 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);
- }
- }
-
- /** ensure parsed for addresses before calling super.getScopeAtAddress()
- * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getScopeAtAddress(org.eclipse.cdt.core.IAddress)
- */
- @Override
- public IScope getScopeAtAddress(IAddress linkAddress) {
- ensureParsedForAddresses();
- return super.getScopeAtAddress(linkAddress);
- }
-
- /**
- * DwarfCompileUnit specific version of toString():<br>
- * <code>
- * [SymFile=, SectionOffset=, lowAddr=, highAddr=, path=, parsedForVarsAndAddress=, parsedForTypes=]
- * </code>
- * @see org.eclipse.cdt.debug.edc.internal.symbols.CompileUnitScope#toString()
- */
- @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();
- }
-
-
- /**
- * 1) calls super.addChild() first<br>
- * 2) checks whether this has an empty range and merges range with passed child scope if not.<br>
- * 3) adds line info to the passed child scope
- * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#addChild(org.eclipse.cdt.debug.edc.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);
- }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009, 2010, 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia - Initial API and implementation
+ * Broadcom - remove duplicate child methods (repeating super methods from Scope)
+ *******************************************************************************/
+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;
+
+/**
+ * extension of CompileUnitScope that holds<br>
+ * 1) DWARF specific debug info provider<br>
+ * 2) DWARF specific attributes<br>
+ * 3) DWARF sepcific compile unit header<br>
+ * 4) cache flags for previously parsed variables, addresses & types
+ *
+ */
+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;
+
+
+ /**
+ * DwarfCompileUnit holds the provider, attributes and DWARF header
+ * in addition to other member variables of its super,
+ * {@link CompileUnitScope#CompileUnitScope(IPath, IModuleScope, IAddress, IAddress)}
+ * @param provider
+ * @param parent
+ * @param filePath
+ * @param lowAddress
+ * @param highAddress
+ * @param header
+ * @param hasChildren
+ * @param attributes
+ */
+ 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;
+ }
+ }
+
+ /**
+ * called by {@link CompileUnitScope#hashCode()}.
+ * this implementation further distinguishes the hash-code
+ * by adding the following to the caller hashCode as follows:
+ * <br><code>
+ * (prime+header.debugInfoOffset)*prime+provider.symbolfFile.hashCode()
+ * </code>
+ * @see CompileUnitScope#cuScopeHashCode()
+ */
+ protected int cuScopeHashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + header.debugInfoOffset;
+ result = prime * result + provider.getSymbolFile().hashCode();
+ return result;
+ }
+
+ /**
+ * called by {@link CompileUnitScope#equals(Object)}.
+ * caller will guarantee objects are not identical, non-null,
+ * of same class, with the same scope name.
+ * This implementation further guarantees equality:
+ * <br>(1) if and only if debugInfoOffset values are equal
+ * <br>(2) if and only if provider symbol file values are equal
+ * @see CompileUnitScope#cuScopeEquals(java.lang.Object)
+ */
+ protected boolean cuScopeEquals(Object obj) {
+ DwarfCompileUnit other = (DwarfCompileUnit) obj;
+ if (header.debugInfoOffset != other.header.debugInfoOffset)
+ return false;
+ if (!provider.getSymbolFile().equals(other.provider.getSymbolFile()))
+ return false;
+ return true;
+ }
+
+ /**
+ * @return attributes of this DwarfCompileUnit
+ */
+ public AttributeList getAttributeList() {
+ return attributes;
+ }
+
+ /**
+ * utilize DwarfInfoReader to implement abstract declaration in
+ * {@link CompileUnitScope#parseLineTable()}
+ */
+ protected Collection<ILineEntry> parseLineTable() {
+ DwarfInfoReader reader = new DwarfInfoReader(provider);
+ fileList = new ArrayList<IPath>();
+ return reader.parseLineTable(this, attributes, fileList);
+ }
+
+ /** fixup ranges and ensure parsed for addresses before calling
+ * super.getFunctionAtAddress()
+ * @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);
+ }
+
+ /** ensure parsed for addresses before calling super.getFunctions
+ * @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;
+ }
+
+// Don't override this here. It causes unnecessary parsing
+// wasting memory & time.
+// @Override
+// public Collection<IScope> getChildren() {
+// ensureParsedForAddresses();
+// return super.getChildren();
+// }
+
+ /**
+ * allow the caller to establish an attribute list
+ */
+ public void setAttributes(AttributeList attributes) {
+ this.attributes = attributes;
+ }
+
+ /**
+ * @return whether or not this DwarfCompileUnit has been parsed for addresses
+ */
+ public boolean isParsedForAddresses() {
+ return parsedForVarsAndAddresses;
+ }
+
+ /**
+ * @return whether or not this DwarfCompileUnit has been parsed for variables
+ */
+ public boolean isParsedForVariables() {
+ return parsedForVarsAndAddresses;
+ }
+
+ /**
+ * @return whether or not this DwarfCompileUnit has been parsed for types
+ */
+ public boolean isParsedForTypes() {
+ return parsedForTypes;
+ }
+
+ /** ensure first parsed for variables before calling
+ * {@link CompileUnitScope#getVariables()}
+ * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getVariables()
+ */
+ @Override
+ public Collection<IVariable> getVariables() {
+ ensureParsedForVariables();
+ return super.getVariables();
+ }
+
+ /**
+ * allow caller to set this DwarfCompileUnit's parsedForVarsAndAddresses flag true
+ * @param parsedForAddresses
+ */
+ public void setParsedForAddresses(boolean parsedForAddresses) {
+ this.parsedForVarsAndAddresses = parsedForAddresses;
+ }
+
+ /**
+ * allow caller to set this DwarfCompileUnit's parsedForVarsAndAddresses flag true
+ * @param parsedForVariables
+ */
+ public void setParsedForVariables(boolean parsedForVariables) {
+ this.parsedForVarsAndAddresses = parsedForVariables;
+ }
+
+ /**
+ * allow caller to set this DwarfCompileUnit's parsedForTypes flag true
+ * @param parsedForTypes
+ */
+ public void setParsedForTypes(boolean parsedForTypes) {
+ this.parsedForTypes = parsedForTypes;
+ }
+
+ private void ensureParsedForAddresses() {
+ if (!parsedForVarsAndAddresses) {
+ DwarfInfoReader reader = new DwarfInfoReader(provider);
+ reader.parseCompilationUnitForAddresses(this);
+ fixupRanges();
+ }
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ /** ensure parsed for addresses before calling super.getScopeAtAddress()
+ * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getScopeAtAddress(org.eclipse.cdt.core.IAddress)
+ */
+ @Override
+ public IScope getScopeAtAddress(IAddress linkAddress) {
+ ensureParsedForAddresses();
+ return super.getScopeAtAddress(linkAddress);
+ }
+
+ /**
+ * DwarfCompileUnit specific version of toString():<br>
+ * <code>
+ * [SymFile=, SectionOffset=, lowAddr=, highAddr=, path=, parsedForVarsAndAddress=, parsedForTypes=]
+ * </code>
+ * @see org.eclipse.cdt.debug.edc.internal.symbols.CompileUnitScope#toString()
+ */
+ @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();
+ }
+
+
+ /**
+ * 1) calls super.addChild() first<br>
+ * 2) checks whether this has an empty range and merges range with passed child scope if not.<br>
+ * 3) adds line info to the passed child scope
+ * @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#addChild(org.eclipse.cdt.debug.edc.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/DwarfDebugInfoProvider.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/internal/symbols/dwarf/DwarfDebugInfoProvider.java
index ffbbbc6..a5bf841 100644
--- 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
@@ -735,6 +735,7 @@ public class DwarfDebugInfoProvider implements IDebugInfoProvider {
functionsByOffset.clear();
typesByOffset.clear();
referenceTypesByOffset.clear();
+ typesByName.clear();
scopesByOffset.clear();
debugOffsetsToCompileUnits.clear();
functionsByName.clear();
@@ -742,6 +743,8 @@ public class DwarfDebugInfoProvider implements IDebugInfoProvider {
publicFunctions.clear();
publicVariables.clear();
abbreviationMaps.clear();
+ frameDescEntries.clear();
+ commonInfoEntries.clear();
referencedFiles.clear();
parsedInitially = false;
parsedForTypes = false;
@@ -988,7 +991,8 @@ public class DwarfDebugInfoProvider implements IDebugInfoProvider {
private void filterOutLocalVariables(List<IVariable> variables) {
List<IVariable> allVariables = new ArrayList<IVariable>(variables);
for (IVariable var : allVariables) {
- if (!(var.getScope() instanceof ICompileUnitScope)) {
+ if (!(var.getScope() instanceof ICompileUnitScope)
+ && !(var.getScope() instanceof IModuleScope)) {
variables.remove(var);
}
}
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
index 674f4c5..3ace41d 100644
--- 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
@@ -98,6 +98,8 @@ import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
+@SuppressWarnings("unused")
+
/**
* Handle restartable parsing of Dwarf information from a single module.
* This class may be instantiated multiple times to parse specific subsets
@@ -247,19 +249,7 @@ public class DwarfInfoReader {
* 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;
- }
- };
+ Job parseInitialJob = new ParseJob(DwarfMessages.DwarfInfoReader_ReadingSymbolInfo + symbolFilePath, provider, this, symbolFilePath);
try {
parseInitialJob.schedule();
@@ -270,6 +260,42 @@ public class DwarfInfoReader {
}
/**
+ * Must be static and a separate class so that its pointer to this
+ * DwarfInfoReader can be broken as Jobs get held onto by the
+ * ProgressViewUpdater and so this prevents GC from occurring on everything.
+ *
+ * @author Daniel Thomas
+ *
+ */
+ private static class ParseJob extends Job{
+
+ private DwarfDebugInfoProvider provider;
+ private DwarfInfoReader reader;
+ private IPath symbolFilePath;
+
+ public ParseJob(String string, DwarfDebugInfoProvider provider, DwarfInfoReader reader, IPath symbolFilePath) {
+ super(string);
+ this.provider = provider;
+ this.reader = reader;
+ this.symbolFilePath = 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) {
+ reader.parseCUDebugInfo(monitor);
+ reader.parsePublicNames();
+ }
+ provider = null;
+ reader = null;
+ symbolFilePath = null;
+ if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceFinishedInitialParse)); }
+ return Status.OK_STATUS;
+ }
+ }
+
+ /**
* Parse all compilation units for addresses
*
* @param includeCUWithoutCode
@@ -1114,9 +1140,7 @@ public class DwarfInfoReader {
int length = data.getInt() + 4;
// Skip the following till "opcode_base"
- @SuppressWarnings("unused")
int version = data.getShort();
- @SuppressWarnings("unused")
int prologue_length = data.getInt();
int minimum_instruction_length = data.get() & 0xff;
boolean default_is_stmt = data.get() > 0;
@@ -1180,9 +1204,7 @@ public class DwarfInfoReader {
int info_line = 1;
int info_column = 0;
boolean is_stmt = default_is_stmt;
- @SuppressWarnings("unused")
int info_flags = 0;
- @SuppressWarnings("unused")
long info_ISA = 0;
long lineInfoEnd = stmtList + length;
@@ -1208,9 +1230,7 @@ public class DwarfInfoReader {
case DwarfConstants.DW_LNE_define_file: {
fileName = readString(data);
long dir = read_unsigned_leb128(data);
- @SuppressWarnings("unused")
long modTime = read_unsigned_leb128(data);
- @SuppressWarnings("unused")
long fileSize = read_unsigned_leb128(data);
IPath fullPath = fileHelper.normalizeFilePath(dirList.get((int) dir), fileName);
if (fullPath != null) {
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
index 94164a7..c63656b 100644
--- 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
@@ -142,7 +142,8 @@ public class ElfExecutableSymbolicsReader extends BaseExecutableSymbolicsReader
protected ISection getSegmentForExecutableSection(Elf.Section section){
for (ISection segment : sections){
if (segment.getLowAddress().compareTo(section.sh_addr) <= 0
- && segment.getHighAddress().compareTo(section.sh_addr.add(section.sh_size)) > 0){
+ && (segment.getHighAddress().compareTo(section.sh_addr.add(section.sh_size)) > 0
+ || segment.getLowAddress().equals(segment.getHighAddress()))) {
return segment;
}
}
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
index b7d2320..bfe0805 100644
--- 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
@@ -1,242 +1,239 @@
-/*******************************************************************************
- * 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();
- }
-}
+/*******************************************************************************
+ * 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;
+
+@SuppressWarnings("rawtypes")
+
+/**
+ * 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;
+
+ private final Map<ServiceKey,ServiceReference> fServiceReferences = Collections.synchronizedMap(new HashMap<ServiceKey,ServiceReference>());
+ 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);
+ }
+ };
+
+ 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
+ */
+ 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")
+ 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();
+ }
+
+ 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/IEDCModuleDMContext.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/services/IEDCModuleDMContext.java
index 9d7785a..20b8d61 100644
--- 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
@@ -1,42 +1,52 @@
-/*******************************************************************************
- * 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();
-
+/*******************************************************************************
+ * Copyright (c) 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, 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();
+
+ /**
+ * Gets the symbol reader used to read symbols for this module. The caller
+ * can force the reader to be created if not done so already.
+ *
+ * @param create try to create the reader if not done so already
+ * @return the symbol reader, or null if none
+ * @since 3.0
+ */
+ public IEDCSymbolReader getSymbolReader(boolean create);
+
} \ No newline at end of file
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
index 3158061..5876d49 100644
--- 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
@@ -1,1237 +1,1241 @@
-/*******************************************************************************
- * 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);
-
- }
-
-}
+/*******************************************************************************
+ * 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) {
+ if (error == null)
+ done(value);
+ else {
+ error(error);
+ }
+ }
+ });
+ }
+ };
+
+ 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
index b1b0f76..d5b361e 100644
--- 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
@@ -1,1653 +1,1739 @@
-/*******************************************************************************
- * 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.EDCSymbolReader;
-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.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.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;
- }
-
- private boolean equals(final IAddress right, final IAddress left) {
- return right == left || right != null && right.equals(left);
- }
-
- private boolean equals(final String right, final String left) {
- return right == left || right != null && right.equals(left);
- }
-
- @Override
- public boolean equals(Object other) {
- return
- this == other
- || (other != null && other instanceof StackFrameData
- && equals(getAddress(), ((StackFrameData)other).getAddress())
- && equals(getFunction(), ((StackFrameData)other).getFunction())
- && getLevel() == ((StackFrameData)other).getLevel()
- && equals(getFile(), ((StackFrameData)other).getFile())
- && getLine() == ((StackFrameData)other).getLine()
- && getColumn() == ((StackFrameData)other).getColumn()
- && equals(getModule(), ((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 = EDCDebugger.getPrefs(EDCDebugger.PLUGIN_ID);
- showAllVariablesEnabled = scope.getBoolean(IEDCSymbols.SHOW_ALL_VARIABLES_ENABLED, false);
- }
-
- boolean enabled = showAllVariablesEnabled.booleanValue();
- if (locals != null) {
- IEclipsePreferences scope = EDCDebugger.getPrefs(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 != null && 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;
- }
-
- /**
- * was initially implemented as "0".
- * currently returns null to guarantee anything calling this
- * knows it's getting a useless bit of data.
- * @see org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMData#getValue()
- */
- public String getValue() {
- // TODO not implemented
- return null;
- }
-
- }
-
- 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.containsKey(context.getID()) && 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());
- }
-
-}
+/*******************************************************************************
+// * Copyright (c) 2009, 2011 Nokia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, 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.EDCSymbolReader;
+import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleDMC;
+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.files.ExecutableSymbolicsReaderFactory;
+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.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;
+
+ /**
+ * When retrieving locals, re-get only those frames that are already cached.
+ */
+ private final static int REFRESH_CACHED_FRAMES = -2;
+
+ /**
+ * this cache is maintained only for those occasions when getFramesForDMC()
+ * is called from {@link #getLocals(IFrameDMContext, DataRequestMonitor)}
+ * and no current cache is available, requiring a refresh.
+ * <p>the cache value for an {@link IEDCExecutionDMC} is established at the
+ * end of {@link #getFramesForDMC(IEDCExecutionDMC, int, int)} with the
+ * value {@link Math#min}(endIndex,frames.size()) .
+ */
+ private final Map<IEDCExecutionDMC, Integer> lastMaxFrameInContextCache
+ = Collections.synchronizedMap(new HashMap<IEDCExecutionDMC, Integer>());
+
+ 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;
+ }
+
+ private boolean equals(final IAddress right, final IAddress left) {
+ return right == left || right != null && right.equals(left);
+ }
+
+ private boolean equals(final String right, final String left) {
+ return right == left || right != null && right.equals(left);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return
+ this == other
+ || (other != null && other instanceof StackFrameData
+ && equals(getAddress(), ((StackFrameData)other).getAddress())
+ && equals(getFunction(), ((StackFrameData)other).getFunction())
+ && getLevel() == ((StackFrameData)other).getLevel()
+ && equals(getFile(), ((StackFrameData)other).getFile())
+ && getLine() == ((StackFrameData)other).getLine()
+ && getColumn() == ((StackFrameData)other).getColumn()
+ && equals(getModule(), ((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> cachedLocals;
+ private List<EnumeratorDMC> cachedEnumerators;
+ 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);
+ }
+ if (!usingCachedProperties || functionName == null || functionName.length() == 0)
+ 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)));
+
+ IPath moduleFilePath = ((ModuleDMC)getModule()).getHostFilePath();
+ if (!moduleFilePath.isEmpty()) {
+ album.addFile(moduleFilePath);
+ IPath possibleSymFile = ExecutableSymbolicsReaderFactory.findSymbolicsFile(moduleFilePath);
+ if (possibleSymFile != null) {
+ album.addFile(possibleSymFile);
+ }
+ }
+
+ 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);
+ }
+
+ synchronized private IVariableDMContext[] getLocals(boolean useCachedVariables) {
+ // may need to refresh the locals list because "Show All Variables"
+ // toggle has changed
+ if (showAllVariablesEnabled == null) {
+ IEclipsePreferences scope = EDCDebugger.getPrefs(EDCDebugger.PLUGIN_ID);
+ showAllVariablesEnabled = scope.getBoolean(IEDCSymbols.SHOW_ALL_VARIABLES_ENABLED, false);
+ }
+
+ boolean enabled = showAllVariablesEnabled.booleanValue();
+ if (cachedLocals != null) {
+ IEclipsePreferences scope = EDCDebugger.getPrefs(EDCDebugger.PLUGIN_ID);
+ enabled = scope.getBoolean(IEDCSymbols.SHOW_ALL_VARIABLES_ENABLED, showAllVariablesEnabled);
+ }
+
+ if (cachedLocals == null || !useCachedVariables || enabled != showAllVariablesEnabled) {
+ showAllVariablesEnabled = enabled;
+ cachedLocals = 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);
+ cachedLocals.remove(haveLocal);
+ }
+ cachedLocals.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);
+ cachedLocals.remove(haveLocal);
+ }
+ cachedLocals.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) + cachedLocals.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 : cachedLocals)
+ 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
+ */
+ synchronized public IVariableEnumeratorContext findVariableOrEnumeratorByName(String name, String qualifiedName, boolean localsOnly) {
+ if (name == null)
+ return null;
+
+ getLocals(); // This will ensure that localsByName is good
+
+ // 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;
+
+ 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 != null && 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;
+ }
+
+ synchronized public EnumeratorDMC[] getEnumerators() {
+ if (cachedEnumerators == null) {
+ cachedEnumerators = 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);
+ cachedEnumerators.add(enumeratorDMC);
+ enumeratorsByName.put(enumerator.getName(), enumeratorDMC);
+ }
+ if (!(scope.getParent() instanceof IFunctionScope))
+ break;
+ scope = (IFunctionScope) scope.getParent();
+ }
+ }
+ }
+ }
+ return cachedEnumerators.toArray(new EnumeratorDMC[cachedEnumerators.size()]);
+ }
+
+ public EnumeratorDMC findEnumeratorbyName(String name) {
+ 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;
+ }
+
+ /**
+ * was initially implemented as "0".
+ * currently returns null to guarantee anything calling this
+ * knows it's getting a useless bit of data.
+ * @see org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMData#getValue()
+ */
+ public String getValue() {
+ // TODO not implemented
+ return null;
+ }
+
+ }
+
+ public class VariableDMC extends DMContext implements IVariableDMContext, IVariableEnumeratorContext {
+
+ public static final String PROP_LOCATION = "Location";
+ private 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;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public void setVariable(IVariable variable) {
+ this.variable = 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, REFRESH_CACHED_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())); }
+ }
+
+ /**
+ * This is loosely based on the concept provided by the pref acquired in
+ * {@link org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.StackFramesVMNode#getStackFrameLimit}
+ * However, that code is not referred to by this method because the
+ * plugin org.eclipse.cdt.debug.edc is designed not to depend upon
+ * any UI code. (and that's why you can't click through to the
+ * javadoc for that link above.)
+ * <p>
+ * Fortunately, the value returned from that function is normally
+ * eventually passed down to getFramesForDMC() early in the process
+ * of performing stack-crawl.
+ * <p>
+ * This private function is designed to take advantage of that,
+ * and it should to be called only when it is desired to
+ * {@link #REFRESH_CACHED_FRAMES} when performing
+ * {@link #getLocals(IFrameDMContext, DataRequestMonitor)}.
+ *
+ * @param context
+ * @param endIndex to help ensure this is called only under proper circumstances
+ * @return a limit based upon a value cached during previous stack crawl for this context
+ */
+ private int getPreviousStackFrameLimit(IEDCExecutionDMC context, int endIndex) {
+ if (endIndex != REFRESH_CACHED_FRAMES) // the guarantee
+ return endIndex;
+
+ Integer previousMax = lastMaxFrameInContextCache.get(context);
+
+ assert previousMax != null : "order of calls to getFramesForDMC should prevent this.";
+
+ if (previousMax != null)
+ return previousMax;
+
+ // as the assert above indicates, control shouldn't get this far.
+ // but provide a couple of fallbacks just in case.
+
+ // first fallback: get any previousMax, since it will likely be something
+ // close to what the user set and/or last retrieved for a similar context.
+ if (!lastMaxFrameInContextCache.isEmpty())
+ return ((Integer[])lastMaxFrameInContextCache.values().toArray())[0];
+
+ // final fallback: something relatively sane to prevent the appearance of
+ // a hung Debug/Stack view that can occur when creating a stack-crawl for
+ // an execution context being accessed for the first time which happens
+ // to be in a state of relative runaway recursion on the target.
+ return 128;
+ }
+
+ 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;
+ 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;
+ endIndex = getPreviousStackFrameLimit(context, endIndex);
+ } else if (allFramesCached.containsKey(context.getID()) && allFramesCached.get(context.getID())) {
+ // all frames are cached
+ needsUpdate = false;
+ } else if (endIndex == ALL_FRAMES) {
+ // some but not all frames cached
+ needsUpdate = true;
+ } else if (endIndex == REFRESH_CACHED_FRAMES) {
+ // update only already cached frames for local variable retrieval
+ needsUpdate = true;
+ endIndex = frames.get(frames.size() - 1).getLevel();
+ } 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) {
+ int frameCount = frames.size();
+ if (startIndex < frameCount && startIndex <= endIndex)
+ frames = frames.subList(startIndex, Math.min(endIndex + 1, frameCount));
+ else
+ frames = Collections.emptyList();
+ if (needsUpdate && endIndex >= 0)
+ lastMaxFrameInContextCache.put(context, Math.min(endIndex + 1, frameCount));
+ }
+ 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/symbols/IVariable.java b/org.eclipse.cdt.debug.edc/src/org/eclipse/cdt/debug/edc/symbols/IVariable.java
index 0741195..9ac5413 100644
--- 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
@@ -1,83 +1,92 @@
-/*******************************************************************************
- * 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();
-}
+/*******************************************************************************
+ * 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();
+
+ /**
+ * Copy the variable with a new (perhaps runtime dependent) type
+ *
+ * @param newType variable type
+ * @return copy of this variable, but with the new type
+ * @since 3.0
+ */
+ IVariable copyWithNewType(IType newType);
+
+ /**
+ *
+ */
+ void dispose();
+}

Back to the top